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.

2875 lines
84 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "in_buttons.h"
  9. #include "engine/IEngineSound.h"
  10. #include "ammodef.h"
  11. #include "SoundEmitterSystem/isoundemittersystembase.h"
  12. #include "physics_saverestore.h"
  13. #include "datacache/imdlcache.h"
  14. #include "activitylist.h"
  15. // NVNT start extra includes
  16. #include "haptics/haptic_utils.h"
  17. #ifdef CLIENT_DLL
  18. #include "prediction.h"
  19. #endif
  20. // NVNT end extra includes
  21. #if defined ( TF_DLL ) || defined ( TF_CLIENT_DLL )
  22. #include "tf_shareddefs.h"
  23. #endif
  24. #if !defined( CLIENT_DLL )
  25. // Game DLL Headers
  26. #include "soundent.h"
  27. #include "eventqueue.h"
  28. #include "fmtstr.h"
  29. #include "gameweaponmanager.h"
  30. #ifdef HL2MP
  31. #include "hl2mp_gamerules.h"
  32. #endif
  33. #endif
  34. #include "vprof.h"
  35. // memdbgon must be the last include file in a .cpp file!!!
  36. #include "tier0/memdbgon.h"
  37. // The minimum time a hud hint for a weapon should be on screen. If we switch away before
  38. // this, then teh hud hint counter will be deremented so the hint will be shown again, as
  39. // if it had never been seen. The total display time for a hud hint is specified in client
  40. // script HudAnimations.txt (which I can't read here).
  41. #define MIN_HUDHINT_DISPLAY_TIME 7.0f
  42. #define HIDEWEAPON_THINK_CONTEXT "BaseCombatWeapon_HideThink"
  43. extern bool UTIL_ItemCanBeTouchedByPlayer( CBaseEntity *pItem, CBasePlayer *pPlayer );
  44. #if defined ( TF_CLIENT_DLL ) || defined ( TF_DLL )
  45. #ifdef _DEBUG
  46. ConVar tf_weapon_criticals_force_random( "tf_weapon_criticals_force_random", "0", FCVAR_REPLICATED | FCVAR_CHEAT );
  47. #endif // _DEBUG
  48. ConVar tf_weapon_criticals_bucket_cap( "tf_weapon_criticals_bucket_cap", "1000.0", FCVAR_REPLICATED | FCVAR_CHEAT );
  49. ConVar tf_weapon_criticals_bucket_bottom( "tf_weapon_criticals_bucket_bottom", "-250.0", FCVAR_REPLICATED | FCVAR_CHEAT );
  50. ConVar tf_weapon_criticals_bucket_default( "tf_weapon_criticals_bucket_default", "300.0", FCVAR_REPLICATED | FCVAR_CHEAT );
  51. #endif // TF
  52. CBaseCombatWeapon::CBaseCombatWeapon()
  53. {
  54. // Constructor must call this
  55. // CONSTRUCT_PREDICTABLE( CBaseCombatWeapon );
  56. // Some default values. There should be set in the particular weapon classes
  57. m_fMinRange1 = 65;
  58. m_fMinRange2 = 65;
  59. m_fMaxRange1 = 1024;
  60. m_fMaxRange2 = 1024;
  61. m_bReloadsSingly = false;
  62. // Defaults to zero
  63. m_nViewModelIndex = 0;
  64. m_bFlipViewModel = false;
  65. #if defined( CLIENT_DLL )
  66. m_iState = m_iOldState = WEAPON_NOT_CARRIED;
  67. m_iClip1 = -1;
  68. m_iClip2 = -1;
  69. m_iPrimaryAmmoType = -1;
  70. m_iSecondaryAmmoType = -1;
  71. #endif
  72. #if !defined( CLIENT_DLL )
  73. m_pConstraint = NULL;
  74. m_bSoundsEnabled = true;
  75. OnBaseCombatWeaponCreated( this );
  76. #endif
  77. m_hWeaponFileInfo = GetInvalidWeaponInfoHandle();
  78. #if defined( TF_DLL )
  79. UseClientSideAnimation();
  80. #endif
  81. #if defined ( TF_CLIENT_DLL ) || defined ( TF_DLL )
  82. m_flCritTokenBucket = tf_weapon_criticals_bucket_default.GetFloat();
  83. m_nCritChecks = 1;
  84. m_nCritSeedRequests = 0;
  85. #endif // TF
  86. }
  87. //-----------------------------------------------------------------------------
  88. // Purpose: Destructor
  89. //-----------------------------------------------------------------------------
  90. CBaseCombatWeapon::~CBaseCombatWeapon( void )
  91. {
  92. #if !defined( CLIENT_DLL )
  93. //Remove our constraint, if we have one
  94. if ( m_pConstraint != NULL )
  95. {
  96. physenv->DestroyConstraint( m_pConstraint );
  97. m_pConstraint = NULL;
  98. }
  99. OnBaseCombatWeaponDestroyed( this );
  100. #endif
  101. }
  102. void CBaseCombatWeapon::Activate( void )
  103. {
  104. BaseClass::Activate();
  105. #ifndef CLIENT_DLL
  106. if ( GetOwnerEntity() )
  107. return;
  108. if ( g_pGameRules->IsAllowedToSpawn( this ) == false )
  109. {
  110. UTIL_Remove( this );
  111. return;
  112. }
  113. #endif
  114. }
  115. void CBaseCombatWeapon::GiveDefaultAmmo( void )
  116. {
  117. // If I use clips, set my clips to the default
  118. if ( UsesClipsForAmmo1() )
  119. {
  120. m_iClip1 = AutoFiresFullClip() ? 0 : GetDefaultClip1();
  121. }
  122. else
  123. {
  124. SetPrimaryAmmoCount( GetDefaultClip1() );
  125. m_iClip1 = WEAPON_NOCLIP;
  126. }
  127. if ( UsesClipsForAmmo2() )
  128. {
  129. m_iClip2 = GetDefaultClip2();
  130. }
  131. else
  132. {
  133. SetSecondaryAmmoCount( GetDefaultClip2() );
  134. m_iClip2 = WEAPON_NOCLIP;
  135. }
  136. }
  137. //-----------------------------------------------------------------------------
  138. // Purpose: Set mode to world model and start falling to the ground
  139. //-----------------------------------------------------------------------------
  140. void CBaseCombatWeapon::Spawn( void )
  141. {
  142. bool bPrecacheAllowed = CBaseEntity::IsPrecacheAllowed();
  143. if (!bPrecacheAllowed)
  144. {
  145. tmEnter( TELEMETRY_LEVEL1, TMZF_NONE, "LateWeaponPrecache" );
  146. }
  147. Precache();
  148. if (!bPrecacheAllowed)
  149. {
  150. tmLeave( TELEMETRY_LEVEL1 );
  151. }
  152. BaseClass::Spawn();
  153. SetSolid( SOLID_BBOX );
  154. m_flNextEmptySoundTime = 0.0f;
  155. // Weapons won't show up in trace calls if they are being carried...
  156. RemoveEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
  157. m_iState = WEAPON_NOT_CARRIED;
  158. // Assume
  159. m_nViewModelIndex = 0;
  160. GiveDefaultAmmo();
  161. if ( GetWorldModel() )
  162. {
  163. SetModel( GetWorldModel() );
  164. }
  165. #if !defined( CLIENT_DLL )
  166. if( IsX360() )
  167. {
  168. AddEffects( EF_ITEM_BLINK );
  169. }
  170. FallInit();
  171. SetCollisionGroup( COLLISION_GROUP_WEAPON );
  172. m_takedamage = DAMAGE_EVENTS_ONLY;
  173. SetBlocksLOS( false );
  174. // Default to non-removeable, because we don't want the
  175. // game_weapon_manager entity to remove weapons that have
  176. // been hand-placed by level designers. We only want to remove
  177. // weapons that have been dropped by NPC's.
  178. SetRemoveable( false );
  179. #endif
  180. // Bloat the box for player pickup
  181. CollisionProp()->UseTriggerBounds( true, 36 );
  182. // Use more efficient bbox culling on the client. Otherwise, it'll setup bones for most
  183. // characters even when they're not in the frustum.
  184. AddEffects( EF_BONEMERGE_FASTCULL );
  185. m_iReloadHudHintCount = 0;
  186. m_iAltFireHudHintCount = 0;
  187. m_flHudHintMinDisplayTime = 0;
  188. }
  189. //-----------------------------------------------------------------------------
  190. // Purpose: get this game's encryption key for decoding weapon kv files
  191. // Output : virtual const unsigned char
  192. //-----------------------------------------------------------------------------
  193. const unsigned char *CBaseCombatWeapon::GetEncryptionKey( void )
  194. {
  195. return g_pGameRules->GetEncryptionKey();
  196. }
  197. //-----------------------------------------------------------------------------
  198. // Purpose:
  199. //-----------------------------------------------------------------------------
  200. void CBaseCombatWeapon::Precache( void )
  201. {
  202. #if defined( CLIENT_DLL )
  203. Assert( Q_strlen( GetClassname() ) > 0 );
  204. // Msg( "Client got %s\n", GetClassname() );
  205. #endif
  206. m_iPrimaryAmmoType = m_iSecondaryAmmoType = -1;
  207. // Add this weapon to the weapon registry, and get our index into it
  208. // Get weapon data from script file
  209. if ( ReadWeaponDataFromFileForSlot( filesystem, GetClassname(), &m_hWeaponFileInfo, GetEncryptionKey() ) )
  210. {
  211. // Get the ammo indexes for the ammo's specified in the data file
  212. if ( GetWpnData().szAmmo1[0] )
  213. {
  214. m_iPrimaryAmmoType = GetAmmoDef()->Index( GetWpnData().szAmmo1 );
  215. if (m_iPrimaryAmmoType == -1)
  216. {
  217. Msg("ERROR: Weapon (%s) using undefined primary ammo type (%s)\n",GetClassname(), GetWpnData().szAmmo1);
  218. }
  219. #if defined ( TF_DLL ) || defined ( TF_CLIENT_DLL )
  220. // Ammo override
  221. int iModUseMetalOverride = 0;
  222. CALL_ATTRIB_HOOK_INT( iModUseMetalOverride, mod_use_metal_ammo_type );
  223. if ( iModUseMetalOverride )
  224. {
  225. m_iPrimaryAmmoType = (int)TF_AMMO_METAL;
  226. }
  227. #endif
  228. }
  229. if ( GetWpnData().szAmmo2[0] )
  230. {
  231. m_iSecondaryAmmoType = GetAmmoDef()->Index( GetWpnData().szAmmo2 );
  232. if (m_iSecondaryAmmoType == -1)
  233. {
  234. Msg("ERROR: Weapon (%s) using undefined secondary ammo type (%s)\n",GetClassname(),GetWpnData().szAmmo2);
  235. }
  236. }
  237. #if defined( CLIENT_DLL )
  238. gWR.LoadWeaponSprites( GetWeaponFileInfoHandle() );
  239. #endif
  240. // Precache models (preload to avoid hitch)
  241. m_iViewModelIndex = 0;
  242. m_iWorldModelIndex = 0;
  243. if ( GetViewModel() && GetViewModel()[0] )
  244. {
  245. m_iViewModelIndex = CBaseEntity::PrecacheModel( GetViewModel() );
  246. }
  247. if ( GetWorldModel() && GetWorldModel()[0] )
  248. {
  249. m_iWorldModelIndex = CBaseEntity::PrecacheModel( GetWorldModel() );
  250. }
  251. // Precache sounds, too
  252. for ( int i = 0; i < NUM_SHOOT_SOUND_TYPES; ++i )
  253. {
  254. const char *shootsound = GetShootSound( i );
  255. if ( shootsound && shootsound[0] )
  256. {
  257. CBaseEntity::PrecacheScriptSound( shootsound );
  258. }
  259. }
  260. }
  261. else
  262. {
  263. // Couldn't read data file, remove myself
  264. Warning( "Error reading weapon data file for: %s\n", GetClassname() );
  265. // Remove( ); //don't remove, this gets released soon!
  266. }
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Purpose: Get my data in the file weapon info array
  270. //-----------------------------------------------------------------------------
  271. const FileWeaponInfo_t &CBaseCombatWeapon::GetWpnData( void ) const
  272. {
  273. return *GetFileWeaponInfoFromHandle( m_hWeaponFileInfo );
  274. }
  275. //-----------------------------------------------------------------------------
  276. // Purpose:
  277. //-----------------------------------------------------------------------------
  278. const char *CBaseCombatWeapon::GetViewModel( int /*viewmodelindex = 0 -- this is ignored in the base class here*/ ) const
  279. {
  280. return GetWpnData().szViewModel;
  281. }
  282. //-----------------------------------------------------------------------------
  283. // Purpose:
  284. //-----------------------------------------------------------------------------
  285. const char *CBaseCombatWeapon::GetWorldModel( void ) const
  286. {
  287. return GetWpnData().szWorldModel;
  288. }
  289. //-----------------------------------------------------------------------------
  290. // Purpose:
  291. //-----------------------------------------------------------------------------
  292. const char *CBaseCombatWeapon::GetAnimPrefix( void ) const
  293. {
  294. return GetWpnData().szAnimationPrefix;
  295. }
  296. //-----------------------------------------------------------------------------
  297. // Purpose:
  298. // Output : char const
  299. //-----------------------------------------------------------------------------
  300. const char *CBaseCombatWeapon::GetPrintName( void ) const
  301. {
  302. return GetWpnData().szPrintName;
  303. }
  304. //-----------------------------------------------------------------------------
  305. // Purpose:
  306. //-----------------------------------------------------------------------------
  307. int CBaseCombatWeapon::GetMaxClip1( void ) const
  308. {
  309. #if defined ( TF_DLL ) || defined ( TF_CLIENT_DLL )
  310. int iModMaxClipOverride = 0;
  311. CALL_ATTRIB_HOOK_INT( iModMaxClipOverride, mod_max_primary_clip_override );
  312. if ( iModMaxClipOverride != 0 )
  313. return iModMaxClipOverride;
  314. #endif
  315. return GetWpnData().iMaxClip1;
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Purpose:
  319. //-----------------------------------------------------------------------------
  320. int CBaseCombatWeapon::GetMaxClip2( void ) const
  321. {
  322. return GetWpnData().iMaxClip2;
  323. }
  324. //-----------------------------------------------------------------------------
  325. // Purpose:
  326. //-----------------------------------------------------------------------------
  327. int CBaseCombatWeapon::GetDefaultClip1( void ) const
  328. {
  329. return GetWpnData().iDefaultClip1;
  330. }
  331. //-----------------------------------------------------------------------------
  332. // Purpose:
  333. //-----------------------------------------------------------------------------
  334. int CBaseCombatWeapon::GetDefaultClip2( void ) const
  335. {
  336. return GetWpnData().iDefaultClip2;
  337. }
  338. //-----------------------------------------------------------------------------
  339. // Purpose:
  340. //-----------------------------------------------------------------------------
  341. bool CBaseCombatWeapon::UsesClipsForAmmo1( void ) const
  342. {
  343. return ( GetMaxClip1() != WEAPON_NOCLIP );
  344. }
  345. bool CBaseCombatWeapon::IsMeleeWeapon() const
  346. {
  347. return GetWpnData().m_bMeleeWeapon;
  348. }
  349. //-----------------------------------------------------------------------------
  350. // Purpose:
  351. //-----------------------------------------------------------------------------
  352. bool CBaseCombatWeapon::UsesClipsForAmmo2( void ) const
  353. {
  354. return ( GetMaxClip2() != WEAPON_NOCLIP );
  355. }
  356. //-----------------------------------------------------------------------------
  357. // Purpose:
  358. //-----------------------------------------------------------------------------
  359. int CBaseCombatWeapon::GetWeight( void ) const
  360. {
  361. return GetWpnData().iWeight;
  362. }
  363. //-----------------------------------------------------------------------------
  364. // Purpose: Whether this weapon can be autoswitched to when the player runs out
  365. // of ammo in their current weapon or they pick this weapon up.
  366. //-----------------------------------------------------------------------------
  367. bool CBaseCombatWeapon::AllowsAutoSwitchTo( void ) const
  368. {
  369. return GetWpnData().bAutoSwitchTo;
  370. }
  371. //-----------------------------------------------------------------------------
  372. // Purpose: Whether this weapon can be autoswitched away from when the player
  373. // runs out of ammo in this weapon or picks up another weapon or ammo.
  374. //-----------------------------------------------------------------------------
  375. bool CBaseCombatWeapon::AllowsAutoSwitchFrom( void ) const
  376. {
  377. return GetWpnData().bAutoSwitchFrom;
  378. }
  379. //-----------------------------------------------------------------------------
  380. // Purpose:
  381. //-----------------------------------------------------------------------------
  382. int CBaseCombatWeapon::GetWeaponFlags( void ) const
  383. {
  384. return GetWpnData().iFlags;
  385. }
  386. //-----------------------------------------------------------------------------
  387. // Purpose:
  388. //-----------------------------------------------------------------------------
  389. int CBaseCombatWeapon::GetSlot( void ) const
  390. {
  391. return GetWpnData().iSlot;
  392. }
  393. //-----------------------------------------------------------------------------
  394. // Purpose:
  395. //-----------------------------------------------------------------------------
  396. int CBaseCombatWeapon::GetPosition( void ) const
  397. {
  398. return GetWpnData().iPosition;
  399. }
  400. //-----------------------------------------------------------------------------
  401. // Purpose:
  402. //-----------------------------------------------------------------------------
  403. const char *CBaseCombatWeapon::GetName( void ) const
  404. {
  405. return GetWpnData().szClassName;
  406. }
  407. //-----------------------------------------------------------------------------
  408. // Purpose:
  409. //-----------------------------------------------------------------------------
  410. CHudTexture const *CBaseCombatWeapon::GetSpriteActive( void ) const
  411. {
  412. return GetWpnData().iconActive;
  413. }
  414. //-----------------------------------------------------------------------------
  415. // Purpose:
  416. //-----------------------------------------------------------------------------
  417. CHudTexture const *CBaseCombatWeapon::GetSpriteInactive( void ) const
  418. {
  419. return GetWpnData().iconInactive;
  420. }
  421. //-----------------------------------------------------------------------------
  422. // Purpose:
  423. //-----------------------------------------------------------------------------
  424. CHudTexture const *CBaseCombatWeapon::GetSpriteAmmo( void ) const
  425. {
  426. return GetWpnData().iconAmmo;
  427. }
  428. //-----------------------------------------------------------------------------
  429. // Purpose:
  430. //-----------------------------------------------------------------------------
  431. CHudTexture const *CBaseCombatWeapon::GetSpriteAmmo2( void ) const
  432. {
  433. return GetWpnData().iconAmmo2;
  434. }
  435. //-----------------------------------------------------------------------------
  436. // Purpose:
  437. //-----------------------------------------------------------------------------
  438. CHudTexture const *CBaseCombatWeapon::GetSpriteCrosshair( void ) const
  439. {
  440. return GetWpnData().iconCrosshair;
  441. }
  442. //-----------------------------------------------------------------------------
  443. // Purpose:
  444. //-----------------------------------------------------------------------------
  445. CHudTexture const *CBaseCombatWeapon::GetSpriteAutoaim( void ) const
  446. {
  447. return GetWpnData().iconAutoaim;
  448. }
  449. //-----------------------------------------------------------------------------
  450. // Purpose:
  451. //-----------------------------------------------------------------------------
  452. CHudTexture const *CBaseCombatWeapon::GetSpriteZoomedCrosshair( void ) const
  453. {
  454. return GetWpnData().iconZoomedCrosshair;
  455. }
  456. //-----------------------------------------------------------------------------
  457. // Purpose:
  458. //-----------------------------------------------------------------------------
  459. CHudTexture const *CBaseCombatWeapon::GetSpriteZoomedAutoaim( void ) const
  460. {
  461. return GetWpnData().iconZoomedAutoaim;
  462. }
  463. //-----------------------------------------------------------------------------
  464. // Purpose:
  465. //-----------------------------------------------------------------------------
  466. const char *CBaseCombatWeapon::GetShootSound( int iIndex ) const
  467. {
  468. return GetWpnData().aShootSounds[ iIndex ];
  469. }
  470. //-----------------------------------------------------------------------------
  471. // Purpose:
  472. //-----------------------------------------------------------------------------
  473. int CBaseCombatWeapon::GetRumbleEffect() const
  474. {
  475. return GetWpnData().iRumbleEffect;
  476. }
  477. //-----------------------------------------------------------------------------
  478. // Purpose:
  479. //-----------------------------------------------------------------------------
  480. CBaseCombatCharacter *CBaseCombatWeapon::GetOwner() const
  481. {
  482. return ToBaseCombatCharacter( m_hOwner.Get() );
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Purpose:
  486. // Input : BaseCombatCharacter -
  487. //-----------------------------------------------------------------------------
  488. void CBaseCombatWeapon::SetOwner( CBaseCombatCharacter *owner )
  489. {
  490. if ( !owner )
  491. {
  492. #ifndef CLIENT_DLL
  493. // Make sure the weapon updates its state when it's removed from the player
  494. // We have to force an active state change, because it's being dropped and won't call UpdateClientData()
  495. int iOldState = m_iState;
  496. m_iState = WEAPON_NOT_CARRIED;
  497. OnActiveStateChanged( iOldState );
  498. #endif
  499. // make sure we clear out our HideThink if we have one pending
  500. SetContextThink( NULL, 0, HIDEWEAPON_THINK_CONTEXT );
  501. }
  502. m_hOwner = owner;
  503. #ifndef CLIENT_DLL
  504. DispatchUpdateTransmitState();
  505. #else
  506. UpdateVisibility();
  507. #endif
  508. }
  509. //-----------------------------------------------------------------------------
  510. // Purpose: Return false if this weapon won't let the player switch away from it
  511. //-----------------------------------------------------------------------------
  512. bool CBaseCombatWeapon::IsAllowedToSwitch( void )
  513. {
  514. return true;
  515. }
  516. //-----------------------------------------------------------------------------
  517. // Purpose: Return true if this weapon can be selected via the weapon selection
  518. //-----------------------------------------------------------------------------
  519. bool CBaseCombatWeapon::CanBeSelected( void )
  520. {
  521. if ( !VisibleInWeaponSelection() )
  522. return false;
  523. return HasAmmo();
  524. }
  525. //-----------------------------------------------------------------------------
  526. // Purpose: Return true if this weapon has some ammo
  527. //-----------------------------------------------------------------------------
  528. bool CBaseCombatWeapon::HasAmmo( void )
  529. {
  530. // Weapons with no ammo types can always be selected
  531. if ( m_iPrimaryAmmoType == -1 && m_iSecondaryAmmoType == -1 )
  532. return true;
  533. if ( GetWeaponFlags() & ITEM_FLAG_SELECTONEMPTY )
  534. return true;
  535. CBasePlayer *player = ToBasePlayer( GetOwner() );
  536. if ( !player )
  537. return false;
  538. return ( m_iClip1 > 0 || player->GetAmmoCount( m_iPrimaryAmmoType ) || m_iClip2 > 0 || player->GetAmmoCount( m_iSecondaryAmmoType ) );
  539. }
  540. //-----------------------------------------------------------------------------
  541. // Purpose: Return true if this weapon should be seen, and hence be selectable, in the weapon selection
  542. //-----------------------------------------------------------------------------
  543. bool CBaseCombatWeapon::VisibleInWeaponSelection( void )
  544. {
  545. return true;
  546. }
  547. //-----------------------------------------------------------------------------
  548. // Purpose:
  549. // Output : Returns true on success, false on failure.
  550. //-----------------------------------------------------------------------------
  551. bool CBaseCombatWeapon::HasWeaponIdleTimeElapsed( void )
  552. {
  553. if ( gpGlobals->curtime > m_flTimeWeaponIdle )
  554. return true;
  555. return false;
  556. }
  557. //-----------------------------------------------------------------------------
  558. // Purpose:
  559. // Input : time -
  560. //-----------------------------------------------------------------------------
  561. void CBaseCombatWeapon::SetWeaponIdleTime( float time )
  562. {
  563. m_flTimeWeaponIdle = time;
  564. }
  565. //-----------------------------------------------------------------------------
  566. // Purpose:
  567. // Output : float
  568. //-----------------------------------------------------------------------------
  569. float CBaseCombatWeapon::GetWeaponIdleTime( void )
  570. {
  571. return m_flTimeWeaponIdle;
  572. }
  573. //-----------------------------------------------------------------------------
  574. // Purpose: Drop/throw the weapon with the given velocity.
  575. //-----------------------------------------------------------------------------
  576. void CBaseCombatWeapon::Drop( const Vector &vecVelocity )
  577. {
  578. #if !defined( CLIENT_DLL )
  579. // Once somebody drops a gun, it's fair game for removal when/if
  580. // a game_weapon_manager does a cleanup on surplus weapons in the
  581. // world.
  582. SetRemoveable( true );
  583. WeaponManager_AmmoMod( this );
  584. //If it was dropped then there's no need to respawn it.
  585. AddSpawnFlags( SF_NORESPAWN );
  586. StopAnimation();
  587. StopFollowingEntity( );
  588. SetMoveType( MOVETYPE_FLYGRAVITY );
  589. // clear follow stuff, setup for collision
  590. SetGravity(1.0);
  591. m_iState = WEAPON_NOT_CARRIED;
  592. RemoveEffects( EF_NODRAW );
  593. FallInit();
  594. SetGroundEntity( NULL );
  595. SetThink( &CBaseCombatWeapon::SetPickupTouch );
  596. SetTouch(NULL);
  597. if( hl2_episodic.GetBool() )
  598. {
  599. RemoveSpawnFlags( SF_WEAPON_NO_PLAYER_PICKUP );
  600. }
  601. IPhysicsObject *pObj = VPhysicsGetObject();
  602. if ( pObj != NULL )
  603. {
  604. AngularImpulse angImp( 200, 200, 200 );
  605. pObj->AddVelocity( &vecVelocity, &angImp );
  606. }
  607. else
  608. {
  609. SetAbsVelocity( vecVelocity );
  610. }
  611. CBaseEntity *pOwner = GetOwnerEntity();
  612. SetNextThink( gpGlobals->curtime + 1.0f );
  613. SetOwnerEntity( NULL );
  614. SetOwner( NULL );
  615. // If we're not allowing to spawn due to the gamerules,
  616. // remove myself when I'm dropped by an NPC.
  617. if ( pOwner && pOwner->IsNPC() )
  618. {
  619. if ( g_pGameRules->IsAllowedToSpawn( this ) == false )
  620. {
  621. UTIL_Remove( this );
  622. return;
  623. }
  624. }
  625. #endif
  626. }
  627. //-----------------------------------------------------------------------------
  628. // Purpose:
  629. // Input : *pPicker -
  630. //-----------------------------------------------------------------------------
  631. void CBaseCombatWeapon::OnPickedUp( CBaseCombatCharacter *pNewOwner )
  632. {
  633. #if !defined( CLIENT_DLL )
  634. RemoveEffects( EF_ITEM_BLINK );
  635. if( pNewOwner->IsPlayer() )
  636. {
  637. m_OnPlayerPickup.FireOutput(pNewOwner, this);
  638. // Play the pickup sound for 1st-person observers
  639. CRecipientFilter filter;
  640. for ( int i=1; i <= gpGlobals->maxClients; ++i )
  641. {
  642. CBasePlayer *player = UTIL_PlayerByIndex(i);
  643. if ( player && !player->IsAlive() && player->GetObserverMode() == OBS_MODE_IN_EYE )
  644. {
  645. filter.AddRecipient( player );
  646. }
  647. }
  648. if ( filter.GetRecipientCount() )
  649. {
  650. CBaseEntity::EmitSound( filter, pNewOwner->entindex(), "Player.PickupWeapon" );
  651. }
  652. // Robin: We don't want to delete weapons the player has picked up, so
  653. // clear the name of the weapon. This prevents wildcards that are meant
  654. // to find NPCs finding weapons dropped by the NPCs as well.
  655. SetName( NULL_STRING );
  656. }
  657. else
  658. {
  659. m_OnNPCPickup.FireOutput(pNewOwner, this);
  660. }
  661. #ifdef HL2MP
  662. HL2MPRules()->RemoveLevelDesignerPlacedObject( this );
  663. #endif
  664. // Someone picked me up, so make it so that I can't be removed.
  665. SetRemoveable( false );
  666. #endif
  667. }
  668. //-----------------------------------------------------------------------------
  669. // Purpose:
  670. // Input : &vecTracerSrc -
  671. // &tr -
  672. // iTracerType -
  673. //-----------------------------------------------------------------------------
  674. void CBaseCombatWeapon::MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType )
  675. {
  676. CBaseEntity *pOwner = GetOwner();
  677. if ( pOwner == NULL )
  678. {
  679. BaseClass::MakeTracer( vecTracerSrc, tr, iTracerType );
  680. return;
  681. }
  682. const char *pszTracerName = GetTracerType();
  683. Vector vNewSrc = vecTracerSrc;
  684. int iEntIndex = pOwner->entindex();
  685. if ( g_pGameRules->IsMultiplayer() )
  686. {
  687. iEntIndex = entindex();
  688. }
  689. int iAttachment = GetTracerAttachment();
  690. switch ( iTracerType )
  691. {
  692. case TRACER_LINE:
  693. UTIL_Tracer( vNewSrc, tr.endpos, iEntIndex, iAttachment, 0.0f, true, pszTracerName );
  694. break;
  695. case TRACER_LINE_AND_WHIZ:
  696. UTIL_Tracer( vNewSrc, tr.endpos, iEntIndex, iAttachment, 0.0f, true, pszTracerName );
  697. break;
  698. }
  699. }
  700. void CBaseCombatWeapon::GiveTo( CBaseEntity *pOther )
  701. {
  702. DefaultTouch( pOther );
  703. }
  704. //-----------------------------------------------------------------------------
  705. // Purpose: Default Touch function for player picking up a weapon (not AI)
  706. // Input : pOther - the entity that touched me
  707. // Output :
  708. //-----------------------------------------------------------------------------
  709. void CBaseCombatWeapon::DefaultTouch( CBaseEntity *pOther )
  710. {
  711. #if !defined( CLIENT_DLL )
  712. // Can't pick up dissolving weapons
  713. if ( IsDissolving() )
  714. return;
  715. // if it's not a player, ignore
  716. CBasePlayer *pPlayer = ToBasePlayer(pOther);
  717. if ( !pPlayer )
  718. return;
  719. if( UTIL_ItemCanBeTouchedByPlayer(this, pPlayer) )
  720. {
  721. // This makes sure the player could potentially take the object
  722. // before firing the cache interaction output. That doesn't mean
  723. // the player WILL end up taking the object, but cache interactions
  724. // are fired as soon as you prove you have found the object, not
  725. // when you finally acquire it.
  726. m_OnCacheInteraction.FireOutput( pOther, this );
  727. }
  728. if( HasSpawnFlags(SF_WEAPON_NO_PLAYER_PICKUP) )
  729. return;
  730. if (pPlayer->BumpWeapon(this))
  731. {
  732. OnPickedUp( pPlayer );
  733. }
  734. #endif
  735. }
  736. //---------------------------------------------------------
  737. // It's OK for base classes to override this completely
  738. // without calling up. (sjb)
  739. //---------------------------------------------------------
  740. bool CBaseCombatWeapon::ShouldDisplayAltFireHUDHint()
  741. {
  742. if( m_iAltFireHudHintCount >= WEAPON_RELOAD_HUD_HINT_COUNT )
  743. return false;
  744. if( UsesSecondaryAmmo() && HasSecondaryAmmo() )
  745. {
  746. return true;
  747. }
  748. if( !UsesSecondaryAmmo() && HasPrimaryAmmo() )
  749. {
  750. return true;
  751. }
  752. return false;
  753. }
  754. //-----------------------------------------------------------------------------
  755. //-----------------------------------------------------------------------------
  756. void CBaseCombatWeapon::DisplayAltFireHudHint()
  757. {
  758. #if !defined( CLIENT_DLL )
  759. CFmtStr hint;
  760. hint.sprintf( "#valve_hint_alt_%s", GetClassname() );
  761. UTIL_HudHintText( GetOwner(), hint.Access() );
  762. m_iAltFireHudHintCount++;
  763. m_bAltFireHudHintDisplayed = true;
  764. m_flHudHintMinDisplayTime = gpGlobals->curtime + MIN_HUDHINT_DISPLAY_TIME;
  765. #endif//CLIENT_DLL
  766. }
  767. //-----------------------------------------------------------------------------
  768. //-----------------------------------------------------------------------------
  769. void CBaseCombatWeapon::RescindAltFireHudHint()
  770. {
  771. #if !defined( CLIENT_DLL )
  772. Assert(m_bAltFireHudHintDisplayed);
  773. UTIL_HudHintText( GetOwner(), "" );
  774. --m_iAltFireHudHintCount;
  775. m_bAltFireHudHintDisplayed = false;
  776. #endif//CLIENT_DLL
  777. }
  778. //-----------------------------------------------------------------------------
  779. //-----------------------------------------------------------------------------
  780. bool CBaseCombatWeapon::ShouldDisplayReloadHUDHint()
  781. {
  782. if( m_iReloadHudHintCount >= WEAPON_RELOAD_HUD_HINT_COUNT )
  783. return false;
  784. CBaseCombatCharacter *pOwner = GetOwner();
  785. if( pOwner != NULL && pOwner->IsPlayer() && UsesClipsForAmmo1() && m_iClip1 < (GetMaxClip1() / 2) )
  786. {
  787. // I'm owned by a player, I use clips, I have less then half a clip loaded. Now, does the player have more ammo?
  788. if ( pOwner )
  789. {
  790. if ( pOwner->GetAmmoCount( m_iPrimaryAmmoType ) > 0 )
  791. return true;
  792. }
  793. }
  794. return false;
  795. }
  796. //-----------------------------------------------------------------------------
  797. //-----------------------------------------------------------------------------
  798. void CBaseCombatWeapon::DisplayReloadHudHint()
  799. {
  800. #if !defined( CLIENT_DLL )
  801. UTIL_HudHintText( GetOwner(), "valve_hint_reload" );
  802. m_iReloadHudHintCount++;
  803. m_bReloadHudHintDisplayed = true;
  804. m_flHudHintMinDisplayTime = gpGlobals->curtime + MIN_HUDHINT_DISPLAY_TIME;
  805. #endif//CLIENT_DLL
  806. }
  807. //-----------------------------------------------------------------------------
  808. //-----------------------------------------------------------------------------
  809. void CBaseCombatWeapon::RescindReloadHudHint()
  810. {
  811. #if !defined( CLIENT_DLL )
  812. Assert(m_bReloadHudHintDisplayed);
  813. UTIL_HudHintText( GetOwner(), "" );
  814. --m_iReloadHudHintCount;
  815. m_bReloadHudHintDisplayed = false;
  816. #endif//CLIENT_DLL
  817. }
  818. void CBaseCombatWeapon::SetPickupTouch( void )
  819. {
  820. #if !defined( CLIENT_DLL )
  821. SetTouch(&CBaseCombatWeapon::DefaultTouch);
  822. if ( gpGlobals->maxClients > 1 )
  823. {
  824. if ( GetSpawnFlags() & SF_NORESPAWN )
  825. {
  826. SetThink( &CBaseEntity::SUB_Remove );
  827. SetNextThink( gpGlobals->curtime + 30.0f );
  828. }
  829. }
  830. #endif
  831. }
  832. //-----------------------------------------------------------------------------
  833. // Purpose: Become a child of the owner (MOVETYPE_FOLLOW)
  834. // disables collisions, touch functions, thinking
  835. // Input : *pOwner - new owner/operator
  836. //-----------------------------------------------------------------------------
  837. void CBaseCombatWeapon::Equip( CBaseCombatCharacter *pOwner )
  838. {
  839. // Attach the weapon to an owner
  840. SetAbsVelocity( vec3_origin );
  841. RemoveSolidFlags( FSOLID_TRIGGER );
  842. FollowEntity( pOwner );
  843. SetOwner( pOwner );
  844. SetOwnerEntity( pOwner );
  845. // Break any constraint I might have to the world.
  846. RemoveEffects( EF_ITEM_BLINK );
  847. #if !defined( CLIENT_DLL )
  848. if ( m_pConstraint != NULL )
  849. {
  850. RemoveSpawnFlags( SF_WEAPON_START_CONSTRAINED );
  851. physenv->DestroyConstraint( m_pConstraint );
  852. m_pConstraint = NULL;
  853. }
  854. #endif
  855. m_flNextPrimaryAttack = gpGlobals->curtime;
  856. m_flNextSecondaryAttack = gpGlobals->curtime;
  857. SetTouch( NULL );
  858. SetThink( NULL );
  859. #if !defined( CLIENT_DLL )
  860. VPhysicsDestroyObject();
  861. #endif
  862. if ( pOwner->IsPlayer() )
  863. {
  864. SetModel( GetViewModel() );
  865. }
  866. else
  867. {
  868. // Make the weapon ready as soon as any NPC picks it up.
  869. m_flNextPrimaryAttack = gpGlobals->curtime;
  870. m_flNextSecondaryAttack = gpGlobals->curtime;
  871. SetModel( GetWorldModel() );
  872. }
  873. }
  874. void CBaseCombatWeapon::SetActivity( Activity act, float duration )
  875. {
  876. //Adrian: Oh man...
  877. #if !defined( CLIENT_DLL ) && (defined( HL2MP ) || defined( PORTAL ))
  878. SetModel( GetWorldModel() );
  879. #endif
  880. int sequence = SelectWeightedSequence( act );
  881. // FORCE IDLE on sequences we don't have (which should be many)
  882. if ( sequence == ACTIVITY_NOT_AVAILABLE )
  883. sequence = SelectWeightedSequence( ACT_VM_IDLE );
  884. //Adrian: Oh man again...
  885. #if !defined( CLIENT_DLL ) && (defined( HL2MP ) || defined( PORTAL ))
  886. SetModel( GetViewModel() );
  887. #endif
  888. if ( sequence != ACTIVITY_NOT_AVAILABLE )
  889. {
  890. SetSequence( sequence );
  891. SetActivity( act );
  892. SetCycle( 0 );
  893. ResetSequenceInfo( );
  894. if ( duration > 0 )
  895. {
  896. // FIXME: does this even make sense in non-shoot animations?
  897. m_flPlaybackRate = SequenceDuration( sequence ) / duration;
  898. m_flPlaybackRate = MIN( m_flPlaybackRate, 12.0); // FIXME; magic number!, network encoding range
  899. }
  900. else
  901. {
  902. m_flPlaybackRate = 1.0;
  903. }
  904. }
  905. }
  906. //====================================================================================
  907. // WEAPON CLIENT HANDLING
  908. //====================================================================================
  909. int CBaseCombatWeapon::UpdateClientData( CBasePlayer *pPlayer )
  910. {
  911. int iNewState = WEAPON_IS_CARRIED_BY_PLAYER;
  912. if ( pPlayer->GetActiveWeapon() == this )
  913. {
  914. if ( pPlayer->m_fOnTarget )
  915. {
  916. iNewState = WEAPON_IS_ONTARGET;
  917. }
  918. else
  919. {
  920. iNewState = WEAPON_IS_ACTIVE;
  921. }
  922. }
  923. else
  924. {
  925. iNewState = WEAPON_IS_CARRIED_BY_PLAYER;
  926. }
  927. if ( m_iState != iNewState )
  928. {
  929. int iOldState = m_iState;
  930. m_iState = iNewState;
  931. OnActiveStateChanged( iOldState );
  932. }
  933. return 1;
  934. }
  935. //-----------------------------------------------------------------------------
  936. // Purpose:
  937. // Input : index -
  938. //-----------------------------------------------------------------------------
  939. void CBaseCombatWeapon::SetViewModelIndex( int index_ )
  940. {
  941. Assert( index_ >= 0 && index_ < MAX_VIEWMODELS );
  942. m_nViewModelIndex = index_;
  943. }
  944. //-----------------------------------------------------------------------------
  945. // Purpose:
  946. // Input : iActivity -
  947. //-----------------------------------------------------------------------------
  948. void CBaseCombatWeapon::SendViewModelAnim( int nSequence )
  949. {
  950. #if defined( CLIENT_DLL )
  951. if ( !IsPredicted() )
  952. return;
  953. #endif
  954. if ( nSequence < 0 )
  955. return;
  956. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  957. if ( pOwner == NULL )
  958. return;
  959. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex, false );
  960. if ( vm == NULL )
  961. return;
  962. SetViewModel();
  963. Assert( vm->ViewModelIndex() == m_nViewModelIndex );
  964. vm->SendViewModelMatchingSequence( nSequence );
  965. }
  966. float CBaseCombatWeapon::GetViewModelSequenceDuration()
  967. {
  968. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  969. if ( pOwner == NULL )
  970. {
  971. Assert( false );
  972. return 0;
  973. }
  974. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
  975. if ( vm == NULL )
  976. {
  977. Assert( false );
  978. return 0;
  979. }
  980. SetViewModel();
  981. Assert( vm->ViewModelIndex() == m_nViewModelIndex );
  982. return vm->SequenceDuration();
  983. }
  984. bool CBaseCombatWeapon::IsViewModelSequenceFinished( void ) const
  985. {
  986. // These are not valid activities and always complete immediately
  987. if ( GetActivity() == ACT_RESET || GetActivity() == ACT_INVALID )
  988. return true;
  989. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  990. if ( pOwner == NULL )
  991. {
  992. Assert( false );
  993. return false;
  994. }
  995. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
  996. if ( vm == NULL )
  997. {
  998. Assert( false );
  999. return false;
  1000. }
  1001. return vm->IsSequenceFinished();
  1002. }
  1003. //-----------------------------------------------------------------------------
  1004. // Purpose:
  1005. //-----------------------------------------------------------------------------
  1006. void CBaseCombatWeapon::SetViewModel()
  1007. {
  1008. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  1009. if ( pOwner == NULL )
  1010. return;
  1011. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex, false );
  1012. if ( vm == NULL )
  1013. return;
  1014. Assert( vm->ViewModelIndex() == m_nViewModelIndex );
  1015. vm->SetWeaponModel( GetViewModel( m_nViewModelIndex ), this );
  1016. }
  1017. //-----------------------------------------------------------------------------
  1018. // Purpose: Set the desired activity for the weapon and its viewmodel counterpart
  1019. // Input : iActivity - activity to play
  1020. //-----------------------------------------------------------------------------
  1021. bool CBaseCombatWeapon::SendWeaponAnim( int iActivity )
  1022. {
  1023. #ifdef USES_ECON_ITEMS
  1024. iActivity = TranslateViewmodelHandActivity( (Activity)iActivity );
  1025. #endif
  1026. // NVNT notify the haptics system of this weapons new activity
  1027. #ifdef WIN32
  1028. #ifdef CLIENT_DLL
  1029. if ( prediction->InPrediction() && prediction->IsFirstTimePredicted() )
  1030. #endif
  1031. #ifndef _X360
  1032. HapticSendWeaponAnim(this,iActivity);
  1033. #endif
  1034. #endif
  1035. //For now, just set the ideal activity and be done with it
  1036. return SetIdealActivity( (Activity) iActivity );
  1037. }
  1038. //====================================================================================
  1039. // WEAPON SELECTION
  1040. //====================================================================================
  1041. //-----------------------------------------------------------------------------
  1042. // Purpose: Returns true if the weapon currently has ammo or doesn't need ammo
  1043. // Output :
  1044. //-----------------------------------------------------------------------------
  1045. bool CBaseCombatWeapon::HasAnyAmmo( void )
  1046. {
  1047. // If I don't use ammo of any kind, I can always fire
  1048. if ( !UsesPrimaryAmmo() && !UsesSecondaryAmmo() )
  1049. return true;
  1050. // Otherwise, I need ammo of either type
  1051. return ( HasPrimaryAmmo() || HasSecondaryAmmo() );
  1052. }
  1053. //-----------------------------------------------------------------------------
  1054. // Purpose: Returns true if the weapon currently has ammo or doesn't need ammo
  1055. // Output :
  1056. //-----------------------------------------------------------------------------
  1057. bool CBaseCombatWeapon::HasPrimaryAmmo( void )
  1058. {
  1059. // If I use a clip, and have some ammo in it, then I have ammo
  1060. if ( UsesClipsForAmmo1() )
  1061. {
  1062. if ( m_iClip1 > 0 )
  1063. return true;
  1064. }
  1065. // Otherwise, I have ammo if I have some in my ammo counts
  1066. CBaseCombatCharacter *pOwner = GetOwner();
  1067. if ( pOwner )
  1068. {
  1069. if ( pOwner->GetAmmoCount( m_iPrimaryAmmoType ) > 0 )
  1070. return true;
  1071. }
  1072. else
  1073. {
  1074. // No owner, so return how much primary ammo I have along with me.
  1075. if( GetPrimaryAmmoCount() > 0 )
  1076. return true;
  1077. }
  1078. return false;
  1079. }
  1080. //-----------------------------------------------------------------------------
  1081. // Purpose: Returns true if the weapon currently has ammo or doesn't need ammo
  1082. // Output :
  1083. //-----------------------------------------------------------------------------
  1084. bool CBaseCombatWeapon::HasSecondaryAmmo( void )
  1085. {
  1086. // If I use a clip, and have some ammo in it, then I have ammo
  1087. if ( UsesClipsForAmmo2() )
  1088. {
  1089. if ( m_iClip2 > 0 )
  1090. return true;
  1091. }
  1092. // Otherwise, I have ammo if I have some in my ammo counts
  1093. CBaseCombatCharacter *pOwner = GetOwner();
  1094. if ( pOwner )
  1095. {
  1096. if ( pOwner->GetAmmoCount( m_iSecondaryAmmoType ) > 0 )
  1097. return true;
  1098. }
  1099. return false;
  1100. }
  1101. //-----------------------------------------------------------------------------
  1102. // Purpose: returns true if the weapon actually uses primary ammo
  1103. //-----------------------------------------------------------------------------
  1104. bool CBaseCombatWeapon::UsesPrimaryAmmo( void )
  1105. {
  1106. if ( m_iPrimaryAmmoType < 0 )
  1107. return false;
  1108. return true;
  1109. }
  1110. //-----------------------------------------------------------------------------
  1111. // Purpose: returns true if the weapon actually uses secondary ammo
  1112. //-----------------------------------------------------------------------------
  1113. bool CBaseCombatWeapon::UsesSecondaryAmmo( void )
  1114. {
  1115. if ( m_iSecondaryAmmoType < 0 )
  1116. return false;
  1117. return true;
  1118. }
  1119. //-----------------------------------------------------------------------------
  1120. // Purpose: Show/hide weapon and corresponding view model if any
  1121. // Input : visible -
  1122. //-----------------------------------------------------------------------------
  1123. void CBaseCombatWeapon::SetWeaponVisible( bool visible )
  1124. {
  1125. CBaseViewModel *vm = NULL;
  1126. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  1127. if ( pOwner )
  1128. {
  1129. vm = pOwner->GetViewModel( m_nViewModelIndex );
  1130. }
  1131. if ( visible )
  1132. {
  1133. RemoveEffects( EF_NODRAW );
  1134. if ( vm )
  1135. {
  1136. vm->RemoveEffects( EF_NODRAW );
  1137. }
  1138. }
  1139. else
  1140. {
  1141. AddEffects( EF_NODRAW );
  1142. if ( vm )
  1143. {
  1144. vm->AddEffects( EF_NODRAW );
  1145. }
  1146. }
  1147. }
  1148. //-----------------------------------------------------------------------------
  1149. // Purpose:
  1150. //-----------------------------------------------------------------------------
  1151. bool CBaseCombatWeapon::IsWeaponVisible( void )
  1152. {
  1153. CBaseViewModel *vm = NULL;
  1154. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  1155. if ( pOwner )
  1156. {
  1157. vm = pOwner->GetViewModel( m_nViewModelIndex );
  1158. if ( vm )
  1159. return ( !vm->IsEffectActive(EF_NODRAW) );
  1160. }
  1161. return false;
  1162. }
  1163. //-----------------------------------------------------------------------------
  1164. // Purpose: If the current weapon has more ammo, reload it. Otherwise, switch
  1165. // to the next best weapon we've got. Returns true if it took any action.
  1166. //-----------------------------------------------------------------------------
  1167. bool CBaseCombatWeapon::ReloadOrSwitchWeapons( void )
  1168. {
  1169. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  1170. Assert( pOwner );
  1171. m_bFireOnEmpty = false;
  1172. // If we don't have any ammo, switch to the next best weapon
  1173. if ( !HasAnyAmmo() && m_flNextPrimaryAttack < gpGlobals->curtime && m_flNextSecondaryAttack < gpGlobals->curtime )
  1174. {
  1175. // weapon isn't useable, switch.
  1176. if ( ( (GetWeaponFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) == false ) && ( g_pGameRules->SwitchToNextBestWeapon( pOwner, this ) ) )
  1177. {
  1178. m_flNextPrimaryAttack = gpGlobals->curtime + 0.3;
  1179. return true;
  1180. }
  1181. }
  1182. else
  1183. {
  1184. // Weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
  1185. if ( UsesClipsForAmmo1() && !AutoFiresFullClip() &&
  1186. (m_iClip1 == 0) &&
  1187. (GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD) == false &&
  1188. m_flNextPrimaryAttack < gpGlobals->curtime &&
  1189. m_flNextSecondaryAttack < gpGlobals->curtime )
  1190. {
  1191. // if we're successfully reloading, we're done
  1192. if ( Reload() )
  1193. return true;
  1194. }
  1195. }
  1196. return false;
  1197. }
  1198. //-----------------------------------------------------------------------------
  1199. // Purpose:
  1200. // Input : *szViewModel -
  1201. // *szWeaponModel -
  1202. // iActivity -
  1203. // *szAnimExt -
  1204. // Output : Returns true on success, false on failure.
  1205. //-----------------------------------------------------------------------------
  1206. bool CBaseCombatWeapon::DefaultDeploy( char *szViewModel, char *szWeaponModel, int iActivity, char *szAnimExt )
  1207. {
  1208. // Msg( "deploy %s at %f\n", GetClassname(), gpGlobals->curtime );
  1209. // Weapons that don't autoswitch away when they run out of ammo
  1210. // can still be deployed when they have no ammo.
  1211. if ( !HasAnyAmmo() && AllowsAutoSwitchFrom() )
  1212. return false;
  1213. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  1214. if ( pOwner )
  1215. {
  1216. // Dead men deploy no weapons
  1217. if ( pOwner->IsAlive() == false )
  1218. return false;
  1219. pOwner->SetAnimationExtension( szAnimExt );
  1220. SetViewModel();
  1221. SendWeaponAnim( iActivity );
  1222. pOwner->SetNextAttack( gpGlobals->curtime + SequenceDuration() );
  1223. }
  1224. // Can't shoot again until we've finished deploying
  1225. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  1226. m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
  1227. m_flHudHintMinDisplayTime = 0;
  1228. m_bAltFireHudHintDisplayed = false;
  1229. m_bReloadHudHintDisplayed = false;
  1230. m_flHudHintPollTime = gpGlobals->curtime + 5.0f;
  1231. WeaponSound( DEPLOY );
  1232. SetWeaponVisible( true );
  1233. /*
  1234. This code is disabled for now, because moving through the weapons in the carousel
  1235. selects and deploys each weapon as you pass it. (sjb)
  1236. */
  1237. SetContextThink( NULL, 0, HIDEWEAPON_THINK_CONTEXT );
  1238. return true;
  1239. }
  1240. //-----------------------------------------------------------------------------
  1241. // Purpose:
  1242. //-----------------------------------------------------------------------------
  1243. bool CBaseCombatWeapon::Deploy( )
  1244. {
  1245. MDLCACHE_CRITICAL_SECTION();
  1246. bool bResult = DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), GetDrawActivity(), (char*)GetAnimPrefix() );
  1247. // override pose parameters
  1248. PoseParameterOverride( false );
  1249. return bResult;
  1250. }
  1251. Activity CBaseCombatWeapon::GetDrawActivity( void )
  1252. {
  1253. return ACT_VM_DRAW;
  1254. }
  1255. //-----------------------------------------------------------------------------
  1256. // Purpose:
  1257. //-----------------------------------------------------------------------------
  1258. bool CBaseCombatWeapon::Holster( CBaseCombatWeapon *pSwitchingTo )
  1259. {
  1260. MDLCACHE_CRITICAL_SECTION();
  1261. // cancel any reload in progress.
  1262. m_bInReload = false;
  1263. m_bFiringWholeClip = false;
  1264. // kill any think functions
  1265. SetThink(NULL);
  1266. // Send holster animation
  1267. SendWeaponAnim( ACT_VM_HOLSTER );
  1268. // Some weapon's don't have holster anims yet, so detect that
  1269. float flSequenceDuration = 0;
  1270. if ( GetActivity() == ACT_VM_HOLSTER )
  1271. {
  1272. flSequenceDuration = SequenceDuration();
  1273. }
  1274. CBaseCombatCharacter *pOwner = GetOwner();
  1275. if (pOwner)
  1276. {
  1277. pOwner->SetNextAttack( gpGlobals->curtime + flSequenceDuration );
  1278. }
  1279. // If we don't have a holster anim, hide immediately to avoid timing issues
  1280. if ( !flSequenceDuration )
  1281. {
  1282. SetWeaponVisible( false );
  1283. }
  1284. else
  1285. {
  1286. // Hide the weapon when the holster animation's finished
  1287. SetContextThink( &CBaseCombatWeapon::HideThink, gpGlobals->curtime + flSequenceDuration, HIDEWEAPON_THINK_CONTEXT );
  1288. }
  1289. // if we were displaying a hud hint, squelch it.
  1290. if (m_flHudHintMinDisplayTime && gpGlobals->curtime < m_flHudHintMinDisplayTime)
  1291. {
  1292. if( m_bAltFireHudHintDisplayed )
  1293. RescindAltFireHudHint();
  1294. if( m_bReloadHudHintDisplayed )
  1295. RescindReloadHudHint();
  1296. }
  1297. // reset pose parameters
  1298. PoseParameterOverride( true );
  1299. return true;
  1300. }
  1301. #ifdef CLIENT_DLL
  1302. void CBaseCombatWeapon::BoneMergeFastCullBloat( Vector &localMins, Vector &localMaxs, const Vector &thisEntityMins, const Vector &thisEntityMaxs ) const
  1303. {
  1304. // The default behavior pushes it out by BONEMERGE_FASTCULL_BBOX_EXPAND in all directions, but we can do better
  1305. // since we know the weapon will never point behind him.
  1306. localMaxs.x += 20; // Leaves some space in front for long weapons.
  1307. localMins.y -= 20; // Fatten it to his left and right since he can rotate that way.
  1308. localMaxs.y += 20;
  1309. localMaxs.z += 15; // Leave some space at the top.
  1310. }
  1311. #else
  1312. //-----------------------------------------------------------------------------
  1313. // Purpose:
  1314. //-----------------------------------------------------------------------------
  1315. void CBaseCombatWeapon::InputHideWeapon( inputdata_t &inputdata )
  1316. {
  1317. // Only hide if we're still the active weapon. If we're not the active weapon
  1318. if ( GetOwner() && GetOwner()->GetActiveWeapon() == this )
  1319. {
  1320. SetWeaponVisible( false );
  1321. }
  1322. }
  1323. #endif
  1324. //-----------------------------------------------------------------------------
  1325. // Purpose:
  1326. //-----------------------------------------------------------------------------
  1327. void CBaseCombatWeapon::HideThink( void )
  1328. {
  1329. // Only hide if we're still the active weapon. If we're not the active weapon
  1330. if ( GetOwner() && GetOwner()->GetActiveWeapon() == this )
  1331. {
  1332. SetWeaponVisible( false );
  1333. }
  1334. }
  1335. bool CBaseCombatWeapon::CanReload( void )
  1336. {
  1337. if ( AutoFiresFullClip() && m_bFiringWholeClip )
  1338. {
  1339. return false;
  1340. }
  1341. return true;
  1342. }
  1343. #if defined ( TF_CLIENT_DLL ) || defined ( TF_DLL )
  1344. //-----------------------------------------------------------------------------
  1345. // Purpose: Anti-hack
  1346. //-----------------------------------------------------------------------------
  1347. void CBaseCombatWeapon::AddToCritBucket( float flAmount )
  1348. {
  1349. float flCap = tf_weapon_criticals_bucket_cap.GetFloat();
  1350. // Regulate crit frequency to reduce client-side seed hacking
  1351. if ( m_flCritTokenBucket < flCap )
  1352. {
  1353. // Treat raw damage as the resource by which we add or subtract from the bucket
  1354. m_flCritTokenBucket += flAmount;
  1355. m_flCritTokenBucket = Min( m_flCritTokenBucket, flCap );
  1356. }
  1357. }
  1358. //-----------------------------------------------------------------------------
  1359. // Purpose: Anti-hack
  1360. //-----------------------------------------------------------------------------
  1361. bool CBaseCombatWeapon::IsAllowedToWithdrawFromCritBucket( float flDamage )
  1362. {
  1363. // Note: If we're in this block of code, the assumption is that the
  1364. // seed said we should grant a random crit. If allowed, the cost
  1365. // will be deducted here.
  1366. // Track each seed request - in cases where a player is hacking, we'll
  1367. // see a silly ratio.
  1368. m_nCritSeedRequests++;
  1369. // Adjust token cost based on the ratio of requests vs granted, except
  1370. // melee, which crits much more than ranged (as high as 60% chance)
  1371. float flMult = ( IsMeleeWeapon() ) ? 0.5f : RemapValClamped( ( (float)m_nCritSeedRequests / (float)m_nCritChecks ), 0.1f, 1.f, 1.f, 3.f );
  1372. // Would this take us below our limit?
  1373. float flCost = ( flDamage * TF_DAMAGE_CRIT_MULTIPLIER ) * flMult;
  1374. if ( flCost > m_flCritTokenBucket )
  1375. return false;
  1376. // Withdraw
  1377. RemoveFromCritBucket( flCost );
  1378. float flBottom = tf_weapon_criticals_bucket_bottom.GetFloat();
  1379. if ( m_flCritTokenBucket < flBottom )
  1380. m_flCritTokenBucket = flBottom;
  1381. return true;
  1382. }
  1383. #endif // TF_DLL
  1384. //-----------------------------------------------------------------------------
  1385. // Purpose:
  1386. //-----------------------------------------------------------------------------
  1387. void CBaseCombatWeapon::ItemPreFrame( void )
  1388. {
  1389. MaintainIdealActivity();
  1390. #ifndef CLIENT_DLL
  1391. #ifndef HL2_EPISODIC
  1392. if ( IsX360() )
  1393. #endif
  1394. {
  1395. // If we haven't displayed the hint enough times yet, it's time to try to
  1396. // display the hint, and the player is not standing still, try to show a hud hint.
  1397. // If the player IS standing still, assume they could change away from this weapon at
  1398. // any second.
  1399. if( (!m_bAltFireHudHintDisplayed || !m_bReloadHudHintDisplayed) && gpGlobals->curtime > m_flHudHintMinDisplayTime && gpGlobals->curtime > m_flHudHintPollTime && GetOwner() && GetOwner()->IsPlayer() )
  1400. {
  1401. CBasePlayer *pPlayer = (CBasePlayer*)(GetOwner());
  1402. if( pPlayer && pPlayer->GetStickDist() > 0.0f )
  1403. {
  1404. // If the player is moving, they're unlikely to switch away from the current weapon
  1405. // the moment this weapon displays its HUD hint.
  1406. if( ShouldDisplayReloadHUDHint() )
  1407. {
  1408. DisplayReloadHudHint();
  1409. }
  1410. else if( ShouldDisplayAltFireHUDHint() )
  1411. {
  1412. DisplayAltFireHudHint();
  1413. }
  1414. }
  1415. else
  1416. {
  1417. m_flHudHintPollTime = gpGlobals->curtime + 2.0f;
  1418. }
  1419. }
  1420. }
  1421. #endif
  1422. }
  1423. bool CBaseCombatWeapon::CanPerformSecondaryAttack() const
  1424. {
  1425. return m_flNextSecondaryAttack <= gpGlobals->curtime;
  1426. }
  1427. //====================================================================================
  1428. // WEAPON BEHAVIOUR
  1429. //====================================================================================
  1430. void CBaseCombatWeapon::ItemPostFrame( void )
  1431. {
  1432. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  1433. if (!pOwner)
  1434. return;
  1435. UpdateAutoFire();
  1436. //Track the duration of the fire
  1437. //FIXME: Check for IN_ATTACK2 as well?
  1438. //FIXME: What if we're calling ItemBusyFrame?
  1439. m_fFireDuration = ( pOwner->m_nButtons & IN_ATTACK ) ? ( m_fFireDuration + gpGlobals->frametime ) : 0.0f;
  1440. if ( UsesClipsForAmmo1() )
  1441. {
  1442. CheckReload();
  1443. }
  1444. bool bFired = false;
  1445. // Secondary attack has priority
  1446. if ((pOwner->m_nButtons & IN_ATTACK2) && CanPerformSecondaryAttack() )
  1447. {
  1448. if (UsesSecondaryAmmo() && pOwner->GetAmmoCount(m_iSecondaryAmmoType)<=0 )
  1449. {
  1450. if (m_flNextEmptySoundTime < gpGlobals->curtime)
  1451. {
  1452. WeaponSound(EMPTY);
  1453. m_flNextSecondaryAttack = m_flNextEmptySoundTime = gpGlobals->curtime + 0.5;
  1454. }
  1455. }
  1456. else if (pOwner->GetWaterLevel() == 3 && m_bAltFiresUnderwater == false)
  1457. {
  1458. // This weapon doesn't fire underwater
  1459. WeaponSound(EMPTY);
  1460. m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
  1461. return;
  1462. }
  1463. else
  1464. {
  1465. // FIXME: This isn't necessarily true if the weapon doesn't have a secondary fire!
  1466. // For instance, the crossbow doesn't have a 'real' secondary fire, but it still
  1467. // stops the crossbow from firing on the 360 if the player chooses to hold down their
  1468. // zoom button. (sjb) Orange Box 7/25/2007
  1469. #if !defined(CLIENT_DLL)
  1470. if( !IsX360() || !ClassMatches("weapon_crossbow") )
  1471. #endif
  1472. {
  1473. bFired = ShouldBlockPrimaryFire();
  1474. }
  1475. SecondaryAttack();
  1476. // Secondary ammo doesn't have a reload animation
  1477. if ( UsesClipsForAmmo2() )
  1478. {
  1479. // reload clip2 if empty
  1480. if (m_iClip2 < 1)
  1481. {
  1482. pOwner->RemoveAmmo( 1, m_iSecondaryAmmoType );
  1483. m_iClip2 = m_iClip2 + 1;
  1484. }
  1485. }
  1486. }
  1487. }
  1488. if ( !bFired && (pOwner->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime))
  1489. {
  1490. // Clip empty? Or out of ammo on a no-clip weapon?
  1491. if ( !IsMeleeWeapon() &&
  1492. (( UsesClipsForAmmo1() && m_iClip1 <= 0) || ( !UsesClipsForAmmo1() && pOwner->GetAmmoCount(m_iPrimaryAmmoType)<=0 )) )
  1493. {
  1494. HandleFireOnEmpty();
  1495. }
  1496. else if (pOwner->GetWaterLevel() == 3 && m_bFiresUnderwater == false)
  1497. {
  1498. // This weapon doesn't fire underwater
  1499. WeaponSound(EMPTY);
  1500. m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
  1501. return;
  1502. }
  1503. else
  1504. {
  1505. //NOTENOTE: There is a bug with this code with regards to the way machine guns catch the leading edge trigger
  1506. // on the player hitting the attack key. It relies on the gun catching that case in the same frame.
  1507. // However, because the player can also be doing a secondary attack, the edge trigger may be missed.
  1508. // We really need to hold onto the edge trigger and only clear the condition when the gun has fired its
  1509. // first shot. Right now that's too much of an architecture change -- jdw
  1510. // If the firing button was just pressed, or the alt-fire just released, reset the firing time
  1511. if ( ( pOwner->m_afButtonPressed & IN_ATTACK ) || ( pOwner->m_afButtonReleased & IN_ATTACK2 ) )
  1512. {
  1513. m_flNextPrimaryAttack = gpGlobals->curtime;
  1514. }
  1515. PrimaryAttack();
  1516. if ( AutoFiresFullClip() )
  1517. {
  1518. m_bFiringWholeClip = true;
  1519. }
  1520. #ifdef CLIENT_DLL
  1521. pOwner->SetFiredWeapon( true );
  1522. #endif
  1523. }
  1524. }
  1525. // -----------------------
  1526. // Reload pressed / Clip Empty
  1527. // Can only start the Reload Cycle after the firing cycle
  1528. if ( ( pOwner->m_nButtons & IN_RELOAD ) && m_flNextPrimaryAttack <= gpGlobals->curtime && UsesClipsForAmmo1() && !m_bInReload )
  1529. {
  1530. // reload when reload is pressed, or if no buttons are down and weapon is empty.
  1531. Reload();
  1532. m_fFireDuration = 0.0f;
  1533. }
  1534. // -----------------------
  1535. // No buttons down
  1536. // -----------------------
  1537. if (!((pOwner->m_nButtons & IN_ATTACK) || (pOwner->m_nButtons & IN_ATTACK2) || (CanReload() && pOwner->m_nButtons & IN_RELOAD)))
  1538. {
  1539. // no fire buttons down or reloading
  1540. if ( !ReloadOrSwitchWeapons() && ( m_bInReload == false ) )
  1541. {
  1542. WeaponIdle();
  1543. }
  1544. }
  1545. }
  1546. void CBaseCombatWeapon::HandleFireOnEmpty()
  1547. {
  1548. // If we're already firing on empty, reload if we can
  1549. if ( m_bFireOnEmpty )
  1550. {
  1551. ReloadOrSwitchWeapons();
  1552. m_fFireDuration = 0.0f;
  1553. }
  1554. else
  1555. {
  1556. if (m_flNextEmptySoundTime < gpGlobals->curtime)
  1557. {
  1558. WeaponSound(EMPTY);
  1559. m_flNextEmptySoundTime = gpGlobals->curtime + 0.5;
  1560. }
  1561. m_bFireOnEmpty = true;
  1562. }
  1563. }
  1564. //-----------------------------------------------------------------------------
  1565. // Purpose: Called each frame by the player PostThink, if the player's not ready to attack yet
  1566. //-----------------------------------------------------------------------------
  1567. void CBaseCombatWeapon::ItemBusyFrame( void )
  1568. {
  1569. UpdateAutoFire();
  1570. }
  1571. //-----------------------------------------------------------------------------
  1572. // Purpose: Base class default for getting bullet type
  1573. // Input :
  1574. // Output :
  1575. //-----------------------------------------------------------------------------
  1576. int CBaseCombatWeapon::GetBulletType( void )
  1577. {
  1578. return 0;
  1579. }
  1580. //-----------------------------------------------------------------------------
  1581. // Purpose: Base class default for getting spread
  1582. // Input :
  1583. // Output :
  1584. //-----------------------------------------------------------------------------
  1585. const Vector& CBaseCombatWeapon::GetBulletSpread( void )
  1586. {
  1587. static Vector cone = VECTOR_CONE_15DEGREES;
  1588. return cone;
  1589. }
  1590. //-----------------------------------------------------------------------------
  1591. const WeaponProficiencyInfo_t *CBaseCombatWeapon::GetProficiencyValues()
  1592. {
  1593. static WeaponProficiencyInfo_t defaultWeaponProficiencyTable[] =
  1594. {
  1595. { 1.0, 1.0 },
  1596. { 1.0, 1.0 },
  1597. { 1.0, 1.0 },
  1598. { 1.0, 1.0 },
  1599. { 1.0, 1.0 },
  1600. };
  1601. COMPILE_TIME_ASSERT( ARRAYSIZE(defaultWeaponProficiencyTable) == WEAPON_PROFICIENCY_PERFECT + 1);
  1602. return defaultWeaponProficiencyTable;
  1603. }
  1604. //-----------------------------------------------------------------------------
  1605. // Purpose: Base class default for getting firerate
  1606. // Input :
  1607. // Output :
  1608. //-----------------------------------------------------------------------------
  1609. float CBaseCombatWeapon::GetFireRate( void )
  1610. {
  1611. return 0;
  1612. }
  1613. //-----------------------------------------------------------------------------
  1614. // Purpose: Base class default for playing shoot sound
  1615. // Input :
  1616. // Output :
  1617. //-----------------------------------------------------------------------------
  1618. void CBaseCombatWeapon::WeaponSound( WeaponSound_t sound_type, float soundtime /* = 0.0f */ )
  1619. {
  1620. #if !defined( CLIENT_DLL )
  1621. if ( !m_bSoundsEnabled )
  1622. return;
  1623. #endif
  1624. // If we have some sounds from the weapon classname.txt file, play a random one of them
  1625. const char *shootsound = GetShootSound( sound_type );
  1626. if ( !shootsound || !shootsound[0] )
  1627. return;
  1628. CSoundParameters params;
  1629. if ( !GetParametersForSound( shootsound, params, NULL ) )
  1630. return;
  1631. if ( params.play_to_owner_only )
  1632. {
  1633. // Am I only to play to my owner?
  1634. if ( GetOwner() && GetOwner()->IsPlayer() )
  1635. {
  1636. CSingleUserRecipientFilter filter( ToBasePlayer( GetOwner() ) );
  1637. if ( IsPredicted() && CBaseEntity::GetPredictionPlayer() )
  1638. {
  1639. filter.UsePredictionRules();
  1640. }
  1641. EmitSound( filter, GetOwner()->entindex(), shootsound, NULL, soundtime );
  1642. }
  1643. }
  1644. else
  1645. {
  1646. // Play weapon sound from the owner
  1647. if ( GetOwner() )
  1648. {
  1649. CPASAttenuationFilter filter( GetOwner(), params.soundlevel );
  1650. if ( IsPredicted() && CBaseEntity::GetPredictionPlayer() )
  1651. {
  1652. filter.UsePredictionRules();
  1653. }
  1654. EmitSound( filter, GetOwner()->entindex(), shootsound, NULL, soundtime );
  1655. #if !defined( CLIENT_DLL )
  1656. if( sound_type == EMPTY )
  1657. {
  1658. CSoundEnt::InsertSound( SOUND_COMBAT, GetOwner()->GetAbsOrigin(), SOUNDENT_VOLUME_EMPTY, 0.2, GetOwner() );
  1659. }
  1660. #endif
  1661. }
  1662. // If no owner play from the weapon (this is used for thrown items)
  1663. else
  1664. {
  1665. CPASAttenuationFilter filter( this, params.soundlevel );
  1666. if ( IsPredicted() && CBaseEntity::GetPredictionPlayer() )
  1667. {
  1668. filter.UsePredictionRules();
  1669. }
  1670. EmitSound( filter, entindex(), shootsound, NULL, soundtime );
  1671. }
  1672. }
  1673. }
  1674. //-----------------------------------------------------------------------------
  1675. // Purpose: Stop a sound played by this weapon.
  1676. //-----------------------------------------------------------------------------
  1677. void CBaseCombatWeapon::StopWeaponSound( WeaponSound_t sound_type )
  1678. {
  1679. //if ( IsPredicted() )
  1680. // return;
  1681. // If we have some sounds from the weapon classname.txt file, play a random one of them
  1682. const char *shootsound = GetShootSound( sound_type );
  1683. if ( !shootsound || !shootsound[0] )
  1684. return;
  1685. CSoundParameters params;
  1686. if ( !GetParametersForSound( shootsound, params, NULL ) )
  1687. return;
  1688. // Am I only to play to my owner?
  1689. if ( params.play_to_owner_only )
  1690. {
  1691. if ( GetOwner() )
  1692. {
  1693. StopSound( GetOwner()->entindex(), shootsound );
  1694. }
  1695. }
  1696. else
  1697. {
  1698. // Play weapon sound from the owner
  1699. if ( GetOwner() )
  1700. {
  1701. StopSound( GetOwner()->entindex(), shootsound );
  1702. }
  1703. // If no owner play from the weapon (this is used for thrown items)
  1704. else
  1705. {
  1706. StopSound( entindex(), shootsound );
  1707. }
  1708. }
  1709. }
  1710. //-----------------------------------------------------------------------------
  1711. // Purpose:
  1712. //-----------------------------------------------------------------------------
  1713. bool CBaseCombatWeapon::DefaultReload( int iClipSize1, int iClipSize2, int iActivity )
  1714. {
  1715. CBaseCombatCharacter *pOwner = GetOwner();
  1716. if (!pOwner)
  1717. return false;
  1718. // If I don't have any spare ammo, I can't reload
  1719. if ( pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
  1720. return false;
  1721. bool bReload = false;
  1722. // If you don't have clips, then don't try to reload them.
  1723. if ( UsesClipsForAmmo1() )
  1724. {
  1725. // need to reload primary clip?
  1726. int primary = MIN(iClipSize1 - m_iClip1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));
  1727. if ( primary != 0 )
  1728. {
  1729. bReload = true;
  1730. }
  1731. }
  1732. if ( UsesClipsForAmmo2() )
  1733. {
  1734. // need to reload secondary clip?
  1735. int secondary = MIN(iClipSize2 - m_iClip2, pOwner->GetAmmoCount(m_iSecondaryAmmoType));
  1736. if ( secondary != 0 )
  1737. {
  1738. bReload = true;
  1739. }
  1740. }
  1741. if ( !bReload )
  1742. return false;
  1743. #ifdef CLIENT_DLL
  1744. // Play reload
  1745. WeaponSound( RELOAD );
  1746. #endif
  1747. SendWeaponAnim( iActivity );
  1748. // Play the player's reload animation
  1749. if ( pOwner->IsPlayer() )
  1750. {
  1751. ( ( CBasePlayer * )pOwner)->SetAnimation( PLAYER_RELOAD );
  1752. }
  1753. MDLCACHE_CRITICAL_SECTION();
  1754. float flSequenceEndTime = gpGlobals->curtime + SequenceDuration();
  1755. pOwner->SetNextAttack( flSequenceEndTime );
  1756. m_flNextPrimaryAttack = m_flNextSecondaryAttack = flSequenceEndTime;
  1757. m_bInReload = true;
  1758. return true;
  1759. }
  1760. bool CBaseCombatWeapon::ReloadsSingly( void ) const
  1761. {
  1762. #if defined ( TF_DLL ) || defined ( TF_CLIENT_DLL )
  1763. float fHasReload = 1.0f;
  1764. CALL_ATTRIB_HOOK_FLOAT( fHasReload, mod_no_reload_display_only );
  1765. if ( fHasReload != 1.0f )
  1766. {
  1767. return false;
  1768. }
  1769. int iWeaponMod = 0;
  1770. CALL_ATTRIB_HOOK_INT( iWeaponMod, set_scattergun_no_reload_single );
  1771. if ( iWeaponMod == 1 )
  1772. {
  1773. return false;
  1774. }
  1775. #endif // TF_DLL || TF_CLIENT_DLL
  1776. return m_bReloadsSingly;
  1777. }
  1778. //-----------------------------------------------------------------------------
  1779. // Purpose:
  1780. //-----------------------------------------------------------------------------
  1781. bool CBaseCombatWeapon::Reload( void )
  1782. {
  1783. return DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD );
  1784. }
  1785. //=========================================================
  1786. void CBaseCombatWeapon::WeaponIdle( void )
  1787. {
  1788. //Idle again if we've finished
  1789. if ( HasWeaponIdleTimeElapsed() )
  1790. {
  1791. SendWeaponAnim( ACT_VM_IDLE );
  1792. }
  1793. }
  1794. //=========================================================
  1795. Activity CBaseCombatWeapon::GetPrimaryAttackActivity( void )
  1796. {
  1797. return ACT_VM_PRIMARYATTACK;
  1798. }
  1799. //=========================================================
  1800. Activity CBaseCombatWeapon::GetSecondaryAttackActivity( void )
  1801. {
  1802. return ACT_VM_SECONDARYATTACK;
  1803. }
  1804. //-----------------------------------------------------------------------------
  1805. // Purpose: Adds in view kick and weapon accuracy degradation effect
  1806. //-----------------------------------------------------------------------------
  1807. void CBaseCombatWeapon::AddViewKick( void )
  1808. {
  1809. //NOTENOTE: By default, weapon will not kick up (defined per weapon)
  1810. }
  1811. //-----------------------------------------------------------------------------
  1812. // Purpose: Get the string to print death notices with
  1813. //-----------------------------------------------------------------------------
  1814. char *CBaseCombatWeapon::GetDeathNoticeName( void )
  1815. {
  1816. #if !defined( CLIENT_DLL )
  1817. return (char*)STRING( m_iszName );
  1818. #else
  1819. return "GetDeathNoticeName not implemented on client yet";
  1820. #endif
  1821. }
  1822. //====================================================================================
  1823. // WEAPON RELOAD TYPES
  1824. //====================================================================================
  1825. void CBaseCombatWeapon::CheckReload( void )
  1826. {
  1827. if ( m_bReloadsSingly )
  1828. {
  1829. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  1830. if ( !pOwner )
  1831. return;
  1832. if ((m_bInReload) && (m_flNextPrimaryAttack <= gpGlobals->curtime))
  1833. {
  1834. if ( pOwner->m_nButtons & (IN_ATTACK | IN_ATTACK2) && m_iClip1 > 0 )
  1835. {
  1836. m_bInReload = false;
  1837. return;
  1838. }
  1839. // If out of ammo end reload
  1840. if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <=0)
  1841. {
  1842. FinishReload();
  1843. return;
  1844. }
  1845. // If clip not full reload again
  1846. else if (m_iClip1 < GetMaxClip1())
  1847. {
  1848. // Add them to the clip
  1849. m_iClip1 += 1;
  1850. pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType );
  1851. Reload();
  1852. return;
  1853. }
  1854. // Clip full, stop reloading
  1855. else
  1856. {
  1857. FinishReload();
  1858. m_flNextPrimaryAttack = gpGlobals->curtime;
  1859. m_flNextSecondaryAttack = gpGlobals->curtime;
  1860. return;
  1861. }
  1862. }
  1863. }
  1864. else
  1865. {
  1866. if ( (m_bInReload) && (m_flNextPrimaryAttack <= gpGlobals->curtime))
  1867. {
  1868. FinishReload();
  1869. m_flNextPrimaryAttack = gpGlobals->curtime;
  1870. m_flNextSecondaryAttack = gpGlobals->curtime;
  1871. m_bInReload = false;
  1872. }
  1873. }
  1874. }
  1875. //-----------------------------------------------------------------------------
  1876. // Purpose: Reload has finished.
  1877. //-----------------------------------------------------------------------------
  1878. void CBaseCombatWeapon::FinishReload( void )
  1879. {
  1880. CBaseCombatCharacter *pOwner = GetOwner();
  1881. if (pOwner)
  1882. {
  1883. // If I use primary clips, reload primary
  1884. if ( UsesClipsForAmmo1() )
  1885. {
  1886. int primary = MIN( GetMaxClip1() - m_iClip1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));
  1887. m_iClip1 += primary;
  1888. pOwner->RemoveAmmo( primary, m_iPrimaryAmmoType);
  1889. }
  1890. // If I use secondary clips, reload secondary
  1891. if ( UsesClipsForAmmo2() )
  1892. {
  1893. int secondary = MIN( GetMaxClip2() - m_iClip2, pOwner->GetAmmoCount(m_iSecondaryAmmoType));
  1894. m_iClip2 += secondary;
  1895. pOwner->RemoveAmmo( secondary, m_iSecondaryAmmoType );
  1896. }
  1897. if ( m_bReloadsSingly )
  1898. {
  1899. m_bInReload = false;
  1900. }
  1901. }
  1902. }
  1903. //-----------------------------------------------------------------------------
  1904. // Purpose: Abort any reload we have in progress
  1905. //-----------------------------------------------------------------------------
  1906. void CBaseCombatWeapon::AbortReload( void )
  1907. {
  1908. #ifdef CLIENT_DLL
  1909. StopWeaponSound( RELOAD );
  1910. #endif
  1911. m_bInReload = false;
  1912. }
  1913. void CBaseCombatWeapon::UpdateAutoFire( void )
  1914. {
  1915. if ( !AutoFiresFullClip() )
  1916. return;
  1917. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  1918. if ( !pOwner )
  1919. return;
  1920. if ( m_iClip1 == 0 )
  1921. {
  1922. // Ready to reload again
  1923. m_bFiringWholeClip = false;
  1924. }
  1925. if ( m_bFiringWholeClip )
  1926. {
  1927. // If it's firing the clip don't let them repress attack to reload
  1928. pOwner->m_nButtons &= ~IN_ATTACK;
  1929. }
  1930. // Don't use the regular reload key
  1931. if ( pOwner->m_nButtons & IN_RELOAD )
  1932. {
  1933. pOwner->m_nButtons &= ~IN_RELOAD;
  1934. }
  1935. // Try to fire if there's ammo in the clip and we're not holding the button
  1936. bool bReleaseClip = m_iClip1 > 0 && !( pOwner->m_nButtons & IN_ATTACK );
  1937. if ( !bReleaseClip )
  1938. {
  1939. if ( CanReload() && ( pOwner->m_nButtons & IN_ATTACK ) )
  1940. {
  1941. // Convert the attack key into the reload key
  1942. pOwner->m_nButtons |= IN_RELOAD;
  1943. }
  1944. // Don't allow attack button if we're not attacking
  1945. pOwner->m_nButtons &= ~IN_ATTACK;
  1946. }
  1947. else
  1948. {
  1949. // Fake the attack key
  1950. pOwner->m_nButtons |= IN_ATTACK;
  1951. }
  1952. }
  1953. //-----------------------------------------------------------------------------
  1954. // Purpose: Primary fire button attack
  1955. //-----------------------------------------------------------------------------
  1956. void CBaseCombatWeapon::PrimaryAttack( void )
  1957. {
  1958. // If my clip is empty (and I use clips) start reload
  1959. if ( UsesClipsForAmmo1() && !m_iClip1 )
  1960. {
  1961. Reload();
  1962. return;
  1963. }
  1964. // Only the player fires this way so we can cast
  1965. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  1966. if (!pPlayer)
  1967. {
  1968. return;
  1969. }
  1970. pPlayer->DoMuzzleFlash();
  1971. SendWeaponAnim( GetPrimaryAttackActivity() );
  1972. // player "shoot" animation
  1973. pPlayer->SetAnimation( PLAYER_ATTACK1 );
  1974. FireBulletsInfo_t info;
  1975. info.m_vecSrc = pPlayer->Weapon_ShootPosition( );
  1976. info.m_vecDirShooting = pPlayer->GetAutoaimVector( AUTOAIM_SCALE_DEFAULT );
  1977. // To make the firing framerate independent, we may have to fire more than one bullet here on low-framerate systems,
  1978. // especially if the weapon we're firing has a really fast rate of fire.
  1979. info.m_iShots = 0;
  1980. float fireRate = GetFireRate();
  1981. while ( m_flNextPrimaryAttack <= gpGlobals->curtime )
  1982. {
  1983. // MUST call sound before removing a round from the clip of a CMachineGun
  1984. WeaponSound(SINGLE, m_flNextPrimaryAttack);
  1985. m_flNextPrimaryAttack = m_flNextPrimaryAttack + fireRate;
  1986. info.m_iShots++;
  1987. if ( !fireRate )
  1988. break;
  1989. }
  1990. // Make sure we don't fire more than the amount in the clip
  1991. if ( UsesClipsForAmmo1() )
  1992. {
  1993. info.m_iShots = MIN( info.m_iShots, m_iClip1 );
  1994. m_iClip1 -= info.m_iShots;
  1995. }
  1996. else
  1997. {
  1998. info.m_iShots = MIN( info.m_iShots, pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) );
  1999. pPlayer->RemoveAmmo( info.m_iShots, m_iPrimaryAmmoType );
  2000. }
  2001. info.m_flDistance = MAX_TRACE_LENGTH;
  2002. info.m_iAmmoType = m_iPrimaryAmmoType;
  2003. info.m_iTracerFreq = 2;
  2004. #if !defined( CLIENT_DLL )
  2005. // Fire the bullets
  2006. info.m_vecSpread = pPlayer->GetAttackSpread( this );
  2007. #else
  2008. //!!!HACKHACK - what does the client want this function for?
  2009. info.m_vecSpread = GetActiveWeapon()->GetBulletSpread();
  2010. #endif // CLIENT_DLL
  2011. pPlayer->FireBullets( info );
  2012. if (!m_iClip1 && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
  2013. {
  2014. // HEV suit - indicate out of ammo condition
  2015. pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
  2016. }
  2017. //Add our view kick in
  2018. AddViewKick();
  2019. }
  2020. //-----------------------------------------------------------------------------
  2021. // Purpose: Called every frame to check if the weapon is going through transition animations
  2022. //-----------------------------------------------------------------------------
  2023. void CBaseCombatWeapon::MaintainIdealActivity( void )
  2024. {
  2025. // Must be transitioning
  2026. if ( GetActivity() != ACT_TRANSITION )
  2027. return;
  2028. // Must not be at our ideal already
  2029. if ( ( GetActivity() == m_IdealActivity ) && ( GetSequence() == m_nIdealSequence ) )
  2030. return;
  2031. // Must be finished with the current animation
  2032. if ( IsViewModelSequenceFinished() == false )
  2033. return;
  2034. // Move to the next animation towards our ideal
  2035. SendWeaponAnim( m_IdealActivity );
  2036. }
  2037. //-----------------------------------------------------------------------------
  2038. // Purpose: Sets the ideal activity for the weapon to be in, allowing for transitional animations inbetween
  2039. // Input : ideal - activity to end up at, ideally
  2040. //-----------------------------------------------------------------------------
  2041. bool CBaseCombatWeapon::SetIdealActivity( Activity ideal )
  2042. {
  2043. MDLCACHE_CRITICAL_SECTION();
  2044. int idealSequence = SelectWeightedSequence( ideal );
  2045. if ( idealSequence == -1 )
  2046. return false;
  2047. //Take the new activity
  2048. m_IdealActivity = ideal;
  2049. m_nIdealSequence = idealSequence;
  2050. //Find the next sequence in the potential chain of sequences leading to our ideal one
  2051. int nextSequence = FindTransitionSequence( GetSequence(), m_nIdealSequence, NULL );
  2052. // Don't use transitions when we're deploying
  2053. if ( ideal != ACT_VM_DRAW && IsWeaponVisible() && nextSequence != m_nIdealSequence )
  2054. {
  2055. //Set our activity to the next transitional animation
  2056. SetActivity( ACT_TRANSITION );
  2057. SetSequence( nextSequence );
  2058. SendViewModelAnim( nextSequence );
  2059. }
  2060. else
  2061. {
  2062. //Set our activity to the ideal
  2063. SetActivity( m_IdealActivity );
  2064. SetSequence( m_nIdealSequence );
  2065. SendViewModelAnim( m_nIdealSequence );
  2066. }
  2067. //Set the next time the weapon will idle
  2068. SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() );
  2069. return true;
  2070. }
  2071. //-----------------------------------------------------------------------------
  2072. // Returns information about the various control panels
  2073. //-----------------------------------------------------------------------------
  2074. void CBaseCombatWeapon::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName )
  2075. {
  2076. pPanelName = NULL;
  2077. }
  2078. //-----------------------------------------------------------------------------
  2079. // Returns information about the various control panels
  2080. //-----------------------------------------------------------------------------
  2081. void CBaseCombatWeapon::GetControlPanelClassName( int nPanelIndex, const char *&pPanelName )
  2082. {
  2083. pPanelName = "vgui_screen";
  2084. }
  2085. //-----------------------------------------------------------------------------
  2086. // Locking a weapon is an exclusive action. If you lock a weapon, that means
  2087. // you are preventing others from doing so for themselves.
  2088. //-----------------------------------------------------------------------------
  2089. void CBaseCombatWeapon::Lock( float lockTime, CBaseEntity *pLocker )
  2090. {
  2091. m_flUnlockTime = gpGlobals->curtime + lockTime;
  2092. m_hLocker.Set( pLocker );
  2093. }
  2094. //-----------------------------------------------------------------------------
  2095. // If I'm still locked for a period of time, tell everyone except the person
  2096. // that locked me that I'm not available.
  2097. //-----------------------------------------------------------------------------
  2098. bool CBaseCombatWeapon::IsLocked( CBaseEntity *pAsker )
  2099. {
  2100. return ( m_flUnlockTime > gpGlobals->curtime && m_hLocker != pAsker );
  2101. }
  2102. //-----------------------------------------------------------------------------
  2103. // Purpose:
  2104. // Input :
  2105. // Output :
  2106. //-----------------------------------------------------------------------------
  2107. Activity CBaseCombatWeapon::ActivityOverride( Activity baseAct, bool *pRequired )
  2108. {
  2109. int actCount = 0;
  2110. acttable_t *pTable = ActivityList( actCount );
  2111. for ( int i = 0; i < actCount; i++ )
  2112. {
  2113. const acttable_t& act = pTable[i];
  2114. if ( baseAct == act.baseAct )
  2115. {
  2116. if (pRequired)
  2117. {
  2118. *pRequired = act.required;
  2119. }
  2120. return (Activity)act.weaponAct;
  2121. }
  2122. }
  2123. return baseAct;
  2124. }
  2125. //-----------------------------------------------------------------------------
  2126. // Purpose:
  2127. //-----------------------------------------------------------------------------
  2128. void CBaseCombatWeapon::PoseParameterOverride( bool bReset )
  2129. {
  2130. CBaseCombatCharacter *pOwner = GetOwner();
  2131. if ( !pOwner )
  2132. return;
  2133. CStudioHdr *pStudioHdr = pOwner->GetModelPtr();
  2134. if ( !pStudioHdr )
  2135. return;
  2136. int iCount = 0;
  2137. poseparamtable_t *pPoseParamList = PoseParamList( iCount );
  2138. if ( pPoseParamList )
  2139. {
  2140. for ( int i=0; i<iCount; ++i )
  2141. {
  2142. int iPoseParam = pOwner->LookupPoseParameter( pStudioHdr, pPoseParamList[i].pszName );
  2143. if ( iPoseParam != -1 )
  2144. pOwner->SetPoseParameter( iPoseParam, bReset ? 0 : pPoseParamList[i].flValue );
  2145. }
  2146. }
  2147. }
  2148. //-----------------------------------------------------------------------------
  2149. // Purpose:
  2150. //-----------------------------------------------------------------------------
  2151. CDmgAccumulator::CDmgAccumulator( void )
  2152. {
  2153. #ifdef GAME_DLL
  2154. SetDefLessFunc( m_TargetsDmgInfo );
  2155. #endif // GAME_DLL
  2156. m_bActive = false;
  2157. }
  2158. //-----------------------------------------------------------------------------
  2159. // Purpose:
  2160. //-----------------------------------------------------------------------------
  2161. CDmgAccumulator::~CDmgAccumulator()
  2162. {
  2163. // Did a weapon get deleted while aggregating CTakeDamageInfo events?
  2164. Assert( !m_bActive );
  2165. }
  2166. #ifdef GAME_DLL
  2167. //-----------------------------------------------------------------------------
  2168. // Collect trace attacks for weapons that fire multiple bullets per attack that also penetrate
  2169. //-----------------------------------------------------------------------------
  2170. void CDmgAccumulator::AccumulateMultiDamage( const CTakeDamageInfo &info, CBaseEntity *pEntity )
  2171. {
  2172. if ( !pEntity )
  2173. return;
  2174. Assert( m_bActive );
  2175. #if defined( GAME_DLL )
  2176. int iIndex = m_TargetsDmgInfo.Find( pEntity->entindex() );
  2177. if ( iIndex == m_TargetsDmgInfo.InvalidIndex() )
  2178. {
  2179. m_TargetsDmgInfo.Insert( pEntity->entindex(), info );
  2180. }
  2181. else
  2182. {
  2183. CTakeDamageInfo *pInfo = &m_TargetsDmgInfo[iIndex];
  2184. if ( pInfo )
  2185. {
  2186. // Update
  2187. m_TargetsDmgInfo[iIndex].AddDamageType( info.GetDamageType() );
  2188. m_TargetsDmgInfo[iIndex].SetDamage( pInfo->GetDamage() + info.GetDamage() );
  2189. m_TargetsDmgInfo[iIndex].SetDamageForce( pInfo->GetDamageForce() + info.GetDamageForce() );
  2190. m_TargetsDmgInfo[iIndex].SetDamagePosition( info.GetDamagePosition() );
  2191. m_TargetsDmgInfo[iIndex].SetReportedPosition( info.GetReportedPosition() );
  2192. m_TargetsDmgInfo[iIndex].SetMaxDamage( MAX( pInfo->GetMaxDamage(), info.GetDamage() ) );
  2193. m_TargetsDmgInfo[iIndex].SetAmmoType( info.GetAmmoType() );
  2194. }
  2195. }
  2196. #endif // GAME_DLL
  2197. }
  2198. //-----------------------------------------------------------------------------
  2199. // Purpose: Send aggregate info
  2200. //-----------------------------------------------------------------------------
  2201. void CDmgAccumulator::Process( void )
  2202. {
  2203. FOR_EACH_MAP( m_TargetsDmgInfo, i )
  2204. {
  2205. CBaseEntity *pEntity = UTIL_EntityByIndex( m_TargetsDmgInfo.Key( i ) );
  2206. if ( pEntity )
  2207. {
  2208. AddMultiDamage( m_TargetsDmgInfo[i], pEntity );
  2209. }
  2210. }
  2211. m_bActive = false;
  2212. m_TargetsDmgInfo.Purge();
  2213. }
  2214. #endif // GAME_DLL
  2215. #if defined( CLIENT_DLL )
  2216. BEGIN_PREDICTION_DATA( CBaseCombatWeapon )
  2217. DEFINE_PRED_FIELD( m_nNextThinkTick, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  2218. // Networked
  2219. DEFINE_PRED_FIELD( m_hOwner, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
  2220. // DEFINE_FIELD( m_hWeaponFileInfo, FIELD_SHORT ),
  2221. DEFINE_PRED_FIELD( m_iState, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  2222. DEFINE_PRED_FIELD( m_iViewModelIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ),
  2223. DEFINE_PRED_FIELD( m_iWorldModelIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ),
  2224. DEFINE_PRED_FIELD_TOL( m_flNextPrimaryAttack, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
  2225. DEFINE_PRED_FIELD_TOL( m_flNextSecondaryAttack, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
  2226. DEFINE_PRED_FIELD_TOL( m_flTimeWeaponIdle, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
  2227. DEFINE_PRED_FIELD( m_iPrimaryAmmoType, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  2228. DEFINE_PRED_FIELD( m_iSecondaryAmmoType, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  2229. DEFINE_PRED_FIELD( m_iClip1, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  2230. DEFINE_PRED_FIELD( m_iClip2, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  2231. DEFINE_PRED_FIELD( m_nViewModelIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  2232. // Not networked
  2233. DEFINE_PRED_FIELD( m_flTimeWeaponIdle, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
  2234. DEFINE_FIELD( m_bInReload, FIELD_BOOLEAN ),
  2235. DEFINE_FIELD( m_bFireOnEmpty, FIELD_BOOLEAN ),
  2236. DEFINE_FIELD( m_bFiringWholeClip, FIELD_BOOLEAN ),
  2237. DEFINE_FIELD( m_flNextEmptySoundTime, FIELD_FLOAT ),
  2238. DEFINE_FIELD( m_Activity, FIELD_INTEGER ),
  2239. DEFINE_FIELD( m_fFireDuration, FIELD_FLOAT ),
  2240. DEFINE_FIELD( m_iszName, FIELD_INTEGER ),
  2241. DEFINE_FIELD( m_bFiresUnderwater, FIELD_BOOLEAN ),
  2242. DEFINE_FIELD( m_bAltFiresUnderwater, FIELD_BOOLEAN ),
  2243. DEFINE_FIELD( m_fMinRange1, FIELD_FLOAT ),
  2244. DEFINE_FIELD( m_fMinRange2, FIELD_FLOAT ),
  2245. DEFINE_FIELD( m_fMaxRange1, FIELD_FLOAT ),
  2246. DEFINE_FIELD( m_fMaxRange2, FIELD_FLOAT ),
  2247. DEFINE_FIELD( m_bReloadsSingly, FIELD_BOOLEAN ),
  2248. DEFINE_FIELD( m_bRemoveable, FIELD_BOOLEAN ),
  2249. DEFINE_FIELD( m_iPrimaryAmmoCount, FIELD_INTEGER ),
  2250. DEFINE_FIELD( m_iSecondaryAmmoCount, FIELD_INTEGER ),
  2251. //DEFINE_PHYSPTR( m_pConstraint ),
  2252. // DEFINE_FIELD( m_iOldState, FIELD_INTEGER ),
  2253. // DEFINE_FIELD( m_bJustRestored, FIELD_BOOLEAN ),
  2254. // DEFINE_FIELD( m_OnPlayerPickup, COutputEvent ),
  2255. // DEFINE_FIELD( m_pConstraint, FIELD_INTEGER ),
  2256. END_PREDICTION_DATA()
  2257. #endif // ! CLIENT_DLL
  2258. // Special hack since we're aliasing the name C_BaseCombatWeapon with a macro on the client
  2259. IMPLEMENT_NETWORKCLASS_ALIASED( BaseCombatWeapon, DT_BaseCombatWeapon )
  2260. #if !defined( CLIENT_DLL )
  2261. //-----------------------------------------------------------------------------
  2262. // Purpose: Save Data for Base Weapon object
  2263. //-----------------------------------------------------------------------------//
  2264. BEGIN_DATADESC( CBaseCombatWeapon )
  2265. DEFINE_FIELD( m_flNextPrimaryAttack, FIELD_TIME ),
  2266. DEFINE_FIELD( m_flNextSecondaryAttack, FIELD_TIME ),
  2267. DEFINE_FIELD( m_flTimeWeaponIdle, FIELD_TIME ),
  2268. DEFINE_FIELD( m_bInReload, FIELD_BOOLEAN ),
  2269. DEFINE_FIELD( m_bFireOnEmpty, FIELD_BOOLEAN ),
  2270. DEFINE_FIELD( m_hOwner, FIELD_EHANDLE ),
  2271. DEFINE_FIELD( m_iState, FIELD_INTEGER ),
  2272. DEFINE_FIELD( m_iszName, FIELD_STRING ),
  2273. DEFINE_FIELD( m_iPrimaryAmmoType, FIELD_INTEGER ),
  2274. DEFINE_FIELD( m_iSecondaryAmmoType, FIELD_INTEGER ),
  2275. DEFINE_FIELD( m_iClip1, FIELD_INTEGER ),
  2276. DEFINE_FIELD( m_iClip2, FIELD_INTEGER ),
  2277. DEFINE_FIELD( m_bFiresUnderwater, FIELD_BOOLEAN ),
  2278. DEFINE_FIELD( m_bAltFiresUnderwater, FIELD_BOOLEAN ),
  2279. DEFINE_FIELD( m_fMinRange1, FIELD_FLOAT ),
  2280. DEFINE_FIELD( m_fMinRange2, FIELD_FLOAT ),
  2281. DEFINE_FIELD( m_fMaxRange1, FIELD_FLOAT ),
  2282. DEFINE_FIELD( m_fMaxRange2, FIELD_FLOAT ),
  2283. DEFINE_FIELD( m_iPrimaryAmmoCount, FIELD_INTEGER ),
  2284. DEFINE_FIELD( m_iSecondaryAmmoCount, FIELD_INTEGER ),
  2285. DEFINE_FIELD( m_nViewModelIndex, FIELD_INTEGER ),
  2286. // don't save these, init to 0 and regenerate
  2287. // DEFINE_FIELD( m_flNextEmptySoundTime, FIELD_TIME ),
  2288. // DEFINE_FIELD( m_Activity, FIELD_INTEGER ),
  2289. DEFINE_FIELD( m_nIdealSequence, FIELD_INTEGER ),
  2290. DEFINE_FIELD( m_IdealActivity, FIELD_INTEGER ),
  2291. DEFINE_FIELD( m_fFireDuration, FIELD_FLOAT ),
  2292. DEFINE_FIELD( m_bReloadsSingly, FIELD_BOOLEAN ),
  2293. DEFINE_FIELD( m_iSubType, FIELD_INTEGER ),
  2294. DEFINE_FIELD( m_bRemoveable, FIELD_BOOLEAN ),
  2295. DEFINE_FIELD( m_flUnlockTime, FIELD_TIME ),
  2296. DEFINE_FIELD( m_hLocker, FIELD_EHANDLE ),
  2297. // DEFINE_FIELD( m_iViewModelIndex, FIELD_INTEGER ),
  2298. // DEFINE_FIELD( m_iWorldModelIndex, FIELD_INTEGER ),
  2299. // DEFINE_FIELD( m_hWeaponFileInfo, ???? ),
  2300. DEFINE_PHYSPTR( m_pConstraint ),
  2301. DEFINE_FIELD( m_iReloadHudHintCount, FIELD_INTEGER ),
  2302. DEFINE_FIELD( m_iAltFireHudHintCount, FIELD_INTEGER ),
  2303. DEFINE_FIELD( m_bReloadHudHintDisplayed, FIELD_BOOLEAN ),
  2304. DEFINE_FIELD( m_bAltFireHudHintDisplayed, FIELD_BOOLEAN ),
  2305. DEFINE_FIELD( m_flHudHintPollTime, FIELD_TIME ),
  2306. DEFINE_FIELD( m_flHudHintMinDisplayTime, FIELD_TIME ),
  2307. // Just to quiet classcheck.. this field exists only on the client
  2308. // DEFINE_FIELD( m_iOldState, FIELD_INTEGER ),
  2309. // DEFINE_FIELD( m_bJustRestored, FIELD_BOOLEAN ),
  2310. // Function pointers
  2311. DEFINE_ENTITYFUNC( DefaultTouch ),
  2312. DEFINE_THINKFUNC( FallThink ),
  2313. DEFINE_THINKFUNC( Materialize ),
  2314. DEFINE_THINKFUNC( AttemptToMaterialize ),
  2315. DEFINE_THINKFUNC( DestroyItem ),
  2316. DEFINE_THINKFUNC( SetPickupTouch ),
  2317. DEFINE_THINKFUNC( HideThink ),
  2318. DEFINE_INPUTFUNC( FIELD_VOID, "HideWeapon", InputHideWeapon ),
  2319. // Outputs
  2320. DEFINE_OUTPUT( m_OnPlayerUse, "OnPlayerUse"),
  2321. DEFINE_OUTPUT( m_OnPlayerPickup, "OnPlayerPickup"),
  2322. DEFINE_OUTPUT( m_OnNPCPickup, "OnNPCPickup"),
  2323. DEFINE_OUTPUT( m_OnCacheInteraction, "OnCacheInteraction" ),
  2324. END_DATADESC()
  2325. //-----------------------------------------------------------------------------
  2326. // Purpose: Only send to local player if this weapon is the active weapon
  2327. // Input : *pStruct -
  2328. // *pVarData -
  2329. // *pRecipients -
  2330. // objectID -
  2331. // Output : void*
  2332. //-----------------------------------------------------------------------------
  2333. void* SendProxy_SendActiveLocalWeaponDataTable( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID )
  2334. {
  2335. // Get the weapon entity
  2336. CBaseCombatWeapon *pWeapon = (CBaseCombatWeapon*)pVarData;
  2337. if ( pWeapon )
  2338. {
  2339. // Only send this chunk of data to the player carrying this weapon
  2340. CBasePlayer *pPlayer = ToBasePlayer( pWeapon->GetOwner() );
  2341. if ( pPlayer /*&& pPlayer->GetActiveWeapon() == pWeapon*/ )
  2342. {
  2343. pRecipients->SetOnly( pPlayer->GetClientIndex() );
  2344. return (void*)pVarData;
  2345. }
  2346. }
  2347. return NULL;
  2348. }
  2349. REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_SendActiveLocalWeaponDataTable );
  2350. //-----------------------------------------------------------------------------
  2351. // Purpose: Only send the LocalWeaponData to the player carrying the weapon
  2352. //-----------------------------------------------------------------------------
  2353. void* SendProxy_SendLocalWeaponDataTable( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID )
  2354. {
  2355. // Get the weapon entity
  2356. CBaseCombatWeapon *pWeapon = (CBaseCombatWeapon*)pVarData;
  2357. if ( pWeapon )
  2358. {
  2359. // Only send this chunk of data to the player carrying this weapon
  2360. CBasePlayer *pPlayer = ToBasePlayer( pWeapon->GetOwner() );
  2361. if ( pPlayer )
  2362. {
  2363. pRecipients->SetOnly( pPlayer->GetClientIndex() );
  2364. return (void*)pVarData;
  2365. }
  2366. }
  2367. return NULL;
  2368. }
  2369. REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_SendLocalWeaponDataTable );
  2370. //-----------------------------------------------------------------------------
  2371. // Purpose: Only send to non-local players
  2372. //-----------------------------------------------------------------------------
  2373. void* SendProxy_SendNonLocalWeaponDataTable( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID )
  2374. {
  2375. pRecipients->SetAllRecipients();
  2376. CBaseCombatWeapon *pWeapon = (CBaseCombatWeapon*)pVarData;
  2377. if ( pWeapon )
  2378. {
  2379. CBasePlayer *pPlayer = ToBasePlayer( pWeapon->GetOwner() );
  2380. if ( pPlayer )
  2381. {
  2382. pRecipients->ClearRecipient( pPlayer->GetClientIndex() );
  2383. return ( void * )pVarData;
  2384. }
  2385. }
  2386. return NULL;
  2387. }
  2388. REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_SendNonLocalWeaponDataTable );
  2389. #else
  2390. void CBaseCombatWeapon::RecvProxy_WeaponState( const CRecvProxyData *pData, void *pStruct, void *pOut )
  2391. {
  2392. CBaseCombatWeapon *pWeapon = (CBaseCombatWeapon*)pStruct;
  2393. pWeapon->m_iState = pData->m_Value.m_Int;
  2394. pWeapon->UpdateVisibility();
  2395. }
  2396. #endif
  2397. #if PREDICTION_ERROR_CHECK_LEVEL > 1
  2398. #define SendPropTime SendPropFloat
  2399. #define RecvPropTime RecvPropFloat
  2400. #endif
  2401. //-----------------------------------------------------------------------------
  2402. // Purpose: Propagation data for weapons. Only sent when a player's holding it.
  2403. //-----------------------------------------------------------------------------
  2404. BEGIN_NETWORK_TABLE_NOBASE( CBaseCombatWeapon, DT_LocalActiveWeaponData )
  2405. #if !defined( CLIENT_DLL )
  2406. SendPropTime( SENDINFO( m_flNextPrimaryAttack ) ),
  2407. SendPropTime( SENDINFO( m_flNextSecondaryAttack ) ),
  2408. SendPropInt( SENDINFO( m_nNextThinkTick ) ),
  2409. SendPropTime( SENDINFO( m_flTimeWeaponIdle ) ),
  2410. #if defined( TF_DLL )
  2411. SendPropExclude( "DT_AnimTimeMustBeFirst" , "m_flAnimTime" ),
  2412. #endif
  2413. #else
  2414. RecvPropTime( RECVINFO( m_flNextPrimaryAttack ) ),
  2415. RecvPropTime( RECVINFO( m_flNextSecondaryAttack ) ),
  2416. RecvPropInt( RECVINFO( m_nNextThinkTick ) ),
  2417. RecvPropTime( RECVINFO( m_flTimeWeaponIdle ) ),
  2418. #endif
  2419. END_NETWORK_TABLE()
  2420. //-----------------------------------------------------------------------------
  2421. // Purpose: Propagation data for weapons. Only sent when a player's holding it.
  2422. //-----------------------------------------------------------------------------
  2423. BEGIN_NETWORK_TABLE_NOBASE( CBaseCombatWeapon, DT_LocalWeaponData )
  2424. #if !defined( CLIENT_DLL )
  2425. SendPropIntWithMinusOneFlag( SENDINFO(m_iClip1 ), 8 ),
  2426. SendPropIntWithMinusOneFlag( SENDINFO(m_iClip2 ), 8 ),
  2427. SendPropInt( SENDINFO(m_iPrimaryAmmoType ), 8 ),
  2428. SendPropInt( SENDINFO(m_iSecondaryAmmoType ), 8 ),
  2429. SendPropInt( SENDINFO( m_nViewModelIndex ), VIEWMODEL_INDEX_BITS, SPROP_UNSIGNED ),
  2430. SendPropInt( SENDINFO( m_bFlipViewModel ) ),
  2431. #if defined( TF_DLL )
  2432. SendPropExclude( "DT_AnimTimeMustBeFirst" , "m_flAnimTime" ),
  2433. #endif
  2434. #else
  2435. RecvPropIntWithMinusOneFlag( RECVINFO(m_iClip1 )),
  2436. RecvPropIntWithMinusOneFlag( RECVINFO(m_iClip2 )),
  2437. RecvPropInt( RECVINFO(m_iPrimaryAmmoType )),
  2438. RecvPropInt( RECVINFO(m_iSecondaryAmmoType )),
  2439. RecvPropInt( RECVINFO( m_nViewModelIndex ) ),
  2440. RecvPropBool( RECVINFO( m_bFlipViewModel ) ),
  2441. #endif
  2442. END_NETWORK_TABLE()
  2443. BEGIN_NETWORK_TABLE(CBaseCombatWeapon, DT_BaseCombatWeapon)
  2444. #if !defined( CLIENT_DLL )
  2445. SendPropDataTable("LocalWeaponData", 0, &REFERENCE_SEND_TABLE(DT_LocalWeaponData), SendProxy_SendLocalWeaponDataTable ),
  2446. SendPropDataTable("LocalActiveWeaponData", 0, &REFERENCE_SEND_TABLE(DT_LocalActiveWeaponData), SendProxy_SendActiveLocalWeaponDataTable ),
  2447. SendPropModelIndex( SENDINFO(m_iViewModelIndex) ),
  2448. SendPropModelIndex( SENDINFO(m_iWorldModelIndex) ),
  2449. SendPropInt( SENDINFO(m_iState ), 8, SPROP_UNSIGNED ),
  2450. SendPropEHandle( SENDINFO(m_hOwner) ),
  2451. #else
  2452. RecvPropDataTable("LocalWeaponData", 0, 0, &REFERENCE_RECV_TABLE(DT_LocalWeaponData)),
  2453. RecvPropDataTable("LocalActiveWeaponData", 0, 0, &REFERENCE_RECV_TABLE(DT_LocalActiveWeaponData)),
  2454. RecvPropInt( RECVINFO(m_iViewModelIndex)),
  2455. RecvPropInt( RECVINFO(m_iWorldModelIndex)),
  2456. RecvPropInt( RECVINFO(m_iState), 0, &CBaseCombatWeapon::RecvProxy_WeaponState ),
  2457. RecvPropEHandle( RECVINFO(m_hOwner ) ),
  2458. #endif
  2459. END_NETWORK_TABLE()