Counter Strike : Global Offensive Source Code
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.

3532 lines
104 KiB

  1. //========= Copyright � 1996-2005, 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 "tier0/vprof.h"
  15. #include "collisionutils.h"
  16. #include "econ_entity.h"
  17. #include "econ_item_view.h"
  18. #if !defined( CLIENT_DLL )
  19. // Game DLL Headers
  20. #include "soundent.h"
  21. #include "eventqueue.h"
  22. #include "fmtstr.h"
  23. #include "gameweaponmanager.h"
  24. #else
  25. #include "input.h"
  26. #include "hltvreplaysystem.h"
  27. #include "model_types.h"
  28. #endif
  29. // memdbgon must be the last include file in a .cpp file!!!
  30. #include "tier0/memdbgon.h"
  31. // The minimum time a hud hint for a weapon should be on screen. If we switch away before
  32. // this, then teh hud hint counter will be deremented so the hint will be shown again, as
  33. // if it had never been seen. The total display time for a hud hint is specified in client
  34. // script HudAnimations.txt (which I can't read here).
  35. #define MIN_HUDHINT_DISPLAY_TIME 7.0f
  36. #define HIDEWEAPON_THINK_CONTEXT "BaseCombatWeapon_HideThink"
  37. extern bool UTIL_ItemCanBeTouchedByPlayer( CBaseEntity *pItem, CBasePlayer *pPlayer );
  38. #if defined( CLIENT_DLL )
  39. void RecvProxy_EffectFlagsWeaponWorldmodel( const CRecvProxyData *pData, void *pStruct, void *pOut );
  40. extern void RecvProxy_IntToMoveParent( const CRecvProxyData *pData, void *pStruct, void *pOut );
  41. void RecvProxy_WeaponWorldmodel( const CRecvProxyData *pData, void *pStruct, void *pOut );
  42. void RecvProxy_WeaponWorldmodelCosmetics( const CRecvProxyData *pData, void *pStruct, void *pOut );
  43. #endif
  44. IMPLEMENT_NETWORKCLASS_ALIASED( BaseWeaponWorldModel, DT_BaseWeaponWorldModel )
  45. LINK_ENTITY_TO_CLASS_ALIASED( weaponworldmodel, BaseWeaponWorldModel );
  46. BEGIN_NETWORK_TABLE_NOBASE(CBaseWeaponWorldModel, DT_BaseWeaponWorldModel)
  47. #if !defined( CLIENT_DLL )
  48. SendPropModelIndex(SENDINFO(m_nModelIndex)),
  49. SendPropInt (SENDINFO(m_nBody), ANIMATION_BODY_BITS ), // increased to 32 bits to support number of bits equal to number of bodygroups
  50. SendPropInt (SENDINFO(m_fEffects), EF_MAX_BITS, SPROP_UNSIGNED),
  51. SendPropEHandle (SENDINFO_NAME(m_hMoveParent, moveparent)),
  52. SendPropEHandle (SENDINFO(m_hCombatWeaponParent)),
  53. #else
  54. RecvPropInt (RECVINFO(m_nModelIndex), 0, RecvProxy_WeaponWorldmodel),
  55. RecvPropInt (RECVINFO(m_nBody)),
  56. RecvPropInt (RECVINFO(m_fEffects), 0, RecvProxy_EffectFlagsWeaponWorldmodel),
  57. RecvPropInt (RECVINFO_NAME(m_hNetworkMoveParent, moveparent), 0, RecvProxy_IntToMoveParent),
  58. RecvPropEHandle (RECVINFO(m_hCombatWeaponParent), RecvProxy_WeaponWorldmodelCosmetics),
  59. #endif
  60. END_NETWORK_TABLE()
  61. #ifdef CLIENT_DLL
  62. BEGIN_PREDICTION_DATA( CBaseWeaponWorldModel )
  63. DEFINE_PRED_FIELD( m_nModelIndex, FIELD_SHORT, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ),
  64. DEFINE_PRED_FIELD( m_nBody, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  65. DEFINE_PRED_FIELD( m_fEffects, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_OVERRIDE ),
  66. DEFINE_FIELD( m_hCombatWeaponParent, FIELD_EHANDLE ),
  67. END_PREDICTION_DATA()
  68. void RecvProxy_EffectFlagsWeaponWorldmodel( const CRecvProxyData *pData, void *pStruct, void *pOut )
  69. {
  70. CBaseWeaponWorldModel *pWeaponWorldModel = (CBaseWeaponWorldModel *) pStruct;
  71. if ( pWeaponWorldModel )
  72. {
  73. if ( pWeaponWorldModel->GetEffects() != pData->m_Value.m_Int )
  74. {
  75. pWeaponWorldModel->SetEffects( pData->m_Value.m_Int );
  76. }
  77. }
  78. }
  79. void RecvProxy_WeaponWorldmodel( const CRecvProxyData *pData, void *pStruct, void *pOut )
  80. {
  81. CBaseWeaponWorldModel *model = (CBaseWeaponWorldModel *)pStruct;
  82. if ( model )
  83. {
  84. int nOldModelIndex = model->GetModelIndex();
  85. MDLCACHE_CRITICAL_SECTION();
  86. model->SetModelByIndex( pData->m_Value.m_Int );
  87. if ( nOldModelIndex != model->GetModelIndex() )
  88. model->ResetCachedBoneIndices();
  89. }
  90. }
  91. void RecvProxy_WeaponWorldmodelCosmetics( const CRecvProxyData *pData, void *pStruct, void *pOut )
  92. {
  93. RecvProxy_IntToEHandle( pData, pStruct, pOut );
  94. CBaseWeaponWorldModel *pWeaponWorldModel = (CBaseWeaponWorldModel *) pStruct;
  95. if ( pWeaponWorldModel )
  96. {
  97. pWeaponWorldModel->ApplyCustomMaterialsAndStickers();
  98. }
  99. }
  100. int CBaseWeaponWorldModel::DrawModel( int flags, const RenderableInstance_t &instance )
  101. {
  102. if ( (flags & STUDIO_RENDER) && ( IsEffectActive(EF_NODRAW) || !ShouldDraw() ) )
  103. return 0;
  104. return BaseClass::DrawModel( flags, instance );
  105. }
  106. void CBaseWeaponWorldModel::OnDataChanged( DataUpdateType_t type )
  107. {
  108. // make sure world model custom materials and stickers are up-to-date
  109. CBaseCombatWeapon *pWeaponParent = m_hCombatWeaponParent->Get();
  110. if ( pWeaponParent )
  111. {
  112. if ( IsVisible() && GetCustomMaterialCount() != pWeaponParent->GetCustomMaterialCount() )
  113. {
  114. ApplyCustomMaterialsAndStickers();
  115. }
  116. // extra sticker application check
  117. if ( IsVisible() && ShouldDraw() && !m_bStickersApplied && pWeaponParent )
  118. {
  119. m_bStickersApplied = true;
  120. pWeaponParent->ApplyThirdPersonStickers( this );
  121. }
  122. if ( !pWeaponParent->GetOwner() )
  123. {
  124. pWeaponParent->ApplyThirdPersonStickers( pWeaponParent );
  125. }
  126. }
  127. if ( type == DATA_UPDATE_CREATED )
  128. {
  129. ResetCachedBoneIndices();
  130. }
  131. BaseClass::OnDataChanged( type );
  132. ValidateParent();
  133. SetAllowFastPath( false ); // so it can control exactly when to render
  134. UpdateVisibility();
  135. }
  136. float *CBaseWeaponWorldModel::GetRenderClipPlane( void )
  137. {
  138. // world model weapons inherit their clip planes from their move parents when the parent is a player
  139. if ( GetMoveParent() && GetMoveParent()->IsPlayer() )
  140. {
  141. return GetMoveParent()->GetRenderClipPlane();
  142. }
  143. else
  144. {
  145. return NULL;
  146. }
  147. }
  148. bool CBaseWeaponWorldModel::SetupBones( matrix3x4a_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
  149. {
  150. if ( GetMoveParent() && GetMoveParent()->IsPlayer() )
  151. {
  152. if ( boneMask == BONE_USED_BY_ATTACHMENT )
  153. {
  154. // fixme: weapons set up more bones than necessary when asking for attachments. Particles request attachment positions
  155. // often and cause computation down more bone chains than they actually need. There's perf to be gained here.
  156. // For now, requests for attachments only are allowed through.
  157. }
  158. else
  159. {
  160. // This is a hacky special case. A better way to do this would be to add more granularity in content bone flags.
  161. // CBaseWeaponWorldModels have a bunch of bones that drive the player's bones when the player sets up,
  162. // BUT they are not necessary to compute when rendering the weapon itself.
  163. // So the gross assumption being made here is that if we don't want an attachment (like for particle system
  164. // attaching or sticker projection, etc) then we actually only care about vertex-weighted bones. And this
  165. // saves a bunch of bone setup we'll never use, like on the weapons 'legs' bones, which never drive the
  166. // mechanical parts of the gun.
  167. boneMask = BONE_USED_BY_VERTEX_LOD0;
  168. }
  169. return BaseClass::SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime );
  170. }
  171. //AssertMsgOnce( false, "Attempted to SetupBones on a dropped weapon world model with no player parent!\n" );
  172. return false;
  173. }
  174. #else
  175. BEGIN_DATADESC( CBaseWeaponWorldModel )
  176. END_DATADESC()
  177. #endif
  178. void CBaseWeaponWorldModel::ValidateParent( void )
  179. {
  180. CBaseCombatWeapon *pWeaponParent = m_hCombatWeaponParent->Get();
  181. if ( pWeaponParent )
  182. {
  183. CBaseEntity *pIdealParent = pWeaponParent;
  184. CBaseCombatCharacter *pWeaponParentOwner = pWeaponParent->GetOwner();
  185. if ( pWeaponParentOwner && pWeaponParentOwner->IsPlayer() )
  186. pIdealParent = pWeaponParentOwner;
  187. if ( GetMoveParent() != pIdealParent ) // reconnect ourselves if the parent is wrong
  188. FollowEntity( pIdealParent, pIdealParent->IsPlayer() );
  189. AddEffects( EF_BONEMERGE_FASTCULL );
  190. }
  191. }
  192. CBaseWeaponWorldModel::CBaseWeaponWorldModel( void )
  193. {
  194. m_nHoldsPlayerAnims = WEAPON_PLAYER_ANIMS_UNKNOWN;
  195. m_nLeftHandAttachBoneIndex = -1;
  196. m_nRightHandAttachBoneIndex = -1;
  197. m_nMuzzleAttachIndex = -1;
  198. m_nMuzzleBoneIndex = -1;
  199. #ifdef CLIENT_DLL
  200. m_bStickersApplied = false;
  201. m_bMaintainSequenceTransitions = false; // disabled for perf - world model weapons do not transition their sequences
  202. RenderWithViewModels( false );
  203. SetUseParentLightingOrigin( true ); // don't set up bones when asked for lighting origin, just use parent's one (in this case player)
  204. #endif
  205. }
  206. CBaseWeaponWorldModel::~CBaseWeaponWorldModel( void )
  207. {
  208. }
  209. bool CBaseWeaponWorldModel::HasDormantOwner( void )
  210. {
  211. CBaseCombatWeapon *pWeaponParent = m_hCombatWeaponParent->Get();
  212. if ( pWeaponParent && pWeaponParent->GetOwner() && pWeaponParent->GetOwner()->IsDormant() )
  213. return true;
  214. return false;
  215. }
  216. void CBaseWeaponWorldModel::ResetCachedBoneIndices( void )
  217. {
  218. m_nLeftHandAttachBoneIndex = -1;
  219. m_nRightHandAttachBoneIndex = -1;
  220. }
  221. int CBaseWeaponWorldModel::GetLeftHandAttachBoneIndex( void )
  222. {
  223. if ( m_nLeftHandAttachBoneIndex == -1 )
  224. m_nLeftHandAttachBoneIndex = LookupBone( "left_hand_attach" );
  225. return m_nLeftHandAttachBoneIndex;
  226. }
  227. int CBaseWeaponWorldModel::GetRightHandAttachBoneIndex( void )
  228. {
  229. if ( m_nRightHandAttachBoneIndex == -1 )
  230. m_nRightHandAttachBoneIndex = LookupBone( "weapon_hand_R" );
  231. return m_nRightHandAttachBoneIndex;
  232. }
  233. int CBaseWeaponWorldModel::GetMuzzleAttachIndex( void )
  234. {
  235. if ( m_nMuzzleAttachIndex == -1 )
  236. m_nMuzzleAttachIndex = LookupAttachment( "muzzle_flash" );
  237. return m_nMuzzleAttachIndex;
  238. }
  239. int CBaseWeaponWorldModel::GetMuzzleBoneIndex( void )
  240. {
  241. if ( m_nMuzzleBoneIndex == -1 )
  242. m_nMuzzleBoneIndex = LookupBone( "weapon_muzzle" );
  243. return m_nMuzzleBoneIndex;
  244. }
  245. void CBaseWeaponWorldModel::SetOwningWeapon( CBaseCombatWeapon *pWeaponParent )
  246. {
  247. if ( !pWeaponParent )
  248. return;
  249. if ( m_hCombatWeaponParent->Get() != pWeaponParent )
  250. {
  251. // assume the parent weapon world model
  252. SetModel( pWeaponParent->GetWorldModel() );
  253. ResetCachedBoneIndices();
  254. // determine if this world model holds player animations
  255. HoldsPlayerAnimations();
  256. //keep a handle to this weapon
  257. m_hCombatWeaponParent.Set( pWeaponParent );
  258. //follow our parent asap
  259. FollowEntity( pWeaponParent, false );
  260. //set initial visibility
  261. CBaseCombatCharacter *pWeaponParentOwner = pWeaponParent->GetOwner();
  262. bool bInitialVisible = ( pWeaponParentOwner && pWeaponParentOwner->GetActiveWeapon() == pWeaponParent );
  263. ShowWorldModel( bInitialVisible );
  264. #ifndef CLIENT_DLL
  265. // whatever the mag state, we want it unhidden now
  266. SetBodygroupPreset( "show_mag" );
  267. #endif
  268. }
  269. ValidateParent();
  270. }
  271. void CBaseWeaponWorldModel::ShowWorldModel( bool bVisible )
  272. {
  273. ValidateParent();
  274. if ( bVisible )
  275. {
  276. RemoveEffects( EF_NODRAW );
  277. }
  278. else
  279. {
  280. AddEffects( EF_NODRAW );
  281. }
  282. }
  283. bool CBaseWeaponWorldModel::HoldsPlayerAnimations( void )
  284. {
  285. // TODO: weapon world models need a better way to claim they hold player animations
  286. if ( m_nHoldsPlayerAnims == WEAPON_PLAYER_ANIMS_UNKNOWN )
  287. {
  288. m_nHoldsPlayerAnims = ( GetModelPtr() && GetModelPtr()->GetNumSeq() > 2 ) ? WEAPON_PLAYER_ANIMS_AVAILABLE : WEAPON_PLAYER_ANIMS_NOT_AVAILABLE;
  289. }
  290. return ( m_nHoldsPlayerAnims == WEAPON_PLAYER_ANIMS_AVAILABLE );
  291. }
  292. #ifndef CLIENT_DLL
  293. void CBaseWeaponWorldModel::HandleAnimEvent( animevent_t *pEvent )
  294. {
  295. int nEvent = pEvent->Event();
  296. if ( nEvent == AE_CL_EJECT_MAG )
  297. {
  298. SetBodygroupPreset( "hide_mag" );
  299. }
  300. else if ( nEvent == AE_CL_EJECT_MAG_UNHIDE )
  301. {
  302. SetBodygroupPreset( "show_mag" );
  303. }
  304. }
  305. #endif
  306. #ifdef CLIENT_DLL
  307. void CBaseWeaponWorldModel::FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options )
  308. {
  309. if ( event == AE_CL_EJECT_MAG )
  310. {
  311. CBaseCombatWeapon *pWeaponParent = m_hCombatWeaponParent->Get();
  312. if ( pWeaponParent )
  313. {
  314. C_BaseCombatCharacter *pPlayer = pWeaponParent->GetOwner();
  315. if ( pPlayer )
  316. {
  317. pPlayer->DropPhysicsMag( options );
  318. }
  319. }
  320. }
  321. }
  322. bool CBaseWeaponWorldModel::ShouldDraw( void )
  323. {
  324. CBaseCombatWeapon *pWeaponParent = m_hCombatWeaponParent->Get();
  325. if ( !pWeaponParent )
  326. return false; // don't draw if we don't have a parent weapon
  327. CBaseCombatCharacter *pWeaponParentOwner = pWeaponParent->GetOwner();
  328. if ( !pWeaponParentOwner || !pWeaponParentOwner->IsPlayer() || !pWeaponParent->GetOwner()->ShouldDraw() || HasDormantOwner() )
  329. return false; // don't draw if our parent weapon is unheld, or held by a dormant or invisible player
  330. // <sergiy> 2016/01/05 - there was a bug here, where (at least in replay, possibly in other spectator type situations) the weapon owner would substitute his active weapon with the active weapon of the observer target.
  331. // This is seemingly done to simplify the code that deals with local player's active weapon (e.g. ironsight and effects rendering): GetLocalPlayer()->GetActiveWeapon(), when in the In-Eye mode, will always return the weapon to use for local effects (the one in the hands of the observer target).
  332. CBaseCombatWeapon *pParentWeaponPlayerPrimary;
  333. #if defined( CLIENT_DLL )
  334. if ( g_HltvReplaySystem.GetHltvReplayDelay() )
  335. pParentWeaponPlayerPrimary = pWeaponParentOwner->CBaseCombatCharacter::GetActiveWeapon(); // the ACTUAL active weapon, not a substitute from another player
  336. else
  337. #endif
  338. pParentWeaponPlayerPrimary = pWeaponParentOwner->GetActiveWeapon();
  339. if ( !pParentWeaponPlayerPrimary || pParentWeaponPlayerPrimary != pWeaponParent )
  340. {
  341. return false; // don't draw if it's not the primary weapon
  342. }
  343. C_BasePlayer * player = C_BasePlayer::GetLocalPlayer();
  344. if ( player &&
  345. player->IsObserver() &&
  346. player->GetObserverMode() == OBS_MODE_IN_EYE &&
  347. player->GetObserverTarget() == pWeaponParentOwner &&
  348. !input->CAM_IsThirdPerson() &&
  349. player->GetObserverInterpState() != 1 )
  350. {
  351. return false; // don't draw if we're spectating the parent player owner in first-person
  352. }
  353. if ( IsEffectActive(EF_NODRAW) && ( pWeaponParent->m_flNextPrimaryAttack > gpGlobals->curtime || pWeaponParent->m_flNextSecondaryAttack > gpGlobals->curtime ) )
  354. {
  355. return false; // only respect nodraw if we also can't fire (presumably deploying)
  356. }
  357. return true;
  358. }
  359. void CBaseWeaponWorldModel::ApplyCustomMaterialsAndStickers( void )
  360. {
  361. CBaseCombatWeapon *pWeaponParent = m_hCombatWeaponParent->Get();
  362. if ( !pWeaponParent )
  363. return;
  364. // inherit custom materials
  365. if ( pWeaponParent->GetCustomMaterialCount() != GetCustomMaterialCount() )
  366. {
  367. ClearCustomMaterials();
  368. for ( int i = 0; i < pWeaponParent->GetCustomMaterialCount(); i++ )
  369. {
  370. SetCustomMaterial( pWeaponParent->GetCustomMaterial( i ), i );
  371. }
  372. SetAllowFastPath( false );
  373. }
  374. // apply stickers
  375. pWeaponParent->ApplyThirdPersonStickers( this );
  376. }
  377. #else
  378. int CBaseWeaponWorldModel::ShouldTransmit( const CCheckTransmitInfo *pInfo )
  379. {
  380. CBaseCombatWeapon *pWeaponParent = m_hCombatWeaponParent->Get();
  381. if ( pWeaponParent )
  382. {
  383. CBaseEntity *pIdealParent = pWeaponParent;
  384. CBaseCombatCharacter *pWeaponParentOwner = pWeaponParent->GetOwner();
  385. if ( pWeaponParentOwner && pWeaponParentOwner->IsPlayer() )
  386. pIdealParent = pWeaponParentOwner;
  387. return pIdealParent->ShouldTransmit( pInfo );
  388. }
  389. else
  390. {
  391. // invalid situation
  392. Assert( !"Base Weapon World Model has no weapon parent" );
  393. return FL_EDICT_ALWAYS;
  394. }
  395. }
  396. int CBaseWeaponWorldModel::UpdateTransmitState( void )
  397. {
  398. return SetTransmitState( FL_EDICT_FULLCHECK );
  399. }
  400. #endif
  401. #ifndef CLIENT_DLL
  402. void CBaseCombatWeapon::ShowWeaponWorldModel( bool bVisible )
  403. {
  404. CBaseWeaponWorldModel *pWeaponWorldModel = GetWeaponWorldModel();
  405. if ( pWeaponWorldModel )
  406. {
  407. pWeaponWorldModel->SetOwningWeapon( this );
  408. pWeaponWorldModel->ShowWorldModel( bVisible );
  409. }
  410. }
  411. // create a new world model if it doesn't exist
  412. CBaseWeaponWorldModel* CBaseCombatWeapon::CreateWeaponWorldModel( void )
  413. {
  414. MDLCACHE_CRITICAL_SECTION();
  415. if ( !GetWeaponWorldModel() )
  416. {
  417. CBaseWeaponWorldModel *pWorldModel = dynamic_cast <CBaseWeaponWorldModel*> ( CreateEntityByName( "weaponworldmodel" ) );
  418. Assert( pWorldModel );
  419. pWorldModel->SetOwningWeapon( this );
  420. m_hWeaponWorldModel.Set( pWorldModel );
  421. return pWorldModel;
  422. }
  423. else
  424. {
  425. return GetWeaponWorldModel();
  426. }
  427. }
  428. #else
  429. void CBaseCombatWeapon::UpdateVisibility( void )
  430. {
  431. CBaseWeaponWorldModel *pWeaponWorldModel = GetWeaponWorldModel();
  432. if ( pWeaponWorldModel )
  433. {
  434. pWeaponWorldModel->UpdateVisibility();
  435. }
  436. BaseClass::UpdateVisibility();
  437. }
  438. #endif
  439. CBaseCombatWeapon::CBaseCombatWeapon()
  440. {
  441. // Constructor must call this
  442. // CONSTRUCT_PREDICTABLE( CBaseCombatWeapon );
  443. // Some default values. There should be set in the particular weapon classes
  444. m_fMinRange1 = 65;
  445. m_fMinRange2 = 65;
  446. m_fMaxRange1 = 1024;
  447. m_fMaxRange2 = 1024;
  448. m_bReloadsSingly = false;
  449. // Defaults to zero
  450. m_nViewModelIndex = 0;
  451. m_bFlipViewModel = false;
  452. #if defined( CLIENT_DLL )
  453. m_iState = WEAPON_NOT_CARRIED;
  454. m_iOldState = m_iState;
  455. m_iClip1 = -1;
  456. m_iClip2 = -1;
  457. m_iPrimaryAmmoType = -1;
  458. m_iSecondaryAmmoType = -1;
  459. m_flWeaponTauntHideTimeout = 0.0f;
  460. #endif
  461. m_iWeaponModule = MODULAR_BODYGROUPS_DEFAULT_NONE_SET;
  462. #if !defined( CLIENT_DLL )
  463. m_pConstraint = NULL;
  464. OnBaseCombatWeaponCreated( this );
  465. #endif
  466. m_hWeaponFileInfo = GetInvalidWeaponInfoHandle();
  467. #if defined( TF_DLL )
  468. UseClientSideAnimation();
  469. #endif
  470. m_WeaponModelClassification = WEAPON_MODEL_IS_UNCLASSIFIED;
  471. }
  472. //-----------------------------------------------------------------------------
  473. // Purpose: Destructor
  474. //-----------------------------------------------------------------------------
  475. CBaseCombatWeapon::~CBaseCombatWeapon( void )
  476. {
  477. #if !defined( CLIENT_DLL )
  478. //Remove our constraint, if we have one
  479. if ( m_pConstraint != NULL )
  480. {
  481. physenv->DestroyConstraint( m_pConstraint );
  482. m_pConstraint = NULL;
  483. }
  484. OnBaseCombatWeaponDestroyed( this );
  485. #endif
  486. CBaseWeaponWorldModel *pWeaponWorldModel = GetWeaponWorldModel();
  487. if ( pWeaponWorldModel )
  488. {
  489. UTIL_Remove( pWeaponWorldModel );
  490. }
  491. // Even though CBaseAnimating calls 'InvalidateMdlCache', it will *NOT* call
  492. // the virtual CBaseCombatWeapon override. This is because the CBaseAnimating
  493. // destructor is called AFTER the CBaseCombatWeapon destructor has run, by
  494. // which time the object has reverted to the base type, so derived virtual
  495. // overrides are no longer in effect.
  496. // This matters because otherwise m_pWorldStudioHdr will leak memory!
  497. InvalidateMdlCache();
  498. }
  499. void CBaseCombatWeapon::Activate( void )
  500. {
  501. BaseClass::Activate();
  502. #ifndef CLIENT_DLL
  503. if ( GetOwnerEntity() )
  504. return;
  505. if ( g_pGameRules->IsAllowedToSpawn( this ) == false )
  506. {
  507. UTIL_Remove( this );
  508. return;
  509. }
  510. #endif
  511. }
  512. void CBaseCombatWeapon::GiveDefaultAmmo( void )
  513. {
  514. // If I use clips, set my clips to the default
  515. if ( UsesClipsForAmmo1() )
  516. {
  517. m_iClip1 = GetDefaultClip1();
  518. }
  519. else
  520. {
  521. SetPrimaryAmmoCount( GetDefaultClip1() );
  522. m_iClip1 = WEAPON_NOCLIP;
  523. }
  524. if ( UsesClipsForAmmo2() )
  525. {
  526. m_iClip2 = GetDefaultClip2();
  527. }
  528. else
  529. {
  530. SetSecondaryAmmoCount( GetDefaultClip2() );
  531. m_iClip2 = WEAPON_NOCLIP;
  532. }
  533. }
  534. //-----------------------------------------------------------------------------
  535. // Purpose: Set mode to world model and start falling to the ground
  536. //-----------------------------------------------------------------------------
  537. void CBaseCombatWeapon::Spawn( void )
  538. {
  539. Precache();
  540. SetSolid( SOLID_BBOX );
  541. m_flNextEmptySoundTime = 0.0f;
  542. // Weapons won't show up in trace calls if they are being carried...
  543. RemoveEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
  544. m_iState = WEAPON_NOT_CARRIED;
  545. SetGlobalFadeScale( 0.0f );
  546. // Assume
  547. m_nViewModelIndex = 0;
  548. m_iWeaponModule = MODULAR_BODYGROUPS_DEFAULT_NONE_SET;
  549. GiveDefaultAmmo();
  550. VerifyAndSetContextSensitiveWeaponModel();
  551. #if !defined( CLIENT_DLL )
  552. if ( GetWpnData().szAIAddOn[ 0 ] != '\0' )
  553. {
  554. SetAIAddOn( AllocPooledString( GetWpnData().szAIAddOn ) );
  555. }
  556. if( IsGameConsole() )
  557. {
  558. AddEffects( EF_ITEM_BLINK );
  559. }
  560. FallInit();
  561. SetCollisionGroup( COLLISION_GROUP_WEAPON );
  562. m_takedamage = DAMAGE_EVENTS_ONLY;
  563. SetBlocksLOS( false );
  564. // Default to non-removeable, because we don't want the
  565. // game_weapon_manager entity to remove weapons that have
  566. // been hand-placed by level designers. We only want to remove
  567. // weapons that have been dropped by NPC's.
  568. SetRemoveable( false );
  569. //SetWeaponModules();
  570. CreateWeaponWorldModel();
  571. #endif
  572. // Bloat the box for player pickup
  573. CollisionProp()->UseTriggerBounds( true, 36 );
  574. // Use more efficient bbox culling on the client. Otherwise, it'll setup bones for most
  575. // characters even when they're not in the frustum.
  576. AddEffects( EF_BONEMERGE_FASTCULL );
  577. m_iReloadHudHintCount = 0;
  578. m_iAltFireHudHintCount = 0;
  579. m_flHudHintMinDisplayTime = 0;
  580. m_iReloadActivityIndex = ACT_VM_RELOAD;
  581. m_iNumEmptyAttacks = 0;
  582. m_iPrimaryReserveAmmoCount = 0; // amount of reserve ammo. This used to be on the player ( m_iAmmo ) but we're moving it to the weapon.
  583. m_iSecondaryReserveAmmoCount = 0; // amount of reserve ammo. This used to be on the player ( m_iAmmo ) but we're moving it to the weapon.
  584. #ifndef CLIENT_DLL
  585. m_flLastTimeInAir = 0;
  586. #endif
  587. }
  588. #ifndef CLIENT_DLL
  589. void CBaseCombatWeapon::PhysicsSimulate( void )
  590. {
  591. BaseClass::PhysicsSimulate();
  592. // remember the last time we were flying through the air
  593. if ( GetOwner() == NULL && !(GetFlags() & FL_ONGROUND) )
  594. {
  595. m_flLastTimeInAir = gpGlobals->curtime;
  596. }
  597. }
  598. #endif
  599. //-----------------------------------------------------------------------------
  600. // Purpose: get this game's encryption key for decoding weapon kv files
  601. // Output : virtual const unsigned char
  602. //-----------------------------------------------------------------------------
  603. const unsigned char *CBaseCombatWeapon::GetEncryptionKey( void )
  604. {
  605. return g_pGameRules->GetEncryptionKey();
  606. }
  607. //-----------------------------------------------------------------------------
  608. // Purpose:
  609. //-----------------------------------------------------------------------------
  610. void CBaseCombatWeapon::Precache( void )
  611. {
  612. #if defined( CLIENT_DLL )
  613. Assert( Q_strlen( GetClassname() ) > 0 );
  614. // Msg( "Client got %s\n", GetClassname() );
  615. #endif
  616. m_iPrimaryAmmoType = m_iSecondaryAmmoType = -1;
  617. // Add this weapon to the weapon registry, and get our index into it
  618. // Get weapon data from script file
  619. m_hWeaponFileInfo = LookupWeaponInfoSlot( GetClassname() );
  620. if ( m_hWeaponFileInfo != GetInvalidWeaponInfoHandle() )
  621. {
  622. // Get the ammo indexes for the ammo's specified in the data file
  623. if ( GetWpnData().GetPrimaryAmmo( GetEconItemView() )[0] )
  624. {
  625. m_iPrimaryAmmoType = GetAmmoDef()->Index( GetWpnData().GetPrimaryAmmo( GetEconItemView() ) );
  626. if (m_iPrimaryAmmoType == -1)
  627. {
  628. Msg("ERROR: Weapon (%s) using undefined primary ammo type (%s)\n",GetClassname(), GetWpnData().GetPrimaryAmmo( GetEconItemView() ) );
  629. }
  630. }
  631. if ( GetWpnData().szAmmo2[0] )
  632. {
  633. m_iSecondaryAmmoType = GetAmmoDef()->Index( GetWpnData().szAmmo2 );
  634. if (m_iSecondaryAmmoType == -1)
  635. {
  636. Msg("ERROR: Weapon (%s) using undefined secondary ammo type (%s)\n",GetClassname(),GetWpnData().szAmmo2);
  637. }
  638. }
  639. #if defined( CLIENT_DLL )
  640. gWR.LoadWeaponSprites( GetWeaponFileInfoHandle() );
  641. #endif
  642. // Precache models (preload to avoid hitch)
  643. m_iViewModelIndex = 0;
  644. m_iWorldModelIndex = 0;
  645. m_iWorldDroppedModelIndex = 0;
  646. m_iWeaponModule = MODULAR_BODYGROUPS_DEFAULT_NONE_SET;
  647. if ( GetViewModel() && GetViewModel()[0] )
  648. {
  649. g_pMDLCache->DisableVCollideLoad();
  650. m_iViewModelIndex = CBaseEntity::PrecacheModel( GetViewModel() );
  651. g_pMDLCache->EnableVCollideLoad();
  652. }
  653. if ( GetWorldModel() && GetWorldModel()[0] )
  654. {
  655. m_iWorldModelIndex = CBaseEntity::PrecacheModel( GetWorldModel() );
  656. }
  657. if ( GetWorldDroppedModel() && GetWorldDroppedModel()[0] )
  658. {
  659. m_iWorldDroppedModelIndex = CBaseEntity::PrecacheModel( GetWorldDroppedModel() );
  660. }
  661. // Precache sounds, too
  662. for ( int i = 0; i < NUM_SHOOT_SOUND_TYPES; ++i )
  663. {
  664. const char *shootsound = GetShootSound( i );
  665. if ( shootsound && shootsound[0] )
  666. {
  667. CBaseEntity::PrecacheScriptSound( shootsound );
  668. }
  669. }
  670. }
  671. else
  672. {
  673. // Couldn't read data file, remove myself
  674. Warning( "Error reading weapon data file for: %s\n", GetClassname() );
  675. // Remove( ); //don't remove, this gets released soon!
  676. }
  677. const char *pszTracerName = GetTracerType();
  678. if ( pszTracerName && pszTracerName[0] )
  679. {
  680. PrecacheEffect( pszTracerName );
  681. }
  682. PrecacheEffect( "ParticleTracer" );
  683. PrecacheParticleSystem( "weapon_tracers" );
  684. }
  685. //-----------------------------------------------------------------------------
  686. // Purpose: Get my data in the file weapon info array
  687. //-----------------------------------------------------------------------------
  688. const FileWeaponInfo_t &CBaseCombatWeapon::GetWpnData( void ) const
  689. {
  690. return *GetFileWeaponInfoFromHandle( m_hWeaponFileInfo );
  691. }
  692. //-----------------------------------------------------------------------------
  693. // Purpose:
  694. //-----------------------------------------------------------------------------
  695. const char *CBaseCombatWeapon::GetViewModel( int /*viewmodelindex = 0 -- this is ignored in the base class here*/ ) const
  696. {
  697. return GetWpnData().GetViewModel( GetEconItemView(), (
  698. ( GetOwner() != NULL && GetOwner()->IsPlayer() ) ? GetOwner()->GetTeamNumber() : 0
  699. ) );
  700. }
  701. //-----------------------------------------------------------------------------
  702. // Purpose:
  703. //-----------------------------------------------------------------------------
  704. const char *CBaseCombatWeapon::GetWorldModel( void ) const
  705. {
  706. return GetWpnData().GetWorldModel( GetEconItemView(), (
  707. ( GetOwner() != NULL && GetOwner()->IsPlayer() ) ? GetOwner()->GetTeamNumber() : 0
  708. ) );
  709. }
  710. const char *CBaseCombatWeapon::GetWorldDroppedModel( void ) const
  711. {
  712. const char *szWorldDroppedModel = GetWpnData().GetWorldDroppedModel( GetEconItemView(), (
  713. ( GetOwner() != NULL && GetOwner()->IsPlayer() ) ? GetOwner()->GetTeamNumber() : 0
  714. ) );
  715. // world dropped model path is optional, but always built. Make sure the model exists before returning it.
  716. if ( szWorldDroppedModel )
  717. {
  718. MDLHandle_t modelHandle = g_pMDLCache->FindMDL( szWorldDroppedModel );
  719. if ( !g_pMDLCache->IsErrorModel( modelHandle ) )
  720. return szWorldDroppedModel;
  721. }
  722. return GetWorldModel();
  723. }
  724. //-----------------------------------------------------------------------------
  725. // Purpose:
  726. //-----------------------------------------------------------------------------
  727. const char *CBaseCombatWeapon::GetAnimPrefix( void ) const
  728. {
  729. return GetWpnData().szAnimationPrefix;
  730. }
  731. //-----------------------------------------------------------------------------
  732. // Purpose:
  733. // Output : char const
  734. //-----------------------------------------------------------------------------
  735. const char *CBaseCombatWeapon::GetPrintName( void ) const
  736. {
  737. if ( GetEconItemView( ) )
  738. return GetEconItemView( )->GetItemDefinition()->GetItemBaseName();
  739. else
  740. return GetWpnData().szPrintName;
  741. }
  742. //-----------------------------------------------------------------------------
  743. // Purpose:
  744. //-----------------------------------------------------------------------------
  745. bool CBaseCombatWeapon::UsesClipsForAmmo1( void ) const
  746. {
  747. return ( GetMaxClip1() != WEAPON_NOCLIP );
  748. }
  749. bool CBaseCombatWeapon::IsMeleeWeapon() const
  750. {
  751. return GetWpnData().m_bMeleeWeapon;
  752. }
  753. //-----------------------------------------------------------------------------
  754. // Purpose:
  755. //-----------------------------------------------------------------------------
  756. bool CBaseCombatWeapon::UsesClipsForAmmo2( void ) const
  757. {
  758. return ( GetMaxClip2() != WEAPON_NOCLIP );
  759. }
  760. //-----------------------------------------------------------------------------
  761. // Purpose:
  762. //-----------------------------------------------------------------------------
  763. int CBaseCombatWeapon::GetWeight( void ) const
  764. {
  765. return GetWpnData().iWeight;
  766. }
  767. //-----------------------------------------------------------------------------
  768. // Purpose: Whether this weapon can be autoswitched to when the player runs out
  769. // of ammo in their current weapon or they pick this weapon up.
  770. //-----------------------------------------------------------------------------
  771. bool CBaseCombatWeapon::AllowsAutoSwitchTo( void ) const
  772. {
  773. return GetWpnData().bAutoSwitchTo;
  774. }
  775. //-----------------------------------------------------------------------------
  776. // Purpose: Whether this weapon can be autoswitched away from when the player
  777. // runs out of ammo in this weapon or picks up another weapon or ammo.
  778. //-----------------------------------------------------------------------------
  779. bool CBaseCombatWeapon::AllowsAutoSwitchFrom( void ) const
  780. {
  781. return GetWpnData().bAutoSwitchFrom;
  782. }
  783. //-----------------------------------------------------------------------------
  784. // Purpose:
  785. //-----------------------------------------------------------------------------
  786. int CBaseCombatWeapon::GetWeaponFlags( void ) const
  787. {
  788. return GetWpnData().iFlags;
  789. }
  790. //-----------------------------------------------------------------------------
  791. // Purpose:
  792. //-----------------------------------------------------------------------------
  793. int CBaseCombatWeapon::GetSlot( void ) const
  794. {
  795. return GetWpnData().iSlot;
  796. }
  797. //-----------------------------------------------------------------------------
  798. // Purpose:
  799. //-----------------------------------------------------------------------------
  800. int CBaseCombatWeapon::GetPosition( void ) const
  801. {
  802. return GetWpnData().iPosition;
  803. }
  804. //-----------------------------------------------------------------------------
  805. // Purpose:
  806. //-----------------------------------------------------------------------------
  807. const char *CBaseCombatWeapon::GetName( void ) const
  808. {
  809. return GetWpnData().szClassName;
  810. }
  811. //-----------------------------------------------------------------------------
  812. // Purpose:
  813. //-----------------------------------------------------------------------------
  814. CHudTexture const *CBaseCombatWeapon::GetSpriteActive( void ) const
  815. {
  816. return GetWpnData().iconActive;
  817. }
  818. //-----------------------------------------------------------------------------
  819. // Purpose:
  820. //-----------------------------------------------------------------------------
  821. CHudTexture const *CBaseCombatWeapon::GetSpriteInactive( void ) const
  822. {
  823. return GetWpnData().iconInactive;
  824. }
  825. //-----------------------------------------------------------------------------
  826. // Purpose:
  827. //-----------------------------------------------------------------------------
  828. CHudTexture const *CBaseCombatWeapon::GetSpriteAmmo( void ) const
  829. {
  830. return GetWpnData().iconAmmo;
  831. }
  832. //-----------------------------------------------------------------------------
  833. // Purpose:
  834. //-----------------------------------------------------------------------------
  835. CHudTexture const *CBaseCombatWeapon::GetSpriteAmmo2( void ) const
  836. {
  837. return GetWpnData().iconAmmo2;
  838. }
  839. //-----------------------------------------------------------------------------
  840. // Purpose:
  841. //-----------------------------------------------------------------------------
  842. CHudTexture const *CBaseCombatWeapon::GetSpriteCrosshair( void ) const
  843. {
  844. return GetWpnData().iconCrosshair;
  845. }
  846. //-----------------------------------------------------------------------------
  847. // Purpose:
  848. //-----------------------------------------------------------------------------
  849. CHudTexture const *CBaseCombatWeapon::GetSpriteAutoaim( void ) const
  850. {
  851. return GetWpnData().iconAutoaim;
  852. }
  853. //-----------------------------------------------------------------------------
  854. // Purpose:
  855. //-----------------------------------------------------------------------------
  856. CHudTexture const *CBaseCombatWeapon::GetSpriteZoomedCrosshair( void ) const
  857. {
  858. return GetWpnData().iconZoomedCrosshair;
  859. }
  860. //-----------------------------------------------------------------------------
  861. // Purpose:
  862. //-----------------------------------------------------------------------------
  863. CHudTexture const *CBaseCombatWeapon::GetSpriteZoomedAutoaim( void ) const
  864. {
  865. return GetWpnData().iconZoomedAutoaim;
  866. }
  867. //-----------------------------------------------------------------------------
  868. // Purpose:
  869. //-----------------------------------------------------------------------------
  870. const char *CBaseCombatWeapon::GetShootSound( int iIndex ) const
  871. {
  872. return GetWpnData().aShootSounds[ iIndex ];
  873. }
  874. //-----------------------------------------------------------------------------
  875. // Purpose:
  876. //-----------------------------------------------------------------------------
  877. int CBaseCombatWeapon::GetRumbleEffect() const
  878. {
  879. return GetWpnData().iRumbleEffect;
  880. }
  881. //-----------------------------------------------------------------------------
  882. // Purpose:
  883. //-----------------------------------------------------------------------------
  884. CBaseCombatCharacter *CBaseCombatWeapon::GetOwner() const
  885. {
  886. return ToBaseCombatCharacter( m_hOwner.Get() );
  887. }
  888. //-----------------------------------------------------------------------------
  889. // Purpose:
  890. // Input : BaseCombatCharacter -
  891. //-----------------------------------------------------------------------------
  892. void CBaseCombatWeapon::SetOwner( CBaseCombatCharacter *owner )
  893. {
  894. if ( !owner )
  895. {
  896. #ifndef CLIENT_DLL
  897. // Make sure the weapon updates its state when it's removed from the player
  898. // We have to force an active state change, because it's being dropped and won't call UpdateClientData()
  899. m_iState = WEAPON_NOT_CARRIED;
  900. #endif
  901. // make sure we clear out our HideThink if we have one pending
  902. SetContextThink( NULL, 0, HIDEWEAPON_THINK_CONTEXT );
  903. }
  904. m_hOwner = owner;
  905. #ifndef CLIENT_DLL
  906. DispatchUpdateTransmitState();
  907. #else
  908. UpdateVisibility();
  909. #endif
  910. }
  911. //-----------------------------------------------------------------------------
  912. // Purpose: Return false if this weapon won't let the player switch away from it
  913. //-----------------------------------------------------------------------------
  914. bool CBaseCombatWeapon::IsAllowedToSwitch( void )
  915. {
  916. return true;
  917. }
  918. //-----------------------------------------------------------------------------
  919. // Purpose: Return true if this weapon can be selected via the weapon selection
  920. //-----------------------------------------------------------------------------
  921. bool CBaseCombatWeapon::CanBeSelected( void )
  922. {
  923. if ( !VisibleInWeaponSelection() )
  924. return false;
  925. return HasAmmo();
  926. }
  927. //-----------------------------------------------------------------------------
  928. // Purpose: Return true if this weapon has some ammo
  929. //-----------------------------------------------------------------------------
  930. bool CBaseCombatWeapon::HasAmmo( void )
  931. {
  932. // Weapons with no ammo types can always be selected
  933. if ( m_iPrimaryAmmoType == -1 && m_iSecondaryAmmoType == -1 )
  934. return true;
  935. if ( GetWeaponFlags() & ITEM_FLAG_SELECTONEMPTY )
  936. return true;
  937. CBasePlayer *player = ToBasePlayer( GetOwner() );
  938. if ( !player )
  939. return false;
  940. return ( m_iClip1 > 0 || GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) || m_iClip2 > 0 || GetReserveAmmoCount( AMMO_POSITION_SECONDARY ) );
  941. }
  942. //-----------------------------------------------------------------------------
  943. // Purpose: Return true if this weapon should be seen, and hence be selectable, in the weapon selection
  944. //-----------------------------------------------------------------------------
  945. bool CBaseCombatWeapon::VisibleInWeaponSelection( void )
  946. {
  947. return true;
  948. }
  949. //-----------------------------------------------------------------------------
  950. // Purpose:
  951. // Output : Returns true on success, false on failure.
  952. //-----------------------------------------------------------------------------
  953. bool CBaseCombatWeapon::HasWeaponIdleTimeElapsed( void )
  954. {
  955. if ( gpGlobals->curtime > m_flTimeWeaponIdle )
  956. return true;
  957. return false;
  958. }
  959. //-----------------------------------------------------------------------------
  960. // Purpose:
  961. // Input : time -
  962. //-----------------------------------------------------------------------------
  963. void CBaseCombatWeapon::SetWeaponIdleTime( float time )
  964. {
  965. m_flTimeWeaponIdle = time;
  966. }
  967. //-----------------------------------------------------------------------------
  968. // Purpose:
  969. // Output : float
  970. //-----------------------------------------------------------------------------
  971. float CBaseCombatWeapon::GetWeaponIdleTime( void )
  972. {
  973. return m_flTimeWeaponIdle;
  974. }
  975. //-----------------------------------------------------------------------------
  976. // Purpose: Drop/throw the weapon with the given velocity.
  977. //-----------------------------------------------------------------------------
  978. void CBaseCombatWeapon::Drop( const Vector &vecVelocity )
  979. {
  980. #if !defined( CLIENT_DLL )
  981. // Once somebody drops a gun, it's fair game for removal when/if
  982. // a game_weapon_manager does a cleanup on surplus weapons in the
  983. // world.
  984. SetRemoveable( true );
  985. WeaponManager_AmmoMod( this );
  986. //If it was dropped then there's no need to respawn it.
  987. AddSpawnFlags( SF_NORESPAWN );
  988. StopAnimation();
  989. StopFollowingEntity( );
  990. SetMoveType( MOVETYPE_FLYGRAVITY );
  991. // clear follow stuff, setup for collision
  992. SetGravity(1.0);
  993. m_iState = WEAPON_NOT_CARRIED;
  994. RemoveEffects( EF_NODRAW );
  995. FallInit();
  996. SetGroundEntity( NULL );
  997. SetThink( &CBaseCombatWeapon::SetPickupTouch );
  998. SetTouch(NULL);
  999. if( hl2_episodic.GetBool() )
  1000. {
  1001. RemoveSpawnFlags( SF_WEAPON_NO_PLAYER_PICKUP );
  1002. }
  1003. IPhysicsObject *pObj = VPhysicsGetObject();
  1004. if ( pObj != NULL )
  1005. {
  1006. AngularImpulse angImp( 200, 200, 200 );
  1007. pObj->AddVelocity( &vecVelocity, &angImp );
  1008. }
  1009. else
  1010. {
  1011. SetAbsVelocity( vecVelocity );
  1012. }
  1013. CBaseEntity *pOwner = GetOwnerEntity();
  1014. SetNextThink( gpGlobals->curtime + 1.0f );
  1015. SetOwnerEntity( NULL );
  1016. SetOwner( NULL );
  1017. // If we're not allowing to spawn due to the gamerules,
  1018. // remove myself when I'm dropped by an NPC.
  1019. if ( pOwner && pOwner->IsNPC() )
  1020. {
  1021. if ( g_pGameRules->IsAllowedToSpawn( this ) == false )
  1022. {
  1023. UTIL_Remove( this );
  1024. return;
  1025. }
  1026. }
  1027. #endif
  1028. }
  1029. //-----------------------------------------------------------------------------
  1030. // Purpose:
  1031. // Input : *pPicker -
  1032. //-----------------------------------------------------------------------------
  1033. void CBaseCombatWeapon::OnPickedUp( CBaseCombatCharacter *pNewOwner )
  1034. {
  1035. #if !defined( CLIENT_DLL )
  1036. RemoveEffects( EF_ITEM_BLINK );
  1037. if( pNewOwner->IsPlayer() )
  1038. {
  1039. m_OnPlayerPickup.FireOutput(pNewOwner, this);
  1040. // Robin: We don't want to delete weapons the player has picked up, so
  1041. // clear the name of the weapon. This prevents wildcards that are meant
  1042. // to find NPCs finding weapons dropped by the NPCs as well.
  1043. SetName( NULL_STRING );
  1044. }
  1045. else
  1046. {
  1047. m_OnNPCPickup.FireOutput(pNewOwner, this);
  1048. }
  1049. // Someone picked me up, so make it so that I can't be removed.
  1050. SetRemoveable( false );
  1051. #endif
  1052. }
  1053. //-----------------------------------------------------------------------------
  1054. // Purpose:
  1055. // Input : &vecTracerSrc -
  1056. // &tr -
  1057. // iTracerType -
  1058. //-----------------------------------------------------------------------------
  1059. void CBaseCombatWeapon::MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType )
  1060. {
  1061. CBaseEntity *pOwner = GetOwner();
  1062. if ( pOwner == NULL )
  1063. {
  1064. BaseClass::MakeTracer( vecTracerSrc, tr, iTracerType );
  1065. return;
  1066. }
  1067. const char *pszTracerName = GetTracerType();
  1068. if ( !pszTracerName )
  1069. {
  1070. pszTracerName = "weapon_tracers";
  1071. }
  1072. Vector vNewSrc = vecTracerSrc;
  1073. int iEntIndex = pOwner->entindex();
  1074. if ( g_pGameRules->IsMultiplayer() )
  1075. {
  1076. iEntIndex = entindex();
  1077. #ifdef CLIENT_DLL
  1078. C_BasePlayer *player = ToBasePlayer( pOwner );
  1079. if ( C_BasePlayer::IsLocalPlayer( player ) )
  1080. {
  1081. CBaseEntity *vm = player->GetViewModel();
  1082. if ( vm )
  1083. {
  1084. iEntIndex = vm->entindex();
  1085. }
  1086. }
  1087. #endif
  1088. }
  1089. int iAttachment = GetTracerAttachment();
  1090. UTIL_ParticleTracer( pszTracerName, vNewSrc, tr.endpos, iEntIndex, iAttachment, true );
  1091. }
  1092. void CBaseCombatWeapon::GiveTo( CBaseEntity *pOther )
  1093. {
  1094. DefaultTouch( pOther );
  1095. }
  1096. //-----------------------------------------------------------------------------
  1097. // Purpose: Default Touch function for player picking up a weapon (not AI)
  1098. // Input : pOther - the entity that touched me
  1099. // Output :
  1100. //-----------------------------------------------------------------------------
  1101. void CBaseCombatWeapon::DefaultTouch( CBaseEntity *pOther )
  1102. {
  1103. #if !defined( CLIENT_DLL )
  1104. // Can't pick up dissolving weapons
  1105. if ( IsDissolving() )
  1106. return;
  1107. // if it's not a player, ignore
  1108. CBasePlayer *pPlayer = ToBasePlayer(pOther);
  1109. if ( !pPlayer )
  1110. return;
  1111. if( UTIL_ItemCanBeTouchedByPlayer(this, pPlayer) )
  1112. {
  1113. // This makes sure the player could potentially take the object
  1114. // before firing the cache interaction output. That doesn't mean
  1115. // the player WILL end up taking the object, but cache interactions
  1116. // are fired as soon as you prove you have found the object, not
  1117. // when you finally acquire it.
  1118. m_OnCacheInteraction.FireOutput( pOther, this );
  1119. }
  1120. if( HasSpawnFlags(SF_WEAPON_NO_PLAYER_PICKUP) )
  1121. return;
  1122. if (pPlayer->BumpWeapon(this))
  1123. {
  1124. OnPickedUp( pPlayer );
  1125. }
  1126. #endif
  1127. }
  1128. //---------------------------------------------------------
  1129. // It's OK for base classes to override this completely
  1130. // without calling up. (sjb)
  1131. //---------------------------------------------------------
  1132. bool CBaseCombatWeapon::ShouldDisplayAltFireHUDHint()
  1133. {
  1134. if( m_iAltFireHudHintCount >= WEAPON_RELOAD_HUD_HINT_COUNT )
  1135. return false;
  1136. if( UsesSecondaryAmmo() && HasSecondaryAmmo() )
  1137. {
  1138. return true;
  1139. }
  1140. if( !UsesSecondaryAmmo() && HasPrimaryAmmo() )
  1141. {
  1142. return true;
  1143. }
  1144. return false;
  1145. }
  1146. //-----------------------------------------------------------------------------
  1147. //-----------------------------------------------------------------------------
  1148. void CBaseCombatWeapon::DisplayAltFireHudHint()
  1149. {
  1150. #if !defined( CLIENT_DLL )
  1151. CFmtStr hint;
  1152. hint.sprintf( "#valve_hint_alt_%s", GetClassname() );
  1153. UTIL_HudHintText( GetOwner(), hint.Access() );
  1154. m_iAltFireHudHintCount++;
  1155. m_bAltFireHudHintDisplayed = true;
  1156. m_flHudHintMinDisplayTime = gpGlobals->curtime + MIN_HUDHINT_DISPLAY_TIME;
  1157. #endif//CLIENT_DLL
  1158. }
  1159. //-----------------------------------------------------------------------------
  1160. //-----------------------------------------------------------------------------
  1161. void CBaseCombatWeapon::RescindAltFireHudHint()
  1162. {
  1163. #if !defined( CLIENT_DLL )
  1164. Assert(m_bAltFireHudHintDisplayed);
  1165. UTIL_HudHintText( GetOwner(), "" );
  1166. --m_iAltFireHudHintCount;
  1167. m_bAltFireHudHintDisplayed = false;
  1168. #endif//CLIENT_DLL
  1169. }
  1170. //-----------------------------------------------------------------------------
  1171. //-----------------------------------------------------------------------------
  1172. bool CBaseCombatWeapon::ShouldDisplayReloadHUDHint()
  1173. {
  1174. if( m_iReloadHudHintCount >= WEAPON_RELOAD_HUD_HINT_COUNT )
  1175. return false;
  1176. CBaseCombatCharacter *pOwner = GetOwner();
  1177. if( pOwner != NULL && pOwner->IsPlayer() && UsesClipsForAmmo1() && m_iClip1 < (GetMaxClip1() / 2) )
  1178. {
  1179. // I'm owned by a player, I use clips, I have less then half a clip loaded. Now, does the player have more ammo?
  1180. if ( GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) > 0 )
  1181. return true;
  1182. }
  1183. return false;
  1184. }
  1185. //-----------------------------------------------------------------------------
  1186. //-----------------------------------------------------------------------------
  1187. void CBaseCombatWeapon::DisplayReloadHudHint()
  1188. {
  1189. #if !defined( CLIENT_DLL )
  1190. UTIL_HudHintText( GetOwner(), "valve_hint_reload" );
  1191. m_iReloadHudHintCount++;
  1192. m_bReloadHudHintDisplayed = true;
  1193. m_flHudHintMinDisplayTime = gpGlobals->curtime + MIN_HUDHINT_DISPLAY_TIME;
  1194. #endif//CLIENT_DLL
  1195. }
  1196. //-----------------------------------------------------------------------------
  1197. //-----------------------------------------------------------------------------
  1198. void CBaseCombatWeapon::RescindReloadHudHint()
  1199. {
  1200. #if !defined( CLIENT_DLL )
  1201. Assert(m_bReloadHudHintDisplayed);
  1202. UTIL_HudHintText( GetOwner(), "" );
  1203. --m_iReloadHudHintCount;
  1204. m_bReloadHudHintDisplayed = false;
  1205. #endif//CLIENT_DLL
  1206. }
  1207. void CBaseCombatWeapon::SetPickupTouch( void )
  1208. {
  1209. #if !defined( CLIENT_DLL )
  1210. SetTouch(&CBaseCombatWeapon::DefaultTouch);
  1211. if ( gpGlobals->maxClients > 1 )
  1212. {
  1213. if ( GetSpawnFlags() & SF_NORESPAWN )
  1214. {
  1215. SetThink( &CBaseEntity::SUB_Remove );
  1216. SetNextThink( gpGlobals->curtime + 30.0f );
  1217. }
  1218. }
  1219. #endif
  1220. }
  1221. //-----------------------------------------------------------------------------
  1222. // Purpose: Become a child of the owner (MOVETYPE_FOLLOW)
  1223. // disables collisions, touch functions, thinking
  1224. // Input : *pOwner - new owner/operator
  1225. //-----------------------------------------------------------------------------
  1226. void CBaseCombatWeapon::Equip( CBaseCombatCharacter *pOwner )
  1227. {
  1228. // Attach the weapon to an owner
  1229. SetAbsVelocity( vec3_origin );
  1230. RemoveSolidFlags( FSOLID_TRIGGER );
  1231. FollowEntity( pOwner );
  1232. SetOwner( pOwner );
  1233. SetOwnerEntity( pOwner );
  1234. // Break any constraint I might have to the world.
  1235. RemoveEffects( EF_ITEM_BLINK );
  1236. #if !defined( CLIENT_DLL )
  1237. if ( m_pConstraint != NULL )
  1238. {
  1239. RemoveSpawnFlags( SF_WEAPON_START_CONSTRAINED );
  1240. physenv->DestroyConstraint( m_pConstraint );
  1241. m_pConstraint = NULL;
  1242. }
  1243. #endif
  1244. m_flNextPrimaryAttack = gpGlobals->curtime;
  1245. m_flNextSecondaryAttack = gpGlobals->curtime;
  1246. SetTouch( NULL );
  1247. SetThink( NULL );
  1248. #if !defined( CLIENT_DLL )
  1249. VPhysicsDestroyObject();
  1250. #endif
  1251. m_flNextPrimaryAttack = gpGlobals->curtime;
  1252. m_flNextSecondaryAttack = gpGlobals->curtime;
  1253. VerifyAndSetContextSensitiveWeaponModel();
  1254. }
  1255. CStudioHdr* CBaseCombatWeapon::OnNewModel()
  1256. {
  1257. ClassifyWeaponModel();
  1258. return BaseClass::OnNewModel();
  1259. }
  1260. void CBaseCombatWeapon::ClassifyWeaponModel( void )
  1261. {
  1262. // I don't like this either, but the model's aren't tagged in content,
  1263. // nor are they tagged coming in from multiple years of legacy demos in
  1264. // their various forms. Game code pushes new models by raw path all over
  1265. // the place, and I just need a way to verify and set the model as the
  1266. // appropriate kind without doing an expensive string comparison or
  1267. // model loop up by string each time.
  1268. const char *pszModelName = NULL;
  1269. if ( GetModel() )
  1270. pszModelName = modelinfo->GetModelName(GetModel());
  1271. if ( !pszModelName || pszModelName[0] == 0 )
  1272. {
  1273. m_WeaponModelClassification = WEAPON_MODEL_IS_UNCLASSIFIED;
  1274. }
  1275. else if ( V_stristr( pszModelName, "models/weapons/v_" ) )
  1276. {
  1277. m_WeaponModelClassification = WEAPON_MODEL_IS_VIEWMODEL;
  1278. }
  1279. else if ( V_stristr( pszModelName, "models/weapons/w_" ) )
  1280. {
  1281. if ( V_stristr( pszModelName, "_dropped.mdl" ) )
  1282. {
  1283. m_WeaponModelClassification = WEAPON_MODEL_IS_DROPPEDMODEL;
  1284. }
  1285. else
  1286. {
  1287. m_WeaponModelClassification = WEAPON_MODEL_IS_WORLDMODEL;
  1288. }
  1289. }
  1290. else
  1291. {
  1292. // valid path, just didn't match anything we were looking for.
  1293. m_WeaponModelClassification = WEAPON_MODEL_IS_UNRECOGNIZED;
  1294. }
  1295. }
  1296. void CBaseCombatWeapon::VerifyAndSetContextSensitiveWeaponModel( void )
  1297. {
  1298. // Check that the weapon model is the right kind (viewmodel, worldmodel, etc )
  1299. // Using a fast, non-string comparison check. If it's the wrong type,
  1300. // set the model to the correct version, then update the record so
  1301. // future checks are fast and don't need to continuously re-set the
  1302. // model unnecessarily.
  1303. WeaponModelClassification_t tClassification = GetWeaponModelClassification();
  1304. #ifdef CLIENT_DLL
  1305. if ( tClassification == WEAPON_MODEL_IS_UNCLASSIFIED )
  1306. {
  1307. if ( GetOwner() )
  1308. {
  1309. SetModel( GetWorldModel() );
  1310. }
  1311. else
  1312. {
  1313. SetModel( GetWorldDroppedModel() );
  1314. }
  1315. }
  1316. else if ( tClassification == WEAPON_MODEL_IS_VIEWMODEL )
  1317. {
  1318. if ( !GetOwner() )
  1319. {
  1320. SetModel( GetWorldDroppedModel() );
  1321. }
  1322. else if ( GetOwner()->ShouldDraw() )
  1323. {
  1324. SetModel( GetWorldModel() );
  1325. }
  1326. }
  1327. #else
  1328. if ( tClassification != WEAPON_MODEL_IS_VIEWMODEL && GetOwner() )
  1329. {
  1330. SetModel( GetViewModel() );
  1331. }
  1332. else if ( tClassification == WEAPON_MODEL_IS_UNCLASSIFIED || (tClassification == WEAPON_MODEL_IS_VIEWMODEL && !GetOwner()) )
  1333. {
  1334. SetModel( GetWorldDroppedModel() );
  1335. }
  1336. #endif
  1337. }
  1338. WeaponModelClassification_t CBaseCombatWeapon::GetWeaponModelClassification( void )
  1339. {
  1340. if ( m_WeaponModelClassification == WEAPON_MODEL_IS_UNCLASSIFIED )
  1341. {
  1342. ClassifyWeaponModel();
  1343. }
  1344. return m_WeaponModelClassification;
  1345. }
  1346. void CBaseCombatWeapon::SetActivity( Activity act, float duration )
  1347. {
  1348. int sequence = SelectWeightedSequence( act );
  1349. // FORCE IDLE on sequences we don't have (which should be many)
  1350. if ( sequence == ACTIVITY_NOT_AVAILABLE )
  1351. sequence = SelectWeightedSequence( ACT_VM_IDLE );
  1352. if ( sequence != ACTIVITY_NOT_AVAILABLE )
  1353. {
  1354. SetSequence( sequence );
  1355. SetActivity( act );
  1356. SetCycle( 0 );
  1357. ResetSequenceInfo( );
  1358. if ( duration > 0 )
  1359. {
  1360. // FIXME: does this even make sense in non-shoot animations?
  1361. m_flPlaybackRate = SequenceDuration( sequence ) / duration;
  1362. m_flPlaybackRate = fpmin( m_flPlaybackRate, 12.0f); // FIXME; magic number!, network encoding range
  1363. Assert( IsFinite( m_flPlaybackRate ) );
  1364. }
  1365. else
  1366. {
  1367. m_flPlaybackRate = 1.0;
  1368. }
  1369. }
  1370. }
  1371. //====================================================================================
  1372. // WEAPON CLIENT HANDLING
  1373. //====================================================================================
  1374. int CBaseCombatWeapon::UpdateClientData( CBasePlayer *pPlayer )
  1375. {
  1376. int iNewState = WEAPON_IS_CARRIED_BY_PLAYER;
  1377. if ( pPlayer->GetActiveWeapon() == this || IsAlwaysActive() )
  1378. {
  1379. iNewState = WEAPON_IS_ACTIVE;
  1380. }
  1381. else
  1382. {
  1383. iNewState = WEAPON_IS_CARRIED_BY_PLAYER;
  1384. }
  1385. if ( m_iState != iNewState )
  1386. {
  1387. m_iState = iNewState;
  1388. }
  1389. return 1;
  1390. }
  1391. //-----------------------------------------------------------------------------
  1392. // Purpose:
  1393. // Input : index -
  1394. //-----------------------------------------------------------------------------
  1395. void CBaseCombatWeapon::SetViewModelIndex( int index )
  1396. {
  1397. Assert( index >= 0 && index < MAX_VIEWMODELS );
  1398. m_nViewModelIndex = index;
  1399. }
  1400. //-----------------------------------------------------------------------------
  1401. // Purpose:
  1402. // Input : iActivity -
  1403. //-----------------------------------------------------------------------------
  1404. void CBaseCombatWeapon::SendViewModelAnim( int nSequence )
  1405. {
  1406. #if defined( CLIENT_DLL )
  1407. if ( !IsPredicted() )
  1408. return;
  1409. #endif
  1410. if ( nSequence < 0 )
  1411. return;
  1412. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  1413. if ( pOwner == NULL )
  1414. return;
  1415. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
  1416. if ( vm == NULL )
  1417. return;
  1418. SetViewModel();
  1419. Assert( vm->ViewModelIndex() == m_nViewModelIndex );
  1420. vm->SendViewModelMatchingSequence( nSequence );
  1421. }
  1422. float CBaseCombatWeapon::GetViewModelSequenceDuration()
  1423. {
  1424. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  1425. if ( pOwner == NULL )
  1426. {
  1427. Assert( false );
  1428. return 0;
  1429. }
  1430. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
  1431. if ( vm == NULL )
  1432. {
  1433. Assert( false );
  1434. return 0;
  1435. }
  1436. SetViewModel();
  1437. Assert( vm->ViewModelIndex() == m_nViewModelIndex );
  1438. return vm->SequenceDuration();
  1439. }
  1440. bool CBaseCombatWeapon::IsViewModelSequenceFinished( void )
  1441. {
  1442. // These are not valid activities and always complete immediately
  1443. if ( GetActivity() == ACT_RESET || GetActivity() == ACT_INVALID )
  1444. return true;
  1445. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  1446. if ( pOwner == NULL )
  1447. {
  1448. Assert( false );
  1449. return false;
  1450. }
  1451. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
  1452. if ( vm == NULL )
  1453. {
  1454. Assert( false );
  1455. return false;
  1456. }
  1457. return vm->IsSequenceFinished();
  1458. }
  1459. //-----------------------------------------------------------------------------
  1460. // Purpose:
  1461. //-----------------------------------------------------------------------------
  1462. void CBaseCombatWeapon::SetViewModel()
  1463. {
  1464. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  1465. if ( pOwner == NULL )
  1466. return;
  1467. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
  1468. if ( vm == NULL )
  1469. return;
  1470. Assert( vm->ViewModelIndex() == m_nViewModelIndex );
  1471. vm->SetWeaponModel( GetViewModel( m_nViewModelIndex ), this );
  1472. //#ifndef CLIENT_DLL
  1473. // SetWeaponModules();
  1474. //#endif
  1475. }
  1476. //-----------------------------------------------------------------------------
  1477. // Purpose: Set the desired activity for the weapon and its viewmodel counterpart
  1478. // Input : iActivity - activity to play
  1479. //-----------------------------------------------------------------------------
  1480. bool CBaseCombatWeapon::SendWeaponAnim( int iActivity )
  1481. {
  1482. //For now, just set the ideal activity and be done with it
  1483. return SetIdealActivity( (Activity) iActivity );
  1484. }
  1485. //====================================================================================
  1486. // WEAPON SELECTION
  1487. //====================================================================================
  1488. //-----------------------------------------------------------------------------
  1489. // Purpose: Returns true if the weapon currently has ammo or doesn't need ammo
  1490. // Output :
  1491. //-----------------------------------------------------------------------------
  1492. bool CBaseCombatWeapon::HasAnyAmmo( void )
  1493. {
  1494. // If I don't use ammo of any kind, I can always fire
  1495. if ( !UsesPrimaryAmmo() && !UsesSecondaryAmmo() )
  1496. return true;
  1497. // Otherwise, I need ammo of either type
  1498. return ( HasPrimaryAmmo() || HasSecondaryAmmo() );
  1499. }
  1500. //-----------------------------------------------------------------------------
  1501. // Purpose: Returns true if the weapon currently has ammo or doesn't need ammo
  1502. // Output :
  1503. //-----------------------------------------------------------------------------
  1504. bool CBaseCombatWeapon::HasPrimaryAmmo( void )
  1505. {
  1506. // If I use a clip, and have some ammo in it, then I have ammo
  1507. if ( UsesClipsForAmmo1() )
  1508. {
  1509. if ( m_iClip1 > 0 )
  1510. return true;
  1511. }
  1512. // Otherwise, I have ammo if I have some in my ammo counts
  1513. if ( GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) > 0 )
  1514. return true;
  1515. return false;
  1516. }
  1517. //-----------------------------------------------------------------------------
  1518. // Purpose: Returns true if the weapon currently has ammo or doesn't need ammo
  1519. // Output :
  1520. //-----------------------------------------------------------------------------
  1521. bool CBaseCombatWeapon::HasSecondaryAmmo( void )
  1522. {
  1523. // If I use a clip, and have some ammo in it, then I have ammo
  1524. if ( UsesClipsForAmmo2() )
  1525. {
  1526. if ( m_iClip2 > 0 )
  1527. return true;
  1528. }
  1529. // Otherwise, I have ammo if I have some in my ammo counts
  1530. if ( GetReserveAmmoCount( AMMO_POSITION_SECONDARY ) > 0 )
  1531. return true;
  1532. return false;
  1533. }
  1534. //-----------------------------------------------------------------------------
  1535. // Purpose: returns true if the weapon actually uses primary ammo
  1536. //-----------------------------------------------------------------------------
  1537. bool CBaseCombatWeapon::UsesPrimaryAmmo( void )
  1538. {
  1539. if ( m_iPrimaryAmmoType < 0 )
  1540. return false;
  1541. return true;
  1542. }
  1543. //-----------------------------------------------------------------------------
  1544. // Purpose: returns true if the weapon actually uses secondary ammo
  1545. //-----------------------------------------------------------------------------
  1546. bool CBaseCombatWeapon::UsesSecondaryAmmo( void )
  1547. {
  1548. if ( m_iSecondaryAmmoType < 0 )
  1549. return false;
  1550. return true;
  1551. }
  1552. //-----------------------------------------------------------------------------
  1553. // Purpose: Show/hide weapon and corresponding view model if any
  1554. // Input : visible -
  1555. //-----------------------------------------------------------------------------
  1556. void CBaseCombatWeapon::SetWeaponVisible( bool visible )
  1557. {
  1558. CBaseViewModel *vm = NULL;
  1559. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  1560. if ( pOwner )
  1561. {
  1562. vm = pOwner->GetViewModel( m_nViewModelIndex );
  1563. }
  1564. if ( pOwner )
  1565. {
  1566. AddEffects( EF_NODRAW ); // The combatweapon hides when held by a player. The weaponworldmodel renders instead.
  1567. }
  1568. else
  1569. {
  1570. if ( visible )
  1571. {
  1572. RemoveEffects( EF_NODRAW );
  1573. }
  1574. else
  1575. {
  1576. AddEffects( EF_NODRAW );
  1577. }
  1578. }
  1579. // viewmodel
  1580. if ( vm )
  1581. {
  1582. if ( visible )
  1583. {
  1584. vm->RemoveEffects( EF_NODRAW );
  1585. }
  1586. else
  1587. {
  1588. vm->AddEffects( EF_NODRAW );
  1589. }
  1590. }
  1591. }
  1592. //-----------------------------------------------------------------------------
  1593. // Purpose:
  1594. //-----------------------------------------------------------------------------
  1595. bool CBaseCombatWeapon::IsWeaponVisible( void )
  1596. {
  1597. CBaseViewModel *vm = NULL;
  1598. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  1599. if ( pOwner )
  1600. {
  1601. vm = pOwner->GetViewModel( m_nViewModelIndex );
  1602. if ( vm )
  1603. {
  1604. #ifdef CLIENT_DLL
  1605. return !vm->IsDormant() && !vm->IsEffectActive(EF_NODRAW);
  1606. #else
  1607. return ( !vm->IsEffectActive(EF_NODRAW) );
  1608. #endif
  1609. }
  1610. }
  1611. return false;
  1612. }
  1613. //-----------------------------------------------------------------------------
  1614. // Purpose: If the current weapon has more ammo, reload it. Otherwise, switch
  1615. // to the next best weapon we've got. Returns true if it took any action.
  1616. //-----------------------------------------------------------------------------
  1617. bool CBaseCombatWeapon::ReloadOrSwitchWeapons( void )
  1618. {
  1619. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  1620. Assert( pOwner );
  1621. m_bFireOnEmpty = false;
  1622. // If we don't have any ammo, switch to the next best weapon
  1623. if ( !HasAnyAmmo() && m_flNextPrimaryAttack < gpGlobals->curtime && m_flNextSecondaryAttack < gpGlobals->curtime )
  1624. {
  1625. // weapon isn't useable, switch.
  1626. if ( ( (GetWeaponFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) == false ) && ( g_pGameRules->SwitchToNextBestWeapon( pOwner, this ) ) )
  1627. {
  1628. m_flNextPrimaryAttack = gpGlobals->curtime + 0.3;
  1629. return true;
  1630. }
  1631. }
  1632. else
  1633. {
  1634. // Weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
  1635. if ( UsesClipsForAmmo1() &&
  1636. (m_iClip1 == 0) &&
  1637. (GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD) == false &&
  1638. m_flNextPrimaryAttack < gpGlobals->curtime &&
  1639. m_flNextSecondaryAttack < gpGlobals->curtime )
  1640. {
  1641. // if we're successfully reloading, we're done
  1642. if ( Reload() )
  1643. {
  1644. return true;
  1645. }
  1646. }
  1647. }
  1648. return false;
  1649. }
  1650. //-----------------------------------------------------------------------------
  1651. // Purpose:
  1652. // Input : *szViewModel -
  1653. // *szWeaponModel -
  1654. // iActivity -
  1655. // *szAnimExt -
  1656. // Output : Returns true on success, false on failure.
  1657. //-----------------------------------------------------------------------------
  1658. bool CBaseCombatWeapon::DefaultDeploy( char *szViewModel, char *szWeaponModel, int iActivity, char *szAnimExt )
  1659. {
  1660. // Msg( "deploy %s at %f\n", GetClassname(), gpGlobals->curtime );
  1661. // Weapons that don't autoswitch away when they run out of ammo
  1662. // can still be deployed when they have no ammo.
  1663. if ( !HasAnyAmmo() && AllowsAutoSwitchFrom() )
  1664. return false;
  1665. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  1666. if ( pOwner )
  1667. {
  1668. // Dead men deploy no weapons
  1669. if ( pOwner->IsAlive() == false )
  1670. return false;
  1671. pOwner->SetAnimationExtension( szAnimExt );
  1672. SetViewModel();
  1673. SendWeaponAnim( iActivity );
  1674. pOwner->SetNextAttack( gpGlobals->curtime + SequenceDuration() );
  1675. }
  1676. // Can't shoot again until we've finished deploying
  1677. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  1678. m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
  1679. m_flHudHintMinDisplayTime = 0;
  1680. m_bAltFireHudHintDisplayed = false;
  1681. m_bReloadHudHintDisplayed = false;
  1682. m_flHudHintPollTime = gpGlobals->curtime + 5.0f;
  1683. SetWeaponVisible( true );
  1684. /*
  1685. This code is disabled for now, because moving through the weapons in the carousel
  1686. selects and deploys each weapon as you pass it. (sjb)
  1687. */
  1688. SetContextThink( NULL, 0, HIDEWEAPON_THINK_CONTEXT );
  1689. return true;
  1690. }
  1691. //-----------------------------------------------------------------------------
  1692. // Purpose:
  1693. //-----------------------------------------------------------------------------
  1694. bool CBaseCombatWeapon::Deploy( )
  1695. {
  1696. MDLCACHE_CRITICAL_SECTION();
  1697. #if !defined( CLIENT_DLL )
  1698. CreateWeaponWorldModel();
  1699. ShowWeaponWorldModel( false ); // don't show right away, wait for the deploy anim to unhide it
  1700. #endif
  1701. return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), GetDrawActivity(), (char*)GetAnimPrefix() );
  1702. }
  1703. Activity CBaseCombatWeapon::GetDrawActivity( void )
  1704. {
  1705. CBaseCombatCharacter *pOwner = GetOwner();
  1706. if (pOwner)
  1707. {
  1708. if ( GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) <= 0 && LookupActivity( "ACT_VM_EMPTY_DRAW" ) > 0 )
  1709. {
  1710. return ACT_VM_EMPTY_DRAW;
  1711. }
  1712. }
  1713. return ACT_VM_DRAW;
  1714. }
  1715. //-----------------------------------------------------------------------------
  1716. // Purpose:
  1717. //-----------------------------------------------------------------------------
  1718. bool CBaseCombatWeapon::Holster( CBaseCombatWeapon *pSwitchingTo )
  1719. {
  1720. MDLCACHE_CRITICAL_SECTION();
  1721. #if !defined( CLIENT_DLL )
  1722. ShowWeaponWorldModel( false );
  1723. //if ( pSwitchingTo )
  1724. // pSwitchingTo->ShowWeaponWorldModel( false ); // redundant - new weapon hides on its own deploy
  1725. #endif
  1726. // cancel any reload in progress.
  1727. m_bInReload = false;
  1728. // kill any think functions
  1729. SetThink(NULL);
  1730. // Send holster animation
  1731. SendWeaponAnim( ACT_VM_HOLSTER );
  1732. // Some weapon's don't have holster anims yet, so detect that
  1733. float flSequenceDuration = 0;
  1734. if ( GetActivity() == ACT_VM_HOLSTER )
  1735. {
  1736. flSequenceDuration = SequenceDuration();
  1737. }
  1738. CBaseCombatCharacter *pOwner = GetOwner();
  1739. if (pOwner)
  1740. {
  1741. pOwner->SetNextAttack( gpGlobals->curtime + flSequenceDuration );
  1742. }
  1743. // If we don't have a holster anim, hide immediately to avoid timing issues
  1744. if ( !flSequenceDuration )
  1745. {
  1746. SetWeaponVisible( false );
  1747. }
  1748. else
  1749. {
  1750. // Hide the weapon when the holster animation's finished
  1751. SetContextThink( &CBaseCombatWeapon::HideThink, gpGlobals->curtime + flSequenceDuration, HIDEWEAPON_THINK_CONTEXT );
  1752. }
  1753. // if we were displaying a hud hint, squelch it.
  1754. if (m_flHudHintMinDisplayTime && gpGlobals->curtime < m_flHudHintMinDisplayTime)
  1755. {
  1756. if( m_bAltFireHudHintDisplayed )
  1757. RescindAltFireHudHint();
  1758. if( m_bReloadHudHintDisplayed )
  1759. RescindReloadHudHint();
  1760. }
  1761. return true;
  1762. }
  1763. #ifdef CLIENT_DLL
  1764. void CBaseCombatWeapon::BoneMergeFastCullBloat( Vector &localMins, Vector &localMaxs, const Vector &thisEntityMins, const Vector &thisEntityMaxs ) const
  1765. {
  1766. // The default behavior pushes it out by BONEMERGE_FASTCULL_BBOX_EXPAND in all directions, but we can do better
  1767. // since we know the weapon will never point behind him.
  1768. localMaxs.x += 20; // Leaves some space in front for long weapons.
  1769. localMins.y -= 20; // Fatten it to his left and right since he can rotate that way.
  1770. localMaxs.y += 20;
  1771. localMaxs.z += 15; // Leave some space at the top.
  1772. }
  1773. #else
  1774. //-----------------------------------------------------------------------------
  1775. // Purpose:
  1776. //-----------------------------------------------------------------------------
  1777. void CBaseCombatWeapon::InputHideWeapon( inputdata_t &inputdata )
  1778. {
  1779. // Only hide if we're still the active weapon. If we're not the active weapon
  1780. if ( GetOwner() && GetOwner()->GetActiveWeapon() == this )
  1781. {
  1782. SetWeaponVisible( false );
  1783. }
  1784. }
  1785. #endif
  1786. //-----------------------------------------------------------------------------
  1787. // Purpose:
  1788. //-----------------------------------------------------------------------------
  1789. void CBaseCombatWeapon::HideThink( void )
  1790. {
  1791. // Only hide if we're still the active weapon. If we're not the active weapon
  1792. if ( GetOwner() && GetOwner()->GetActiveWeapon() == this )
  1793. {
  1794. SetWeaponVisible( false );
  1795. }
  1796. }
  1797. //-----------------------------------------------------------------------------
  1798. // Purpose:
  1799. //-----------------------------------------------------------------------------
  1800. void CBaseCombatWeapon::ItemPreFrame( void )
  1801. {
  1802. MaintainIdealActivity();
  1803. #ifndef CLIENT_DLL
  1804. #ifndef HL2_EPISODIC
  1805. if ( IsGameConsole() )
  1806. #endif
  1807. {
  1808. // If we haven't displayed the hint enough times yet, it's time to try to
  1809. // display the hint, and the player is not standing still, try to show a hud hint.
  1810. // If the player IS standing still, assume they could change away from this weapon at
  1811. // any second.
  1812. if( (!m_bAltFireHudHintDisplayed || !m_bReloadHudHintDisplayed) && gpGlobals->curtime > m_flHudHintMinDisplayTime && gpGlobals->curtime > m_flHudHintPollTime && GetOwner() && GetOwner()->IsPlayer() )
  1813. {
  1814. CBasePlayer *pPlayer = (CBasePlayer*)(GetOwner());
  1815. if( pPlayer && pPlayer->GetStickDist() > 0.0f )
  1816. {
  1817. // If the player is moving, they're unlikely to switch away from the current weapon
  1818. // the moment this weapon displays its HUD hint.
  1819. if( ShouldDisplayReloadHUDHint() )
  1820. {
  1821. DisplayReloadHudHint();
  1822. }
  1823. else if( ShouldDisplayAltFireHUDHint() )
  1824. {
  1825. DisplayAltFireHudHint();
  1826. }
  1827. }
  1828. else
  1829. {
  1830. m_flHudHintPollTime = gpGlobals->curtime + 2.0f;
  1831. }
  1832. }
  1833. }
  1834. #endif
  1835. }
  1836. //====================================================================================
  1837. // WEAPON BEHAVIOUR
  1838. //====================================================================================
  1839. void CBaseCombatWeapon::ItemPostFrame( void )
  1840. {
  1841. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  1842. if (!pOwner)
  1843. return;
  1844. //Track the duration of the fire
  1845. //FIXME: Check for IN_ATTACK2 as well?
  1846. //FIXME: What if we're calling ItemBusyFrame?
  1847. m_fFireDuration = ( pOwner->m_nButtons & IN_ATTACK ) ? ( m_fFireDuration + gpGlobals->frametime ) : 0.0f;
  1848. if ( UsesClipsForAmmo1() )
  1849. {
  1850. CheckReload();
  1851. }
  1852. bool bFired = false;
  1853. // Secondary attack has priority
  1854. if ((pOwner->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime))
  1855. {
  1856. if (UsesSecondaryAmmo() && GetReserveAmmoCount( AMMO_POSITION_SECONDARY ) <= 0 )
  1857. {
  1858. if (m_flNextEmptySoundTime < gpGlobals->curtime)
  1859. {
  1860. WeaponSound(EMPTY);
  1861. m_flNextSecondaryAttack = m_flNextEmptySoundTime = gpGlobals->curtime + 0.5;
  1862. }
  1863. }
  1864. else if (pOwner->GetWaterLevel() == WL_Eyes && m_bAltFiresUnderwater == false)
  1865. {
  1866. // This weapon doesn't fire underwater
  1867. WeaponSound(EMPTY);
  1868. m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
  1869. return;
  1870. }
  1871. else
  1872. {
  1873. // FIXME: This isn't necessarily true if the weapon doesn't have a secondary fire!
  1874. // For instance, the crossbow doesn't have a 'real' secondary fire, but it still
  1875. // stops the crossbow from firing on the 360 if the player chooses to hold down their
  1876. // zoom button. (sjb) Orange Box 7/25/2007
  1877. #if !defined(CLIENT_DLL)
  1878. if( !IsGameConsole() || !ClassMatches("weapon_crossbow") )
  1879. #endif
  1880. {
  1881. bFired = ShouldBlockPrimaryFire();
  1882. }
  1883. SecondaryAttack();
  1884. // Secondary ammo doesn't have a reload animation
  1885. if ( UsesClipsForAmmo2() )
  1886. {
  1887. // reload clip2 if empty
  1888. if (m_iClip2 < 1)
  1889. {
  1890. GiveReserveAmmo( AMMO_POSITION_SECONDARY, -1 );
  1891. m_iClip2 = m_iClip2 + 1;
  1892. }
  1893. }
  1894. }
  1895. }
  1896. if ( !bFired && (pOwner->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime))
  1897. {
  1898. // Clip empty? Or out of ammo on a no-clip weapon?
  1899. if ( !IsMeleeWeapon() &&
  1900. (( UsesClipsForAmmo1() && m_iClip1 <= 0) || ( !UsesClipsForAmmo1() && GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) <= 0 )) )
  1901. {
  1902. HandleFireOnEmpty();
  1903. }
  1904. else if (pOwner->GetWaterLevel() == WL_Eyes && m_bFiresUnderwater == false)
  1905. {
  1906. // This weapon doesn't fire underwater
  1907. WeaponSound(EMPTY);
  1908. m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
  1909. return;
  1910. }
  1911. else
  1912. {
  1913. //NOTENOTE: There is a bug with this code with regards to the way machine guns catch the leading edge trigger
  1914. // on the player hitting the attack key. It relies on the gun catching that case in the same frame.
  1915. // However, because the player can also be doing a secondary attack, the edge trigger may be missed.
  1916. // We really need to hold onto the edge trigger and only clear the condition when the gun has fired its
  1917. // first shot. Right now that's too much of an architecture change -- jdw
  1918. // If the firing button was just pressed, or the alt-fire just released, reset the firing time
  1919. if ( ( pOwner->m_afButtonPressed & IN_ATTACK ) || ( pOwner->m_afButtonReleased & IN_ATTACK2 ) || ( pOwner->m_afButtonReleased & IN_ZOOM ) )
  1920. {
  1921. m_flNextPrimaryAttack = gpGlobals->curtime;
  1922. }
  1923. PrimaryAttack();
  1924. #ifdef CLIENT_DLL
  1925. pOwner->SetFiredWeapon( true );
  1926. #endif
  1927. }
  1928. }
  1929. // -----------------------
  1930. // Reload pressed / Clip Empty
  1931. // -----------------------
  1932. if ( (pOwner->m_nButtons & IN_RELOAD) && UsesClipsForAmmo1() && !m_bInReload )
  1933. {
  1934. // reload when reload is pressed, or if no buttons are down and weapon is empty.
  1935. Reload();
  1936. m_fFireDuration = 0.0f;
  1937. }
  1938. // -----------------------
  1939. // No buttons down
  1940. // -----------------------
  1941. if (!((pOwner->m_nButtons & IN_ATTACK) || (pOwner->m_nButtons & IN_ATTACK2) || ( pOwner->m_nButtons & IN_ZOOM) || ( CanReload() && pOwner->m_nButtons & IN_RELOAD )))
  1942. {
  1943. // no fire buttons down or reloading
  1944. if ( ( m_bInReload == false ) && !ReloadOrSwitchWeapons() )
  1945. {
  1946. WeaponIdle();
  1947. }
  1948. }
  1949. }
  1950. void CBaseCombatWeapon::HandleFireOnEmpty()
  1951. {
  1952. // If we're already firing on empty, reload if we can
  1953. if ( m_bFireOnEmpty )
  1954. {
  1955. ReloadOrSwitchWeapons();
  1956. m_fFireDuration = 0.0f;
  1957. }
  1958. else
  1959. {
  1960. if (m_flNextEmptySoundTime < gpGlobals->curtime)
  1961. {
  1962. WeaponSound(EMPTY);
  1963. m_flNextEmptySoundTime = gpGlobals->curtime + 0.5;
  1964. }
  1965. m_bFireOnEmpty = true;
  1966. }
  1967. }
  1968. //-----------------------------------------------------------------------------
  1969. // Purpose: Called each frame by the player PostThink, if the player's not ready to attack yet
  1970. //-----------------------------------------------------------------------------
  1971. void CBaseCombatWeapon::ItemBusyFrame( void )
  1972. {
  1973. }
  1974. //-----------------------------------------------------------------------------
  1975. // Purpose: Base class default for getting bullet type
  1976. // Input :
  1977. // Output :
  1978. //-----------------------------------------------------------------------------
  1979. int CBaseCombatWeapon::GetBulletType( void )
  1980. {
  1981. return 0;
  1982. }
  1983. //-----------------------------------------------------------------------------
  1984. // Purpose: Base class default for getting spread
  1985. // Input :
  1986. // Output :
  1987. //-----------------------------------------------------------------------------
  1988. const Vector& CBaseCombatWeapon::GetBulletSpread( void )
  1989. {
  1990. static Vector cone = VECTOR_CONE_15DEGREES;
  1991. return cone;
  1992. }
  1993. //-----------------------------------------------------------------------------
  1994. const WeaponProficiencyInfo_t *CBaseCombatWeapon::GetProficiencyValues()
  1995. {
  1996. static WeaponProficiencyInfo_t defaultWeaponProficiencyTable[] =
  1997. {
  1998. { 1.0, 1.0 },
  1999. { 1.0, 1.0 },
  2000. { 1.0, 1.0 },
  2001. { 1.0, 1.0 },
  2002. { 1.0, 1.0 },
  2003. };
  2004. COMPILE_TIME_ASSERT( ARRAYSIZE(defaultWeaponProficiencyTable) == WEAPON_PROFICIENCY_PERFECT + 1);
  2005. return defaultWeaponProficiencyTable;
  2006. }
  2007. //-----------------------------------------------------------------------------
  2008. // Purpose: Base class default for getting firerate
  2009. // Input :
  2010. // Output :
  2011. //-----------------------------------------------------------------------------
  2012. float CBaseCombatWeapon::GetFireRate( void )
  2013. {
  2014. return 0;
  2015. }
  2016. //-----------------------------------------------------------------------------
  2017. // Purpose: Base class default for playing shoot sound
  2018. // Input :
  2019. // Output :
  2020. //-----------------------------------------------------------------------------
  2021. void CBaseCombatWeapon::WeaponSound( WeaponSound_t sound_type, float soundtime /* = 0.0f */ )
  2022. {
  2023. // If we have some sounds from the weapon classname.txt file, play a random one of them
  2024. const char *shootsound = GetShootSound( sound_type );
  2025. if ( !shootsound || !shootsound[0] )
  2026. return;
  2027. CSoundParameters params;
  2028. if ( !GetParametersForSound( shootsound, params, NULL ) )
  2029. return;
  2030. if ( params.play_to_owner_only )
  2031. {
  2032. // Am I only to play to my owner?
  2033. if ( GetOwner() && GetOwner()->IsPlayer() )
  2034. {
  2035. CSingleUserRecipientFilter filter( ToBasePlayer( GetOwner() ) );
  2036. if ( IsPredicted() && CBaseEntity::GetPredictionPlayer() )
  2037. {
  2038. filter.UsePredictionRules();
  2039. }
  2040. EmitSound( filter, GetOwner()->entindex(), shootsound, NULL, soundtime );
  2041. }
  2042. }
  2043. else
  2044. {
  2045. // Play weapon sound from the owner
  2046. if ( GetOwner() )
  2047. {
  2048. CBroadcastRecipientFilter filter;
  2049. EmitSound( filter, GetOwner()->entindex(), shootsound, NULL, soundtime );
  2050. #if !defined( CLIENT_DLL )
  2051. if( sound_type == EMPTY )
  2052. {
  2053. CSoundEnt::InsertSound( SOUND_COMBAT, GetOwner()->GetAbsOrigin(), SOUNDENT_VOLUME_EMPTY, 0.2, GetOwner() );
  2054. }
  2055. #endif
  2056. }
  2057. // If no owner play from the weapon (this is used for thrown items)
  2058. else
  2059. {
  2060. CBroadcastRecipientFilter filter;
  2061. EmitSound( filter, entindex(), shootsound, NULL, soundtime );
  2062. }
  2063. }
  2064. }
  2065. //-----------------------------------------------------------------------------
  2066. // Purpose: Stop a sound played by this weapon.
  2067. //-----------------------------------------------------------------------------
  2068. void CBaseCombatWeapon::StopWeaponSound( WeaponSound_t sound_type )
  2069. {
  2070. //if ( IsPredicted() )
  2071. // return;
  2072. // If we have some sounds from the weapon classname.txt file, play a random one of them
  2073. const char *shootsound = GetShootSound( sound_type );
  2074. if ( !shootsound || !shootsound[0] )
  2075. return;
  2076. CSoundParameters params;
  2077. if ( !GetParametersForSound( shootsound, params, NULL ) )
  2078. return;
  2079. // Am I only to play to my owner?
  2080. if ( params.play_to_owner_only )
  2081. {
  2082. if ( GetOwner() )
  2083. {
  2084. StopSound( GetOwner()->entindex(), shootsound );
  2085. }
  2086. }
  2087. else
  2088. {
  2089. // Play weapon sound from the owner
  2090. if ( GetOwner() )
  2091. {
  2092. StopSound( GetOwner()->entindex(), shootsound );
  2093. }
  2094. // If no owner play from the weapon (this is used for thrown items)
  2095. else
  2096. {
  2097. StopSound( entindex(), shootsound );
  2098. }
  2099. }
  2100. }
  2101. //-----------------------------------------------------------------------------
  2102. // Purpose:
  2103. //-----------------------------------------------------------------------------
  2104. bool CBaseCombatWeapon::DefaultReload( int iClipSize1, int iClipSize2, int iActivity )
  2105. {
  2106. CBaseCombatCharacter *pOwner = GetOwner();
  2107. if (!pOwner)
  2108. return false;
  2109. // If I don't have any spare ammo, I can't reload
  2110. if ( GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) <= 0 )
  2111. return false;
  2112. bool bReload = false;
  2113. // If you don't have clips, then don't try to reload them.
  2114. if ( UsesClipsForAmmo1() )
  2115. {
  2116. // need to reload primary clip?
  2117. int primary = MIN(iClipSize1 - m_iClip1, GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) );
  2118. if ( primary != 0 )
  2119. {
  2120. bReload = true;
  2121. }
  2122. }
  2123. if ( UsesClipsForAmmo2() )
  2124. {
  2125. // need to reload secondary clip?
  2126. int secondary = MIN(iClipSize2 - m_iClip2, GetReserveAmmoCount( AMMO_POSITION_SECONDARY ) );
  2127. if ( secondary != 0 )
  2128. {
  2129. bReload = true;
  2130. }
  2131. }
  2132. if ( !bReload )
  2133. return false;
  2134. #ifdef CLIENT_DLL
  2135. // Play reload
  2136. WeaponSound( RELOAD );
  2137. #endif
  2138. SendWeaponAnim( iActivity );
  2139. // Play the player's reload animation
  2140. if ( pOwner->IsPlayer() )
  2141. {
  2142. ( ( CBasePlayer * )pOwner)->SetAnimation( PLAYER_RELOAD );
  2143. }
  2144. MDLCACHE_CRITICAL_SECTION();
  2145. float flSequenceEndTime = gpGlobals->curtime + SequenceDuration();
  2146. pOwner->SetNextAttack( flSequenceEndTime );
  2147. m_flNextPrimaryAttack = m_flNextSecondaryAttack = flSequenceEndTime;
  2148. m_bInReload = true;
  2149. return true;
  2150. }
  2151. //-----------------------------------------------------------------------------
  2152. // Purpose:
  2153. //-----------------------------------------------------------------------------
  2154. bool CBaseCombatWeapon::Reload( void )
  2155. {
  2156. return DefaultReload( GetMaxClip1(), GetMaxClip2(), m_iReloadActivityIndex );
  2157. }
  2158. //=========================================================
  2159. void CBaseCombatWeapon::WeaponIdle( void )
  2160. {
  2161. //Idle again if we've finished
  2162. if ( HasWeaponIdleTimeElapsed() )
  2163. {
  2164. SendWeaponAnim( ACT_VM_IDLE );
  2165. }
  2166. }
  2167. //=========================================================
  2168. Activity CBaseCombatWeapon::GetPrimaryAttackActivity( void )
  2169. {
  2170. return ACT_VM_PRIMARYATTACK;
  2171. }
  2172. //=========================================================
  2173. Activity CBaseCombatWeapon::GetSecondaryAttackActivity( void )
  2174. {
  2175. return ACT_VM_SECONDARYATTACK;
  2176. }
  2177. //-----------------------------------------------------------------------------
  2178. // Purpose: Adds in view kick and weapon accuracy degradation effect
  2179. //-----------------------------------------------------------------------------
  2180. void CBaseCombatWeapon::AddViewKick( void )
  2181. {
  2182. //NOTENOTE: By default, weapon will not kick up (defined per weapon)
  2183. }
  2184. //-----------------------------------------------------------------------------
  2185. // Purpose: Get the string to print death notices with
  2186. //-----------------------------------------------------------------------------
  2187. char *CBaseCombatWeapon::GetDeathNoticeName( void )
  2188. {
  2189. #if !defined( CLIENT_DLL )
  2190. return (char*)STRING( m_iszName );
  2191. #else
  2192. return "GetDeathNoticeName not implemented on client yet";
  2193. #endif
  2194. }
  2195. //====================================================================================
  2196. // WEAPON RELOAD TYPES
  2197. //====================================================================================
  2198. void CBaseCombatWeapon::CheckReload( void )
  2199. {
  2200. if ( m_bReloadsSingly )
  2201. {
  2202. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  2203. if ( !pOwner )
  2204. return;
  2205. if ((m_bInReload) && (m_flNextPrimaryAttack <= gpGlobals->curtime))
  2206. {
  2207. if ( pOwner->m_nButtons & (IN_ATTACK | IN_ATTACK2 | IN_ZOOM ) && m_iClip1 > 0 )
  2208. {
  2209. m_bInReload = false;
  2210. return;
  2211. }
  2212. // If out of ammo end reload
  2213. if ( GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) <=0 )
  2214. {
  2215. FinishReload();
  2216. return;
  2217. }
  2218. // If clip not full reload again
  2219. else if (m_iClip1 < GetMaxClip1())
  2220. {
  2221. // Add them to the clip
  2222. m_iClip1 += 1;
  2223. GiveReserveAmmo( AMMO_POSITION_PRIMARY, - 1 );
  2224. Reload();
  2225. return;
  2226. }
  2227. // Clip full, stop reloading
  2228. else
  2229. {
  2230. FinishReload();
  2231. m_flNextPrimaryAttack = gpGlobals->curtime;
  2232. m_flNextSecondaryAttack = gpGlobals->curtime;
  2233. return;
  2234. }
  2235. }
  2236. }
  2237. else
  2238. {
  2239. if ( (m_bInReload) && (m_flNextPrimaryAttack <= gpGlobals->curtime))
  2240. {
  2241. FinishReload();
  2242. m_flNextPrimaryAttack = gpGlobals->curtime;
  2243. m_flNextSecondaryAttack = gpGlobals->curtime;
  2244. m_bInReload = false;
  2245. }
  2246. }
  2247. }
  2248. //-----------------------------------------------------------------------------
  2249. // Purpose: Reload has finished.
  2250. //-----------------------------------------------------------------------------
  2251. void CBaseCombatWeapon::FinishReload( void )
  2252. {
  2253. CBaseCombatCharacter *pOwner = GetOwner();
  2254. if (pOwner)
  2255. {
  2256. // If I use primary clips, reload primary
  2257. if ( UsesClipsForAmmo1() )
  2258. {
  2259. int primary = MIN( GetMaxClip1() - m_iClip1, GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) );
  2260. m_iClip1 += primary;
  2261. GiveReserveAmmo( AMMO_POSITION_PRIMARY, -primary );
  2262. }
  2263. // If I use secondary clips, reload secondary
  2264. if ( UsesClipsForAmmo2() )
  2265. {
  2266. int secondary = MIN( GetMaxClip2() - m_iClip2, GetReserveAmmoCount( AMMO_POSITION_SECONDARY ) );
  2267. m_iClip2 += secondary;
  2268. GiveReserveAmmo( AMMO_POSITION_SECONDARY, -secondary );
  2269. }
  2270. if ( m_bReloadsSingly )
  2271. {
  2272. m_bInReload = false;
  2273. }
  2274. }
  2275. }
  2276. //-----------------------------------------------------------------------------
  2277. // Purpose: Abort any reload we have in progress
  2278. //-----------------------------------------------------------------------------
  2279. void CBaseCombatWeapon::AbortReload( void )
  2280. {
  2281. #ifdef CLIENT_DLL
  2282. StopWeaponSound( RELOAD );
  2283. #endif
  2284. m_bInReload = false;
  2285. }
  2286. //-----------------------------------------------------------------------------
  2287. // Purpose: Primary fire button attack
  2288. //-----------------------------------------------------------------------------
  2289. void CBaseCombatWeapon::PrimaryAttack( void )
  2290. {
  2291. // If my clip is empty (and I use clips) start reload
  2292. if ( UsesClipsForAmmo1() && !m_iClip1 )
  2293. {
  2294. m_iNumEmptyAttacks++;
  2295. Reload();
  2296. return;
  2297. }
  2298. // Only the player fires this way so we can cast
  2299. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  2300. if (!pPlayer)
  2301. {
  2302. return;
  2303. }
  2304. pPlayer->DoMuzzleFlash();
  2305. SendWeaponAnim( GetPrimaryAttackActivity() );
  2306. // player "shoot" animation
  2307. pPlayer->SetAnimation( PLAYER_ATTACK1 );
  2308. FireBulletsInfo_t info;
  2309. info.m_vecSrc = pPlayer->Weapon_ShootPosition( );
  2310. info.m_vecDirShooting = pPlayer->GetAutoaimVector( AUTOAIM_SCALE_DEFAULT );
  2311. float flFishtail = GetAccuracyFishtail();
  2312. if ( flFishtail != 0.0f )
  2313. {
  2314. QAngle angShootAngles;
  2315. VectorAngles( info.m_vecDirShooting, angShootAngles );
  2316. angShootAngles.y += flFishtail;
  2317. AngleVectors( angShootAngles, &info.m_vecDirShooting );
  2318. }
  2319. // To make the firing framerate independent, we may have to fire more than one bullet here on low-framerate systems,
  2320. // especially if the weapon we're firing has a really fast rate of fire.
  2321. info.m_iShots = 0;
  2322. float fireRate = GetFireRate();
  2323. while ( m_flNextPrimaryAttack <= gpGlobals->curtime )
  2324. {
  2325. // MUST call sound before removing a round from the clip of a CMachineGun
  2326. WeaponSound(SINGLE, m_flNextPrimaryAttack);
  2327. m_flNextPrimaryAttack = m_flNextPrimaryAttack + fireRate;
  2328. info.m_iShots++;
  2329. if ( !fireRate )
  2330. break;
  2331. }
  2332. // Make sure we don't fire more than the amount in the clip
  2333. if ( UsesClipsForAmmo1() )
  2334. {
  2335. info.m_iShots = MIN( info.m_iShots, m_iClip1.Get() );
  2336. m_iClip1 -= info.m_iShots;
  2337. }
  2338. else
  2339. {
  2340. info.m_iShots = MIN( info.m_iShots, GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) );
  2341. GiveReserveAmmo( AMMO_POSITION_PRIMARY, -info.m_iShots );
  2342. }
  2343. info.m_flDistance = MAX_TRACE_LENGTH;
  2344. info.m_iAmmoType = m_iPrimaryAmmoType;
  2345. info.m_iTracerFreq = 2;
  2346. #if !defined( CLIENT_DLL )
  2347. // Fire the bullets
  2348. info.m_vecSpread = pPlayer->GetAttackSpread( this );
  2349. #else
  2350. //!!!HACKHACK - what does the client want this function for?
  2351. info.m_vecSpread = pPlayer->GetActiveWeapon()->GetBulletSpread();
  2352. #endif // CLIENT_DLL
  2353. pPlayer->FireBullets( info );
  2354. if (!m_iClip1 && GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) <= 0 )
  2355. {
  2356. // HEV suit - indicate out of ammo condition
  2357. pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
  2358. }
  2359. //Add our view kick in
  2360. AddViewKick();
  2361. }
  2362. void CBaseCombatWeapon::BaseForceFire( CBaseCombatCharacter *pOperator, CBaseEntity *pTarget )
  2363. {
  2364. // Ensure we have enough rounds in the clip
  2365. m_iClip1++;
  2366. // If my clip is empty (and I use clips) start reload
  2367. if ( UsesClipsForAmmo1() && !m_iClip1 )
  2368. {
  2369. Reload();
  2370. return;
  2371. }
  2372. pOperator->DoMuzzleFlash();
  2373. SendWeaponAnim( GetPrimaryAttackActivity() );
  2374. // player "shoot" animation
  2375. //pOperator->SetAnimation( PLAYER_ATTACK1 );
  2376. FireBulletsInfo_t info;
  2377. QAngle angShootDir;
  2378. GetAttachment( LookupAttachment( "muzzle" ), info.m_vecSrc, angShootDir );
  2379. if ( pTarget )
  2380. {
  2381. info.m_vecDirShooting = pTarget->WorldSpaceCenter() - info.m_vecSrc;
  2382. VectorNormalize( info.m_vecDirShooting );
  2383. }
  2384. else
  2385. {
  2386. AngleVectors( angShootDir, &info.m_vecDirShooting );
  2387. }
  2388. // To make the firing framerate independent, we may have to fire more than one bullet here on low-framerate systems,
  2389. // especially if the weapon we're firing has a really fast rate of fire.
  2390. info.m_iShots = 0;
  2391. float fireRate = GetFireRate();
  2392. while ( m_flNextPrimaryAttack <= gpGlobals->curtime )
  2393. {
  2394. // MUST call sound before removing a round from the clip of a CMachineGun
  2395. WeaponSound(SINGLE, m_flNextPrimaryAttack);
  2396. m_flNextPrimaryAttack = m_flNextPrimaryAttack + fireRate;
  2397. info.m_iShots++;
  2398. if ( !fireRate )
  2399. break;
  2400. }
  2401. // Make sure we don't fire more than the amount in the clip
  2402. if ( UsesClipsForAmmo1() )
  2403. {
  2404. info.m_iShots = Min( info.m_iShots, m_iClip1.Get() );
  2405. m_iClip1 -= info.m_iShots;
  2406. }
  2407. else
  2408. {
  2409. info.m_iShots = Min( info.m_iShots, GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) );
  2410. GiveReserveAmmo( AMMO_POSITION_PRIMARY, -info.m_iShots );
  2411. }
  2412. info.m_flDistance = MAX_TRACE_LENGTH;
  2413. info.m_iAmmoType = m_iPrimaryAmmoType;
  2414. info.m_iTracerFreq = 2;
  2415. #if !defined( CLIENT_DLL )
  2416. // Fire the bullets
  2417. info.m_vecSpread = pOperator->GetAttackSpread( this );
  2418. #else
  2419. //!!!HACKHACK - what does the client want this function for?
  2420. info.m_vecSpread = GetBulletSpread();
  2421. #endif // CLIENT_DLL
  2422. pOperator->FireBullets( info );
  2423. }
  2424. //-----------------------------------------------------------------------------
  2425. // Purpose: Called every frame to check if the weapon is going through transition animations
  2426. //-----------------------------------------------------------------------------
  2427. void CBaseCombatWeapon::MaintainIdealActivity( void )
  2428. {
  2429. // Must be transitioning
  2430. if ( GetActivity() != ACT_TRANSITION )
  2431. return;
  2432. // Must not be at our ideal already
  2433. if ( ( GetActivity() == m_IdealActivity ) && ( GetSequence() == m_nIdealSequence ) )
  2434. return;
  2435. // Must be finished with the current animation
  2436. if ( IsViewModelSequenceFinished() == false )
  2437. return;
  2438. // Move to the next animation towards our ideal
  2439. SendWeaponAnim( m_IdealActivity );
  2440. }
  2441. //-----------------------------------------------------------------------------
  2442. // Purpose: Sets the ideal activity for the weapon to be in, allowing for transitional animations in between
  2443. // Input : ideal - activity to end up at, ideally
  2444. //-----------------------------------------------------------------------------
  2445. bool CBaseCombatWeapon::SetIdealActivity( Activity ideal )
  2446. {
  2447. MDLCACHE_CRITICAL_SECTION();
  2448. int idealSequence = SelectWeightedSequence( ideal );
  2449. if ( idealSequence == -1 )
  2450. return false;
  2451. //Take the new activity
  2452. m_IdealActivity = ideal;
  2453. m_nIdealSequence = idealSequence;
  2454. //Find the next sequence in the potential chain of sequences leading to our ideal one
  2455. int nextSequence = FindTransitionSequence( GetSequence(), m_nIdealSequence, NULL );
  2456. // Don't use transitions when we're deploying
  2457. if ( ideal != ACT_VM_DRAW && ideal != ACT_VM_EMPTY_DRAW && IsWeaponVisible() && nextSequence != m_nIdealSequence )
  2458. {
  2459. //Set our activity to the next transitional animation
  2460. SetActivity( ACT_TRANSITION );
  2461. SetSequence( nextSequence );
  2462. SendViewModelAnim( nextSequence );
  2463. }
  2464. else
  2465. {
  2466. //Set our activity to the ideal
  2467. SetActivity( m_IdealActivity );
  2468. SetSequence( m_nIdealSequence );
  2469. SendViewModelAnim( m_nIdealSequence );
  2470. }
  2471. //Set the next time the weapon will idle
  2472. SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() );
  2473. return true;
  2474. }
  2475. //-----------------------------------------------------------------------------
  2476. // Returns information about the various control panels
  2477. //-----------------------------------------------------------------------------
  2478. void CBaseCombatWeapon::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName )
  2479. {
  2480. pPanelName = NULL;
  2481. }
  2482. //-----------------------------------------------------------------------------
  2483. // Returns information about the various control panels
  2484. //-----------------------------------------------------------------------------
  2485. void CBaseCombatWeapon::GetControlPanelClassName( int nPanelIndex, const char *&pPanelName )
  2486. {
  2487. pPanelName = "vgui_screen";
  2488. }
  2489. //-----------------------------------------------------------------------------
  2490. // Locking a weapon is an exclusive action. If you lock a weapon, that means
  2491. // you are preventing others from doing so for themselves.
  2492. //-----------------------------------------------------------------------------
  2493. void CBaseCombatWeapon::Lock( float lockTime, CBaseEntity *pLocker )
  2494. {
  2495. m_flUnlockTime = gpGlobals->curtime + lockTime;
  2496. m_hLocker.Set( pLocker );
  2497. }
  2498. //-----------------------------------------------------------------------------
  2499. // If I'm still locked for a period of time, tell everyone except the person
  2500. // that locked me that I'm not available.
  2501. //-----------------------------------------------------------------------------
  2502. bool CBaseCombatWeapon::IsLocked( CBaseEntity *pAsker )
  2503. {
  2504. return ( m_flUnlockTime > gpGlobals->curtime && m_hLocker != pAsker );
  2505. }
  2506. //-----------------------------------------------------------------------------
  2507. // Purpose:
  2508. // Input :
  2509. // Output :
  2510. //-----------------------------------------------------------------------------
  2511. Activity CBaseCombatWeapon::ActivityOverride( Activity baseAct, bool *pRequired )
  2512. {
  2513. acttable_t *pTable = ActivityList();
  2514. int actCount = ActivityListCount();
  2515. for ( int i = 0; i < actCount; i++, pTable++ )
  2516. {
  2517. if ( baseAct == pTable->baseAct )
  2518. {
  2519. if (pRequired)
  2520. {
  2521. *pRequired = pTable->required;
  2522. }
  2523. return (Activity)pTable->weaponAct;
  2524. }
  2525. }
  2526. return baseAct;
  2527. }
  2528. class CWeaponList : public CAutoGameSystem
  2529. {
  2530. public:
  2531. CWeaponList( char const *name ) : CAutoGameSystem( name )
  2532. {
  2533. }
  2534. virtual void LevelShutdownPostEntity()
  2535. {
  2536. m_list.Purge();
  2537. }
  2538. void AddWeapon( CBaseCombatWeapon *pWeapon )
  2539. {
  2540. m_list.AddToTail( pWeapon );
  2541. }
  2542. void RemoveWeapon( CBaseCombatWeapon *pWeapon )
  2543. {
  2544. m_list.FindAndRemove( pWeapon );
  2545. }
  2546. CUtlLinkedList< CBaseCombatWeapon * > m_list;
  2547. };
  2548. CWeaponList g_WeaponList( "CWeaponList" );
  2549. #ifndef CLIENT_DLL
  2550. void OnBaseCombatWeaponCreated( CBaseCombatWeapon *pWeapon )
  2551. {
  2552. g_WeaponList.AddWeapon( pWeapon );
  2553. }
  2554. void OnBaseCombatWeaponDestroyed( CBaseCombatWeapon *pWeapon )
  2555. {
  2556. g_WeaponList.RemoveWeapon( pWeapon );
  2557. }
  2558. #endif
  2559. #ifdef CLIENT_DLL
  2560. CUtlLinkedList< CBaseCombatWeapon * >& CBaseCombatWeapon::GetWeaponList( void )
  2561. {
  2562. return g_WeaponList.m_list;
  2563. }
  2564. #else
  2565. int CBaseCombatWeapon::GetAvailableWeaponsInBox( CBaseCombatWeapon **pList, int listMax, const Vector &mins, const Vector &maxs )
  2566. {
  2567. // linear search all weapons
  2568. int count = 0;
  2569. int index = g_WeaponList.m_list.Head();
  2570. while ( index != g_WeaponList.m_list.InvalidIndex() )
  2571. {
  2572. CBaseCombatWeapon *pWeapon = g_WeaponList.m_list[index];
  2573. // skip any held weapon
  2574. if ( !pWeapon->GetOwner() )
  2575. {
  2576. // restrict to mins/maxs
  2577. if ( IsPointInBox( pWeapon->GetAbsOrigin(), mins, maxs ) )
  2578. {
  2579. if ( count < listMax )
  2580. {
  2581. pList[count] = pWeapon;
  2582. count++;
  2583. }
  2584. }
  2585. }
  2586. index = g_WeaponList.m_list.Next( index );
  2587. }
  2588. return count;
  2589. }
  2590. #endif
  2591. #if defined( CLIENT_DLL )
  2592. BEGIN_PREDICTION_DATA( CBaseCombatWeapon )
  2593. DEFINE_PRED_FIELD( m_nNextThinkTick, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_NOERRORCHECK ),
  2594. // Networked
  2595. DEFINE_PRED_FIELD( m_hOwner, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
  2596. // DEFINE_FIELD( m_hWeaponFileInfo, FIELD_SHORT ),
  2597. DEFINE_PRED_FIELD( m_iState, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  2598. DEFINE_PRED_FIELD( m_iViewModelIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ),
  2599. DEFINE_PRED_FIELD( m_iWorldModelIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ),
  2600. DEFINE_PRED_FIELD( m_iWorldDroppedModelIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ),
  2601. DEFINE_PRED_FIELD_TOL( m_flNextPrimaryAttack, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
  2602. DEFINE_PRED_FIELD_TOL( m_flNextSecondaryAttack, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
  2603. DEFINE_PRED_FIELD_TOL( m_flTimeWeaponIdle, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
  2604. DEFINE_PRED_FIELD( m_iPrimaryAmmoType, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  2605. DEFINE_PRED_FIELD( m_iSecondaryAmmoType, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  2606. DEFINE_PRED_FIELD( m_iClip1, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  2607. DEFINE_PRED_FIELD( m_iClip2, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  2608. DEFINE_PRED_FIELD( m_nViewModelIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  2609. DEFINE_PRED_FIELD( m_iWeaponModule, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  2610. DEFINE_PRED_FIELD( m_iPrimaryReserveAmmoCount, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  2611. DEFINE_PRED_FIELD( m_iSecondaryReserveAmmoCount, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  2612. DEFINE_PRED_FIELD( m_iNumEmptyAttacks, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  2613. // Not networked
  2614. DEFINE_FIELD( m_bInReload, FIELD_BOOLEAN ),
  2615. DEFINE_FIELD( m_bFireOnEmpty, FIELD_BOOLEAN ),
  2616. DEFINE_FIELD( m_flNextEmptySoundTime, FIELD_FLOAT ),
  2617. DEFINE_FIELD( m_Activity, FIELD_INTEGER ),
  2618. DEFINE_FIELD( m_fFireDuration, FIELD_FLOAT ),
  2619. DEFINE_FIELD( m_iszName, FIELD_INTEGER ),
  2620. DEFINE_FIELD( m_bFiresUnderwater, FIELD_BOOLEAN ),
  2621. DEFINE_FIELD( m_bAltFiresUnderwater, FIELD_BOOLEAN ),
  2622. DEFINE_FIELD( m_fMinRange1, FIELD_FLOAT ),
  2623. DEFINE_FIELD( m_fMinRange2, FIELD_FLOAT ),
  2624. DEFINE_FIELD( m_fMaxRange1, FIELD_FLOAT ),
  2625. DEFINE_FIELD( m_fMaxRange2, FIELD_FLOAT ),
  2626. DEFINE_FIELD( m_bReloadsSingly, FIELD_BOOLEAN ),
  2627. DEFINE_FIELD( m_bRemoveable, FIELD_BOOLEAN ),
  2628. DEFINE_FIELD( m_iPrimaryAmmoCount, FIELD_INTEGER ),
  2629. DEFINE_FIELD( m_iSecondaryAmmoCount, FIELD_INTEGER ),
  2630. //DEFINE_PHYSPTR( m_pConstraint ),
  2631. // DEFINE_FIELD( m_iOldState, FIELD_INTEGER ),
  2632. // DEFINE_FIELD( m_bJustRestored, FIELD_BOOLEAN ),
  2633. // DEFINE_FIELD( m_OnPlayerPickup, COutputEvent ),
  2634. // DEFINE_FIELD( m_pConstraint, FIELD_INTEGER ),
  2635. END_PREDICTION_DATA()
  2636. #endif // ! CLIENT_DLL
  2637. // Special hack since we're aliasing the name C_BaseCombatWeapon with a macro on the client
  2638. IMPLEMENT_NETWORKCLASS_ALIASED( BaseCombatWeapon, DT_BaseCombatWeapon )
  2639. #if !defined( CLIENT_DLL )
  2640. //-----------------------------------------------------------------------------
  2641. // Purpose: Save Data for Base Weapon object
  2642. //-----------------------------------------------------------------------------//
  2643. BEGIN_DATADESC( CBaseCombatWeapon )
  2644. DEFINE_FIELD( m_flNextPrimaryAttack, FIELD_TIME ),
  2645. DEFINE_FIELD( m_flNextSecondaryAttack, FIELD_TIME ),
  2646. DEFINE_FIELD( m_flTimeWeaponIdle, FIELD_TIME ),
  2647. DEFINE_FIELD( m_bInReload, FIELD_BOOLEAN ),
  2648. DEFINE_FIELD( m_bFireOnEmpty, FIELD_BOOLEAN ),
  2649. DEFINE_FIELD( m_hOwner, FIELD_EHANDLE ),
  2650. DEFINE_FIELD( m_iState, FIELD_INTEGER ),
  2651. DEFINE_FIELD( m_iszName, FIELD_STRING ),
  2652. DEFINE_FIELD( m_iPrimaryAmmoType, FIELD_INTEGER ),
  2653. DEFINE_FIELD( m_iSecondaryAmmoType, FIELD_INTEGER ),
  2654. DEFINE_FIELD( m_iClip1, FIELD_INTEGER ),
  2655. DEFINE_FIELD( m_iClip2, FIELD_INTEGER ),
  2656. DEFINE_FIELD( m_bFiresUnderwater, FIELD_BOOLEAN ),
  2657. DEFINE_FIELD( m_bAltFiresUnderwater, FIELD_BOOLEAN ),
  2658. DEFINE_FIELD( m_fMinRange1, FIELD_FLOAT ),
  2659. DEFINE_FIELD( m_fMinRange2, FIELD_FLOAT ),
  2660. DEFINE_FIELD( m_fMaxRange1, FIELD_FLOAT ),
  2661. DEFINE_FIELD( m_fMaxRange2, FIELD_FLOAT ),
  2662. DEFINE_FIELD( m_iPrimaryAmmoCount, FIELD_INTEGER ),
  2663. DEFINE_FIELD( m_iSecondaryAmmoCount, FIELD_INTEGER ),
  2664. DEFINE_FIELD( m_nViewModelIndex, FIELD_INTEGER ),
  2665. DEFINE_FIELD( m_iWeaponModule, FIELD_INTEGER ),
  2666. // don't save these, init to 0 and regenerate
  2667. // DEFINE_FIELD( m_flNextEmptySoundTime, FIELD_TIME ),
  2668. // DEFINE_FIELD( m_Activity, FIELD_INTEGER ),
  2669. DEFINE_FIELD( m_nIdealSequence, FIELD_INTEGER ),
  2670. DEFINE_FIELD( m_IdealActivity, FIELD_INTEGER ),
  2671. DEFINE_FIELD( m_fFireDuration, FIELD_FLOAT ),
  2672. DEFINE_FIELD( m_bReloadsSingly, FIELD_BOOLEAN ),
  2673. DEFINE_FIELD( m_iSubType, FIELD_INTEGER ),
  2674. DEFINE_FIELD( m_bRemoveable, FIELD_BOOLEAN ),
  2675. DEFINE_FIELD( m_flUnlockTime, FIELD_TIME ),
  2676. DEFINE_FIELD( m_hLocker, FIELD_EHANDLE ),
  2677. // DEFINE_FIELD( m_iViewModelIndex, FIELD_INTEGER ),
  2678. // DEFINE_FIELD( m_iWorldModelIndex, FIELD_INTEGER ),
  2679. // DEFINE_FIELD( m_hWeaponFileInfo, ???? ),
  2680. DEFINE_PHYSPTR( m_pConstraint ),
  2681. DEFINE_FIELD( m_iReloadHudHintCount, FIELD_INTEGER ),
  2682. DEFINE_FIELD( m_iAltFireHudHintCount, FIELD_INTEGER ),
  2683. DEFINE_FIELD( m_bReloadHudHintDisplayed, FIELD_BOOLEAN ),
  2684. DEFINE_FIELD( m_bAltFireHudHintDisplayed, FIELD_BOOLEAN ),
  2685. DEFINE_FIELD( m_flHudHintPollTime, FIELD_TIME ),
  2686. DEFINE_FIELD( m_flHudHintMinDisplayTime, FIELD_TIME ),
  2687. // Just to quiet classcheck.. this field exists only on the client
  2688. // DEFINE_FIELD( m_iOldState, FIELD_INTEGER ),
  2689. // DEFINE_FIELD( m_bJustRestored, FIELD_BOOLEAN ),
  2690. // Function pointers
  2691. DEFINE_ENTITYFUNC( DefaultTouch ),
  2692. DEFINE_THINKFUNC( FallThink ),
  2693. DEFINE_THINKFUNC( Materialize ),
  2694. DEFINE_THINKFUNC( AttemptToMaterialize ),
  2695. DEFINE_THINKFUNC( DestroyItem ),
  2696. DEFINE_THINKFUNC( SetPickupTouch ),
  2697. DEFINE_THINKFUNC( HideThink ),
  2698. DEFINE_INPUTFUNC( FIELD_VOID, "HideWeapon", InputHideWeapon ),
  2699. // Outputs
  2700. DEFINE_OUTPUT( m_OnPlayerUse, "OnPlayerUse"),
  2701. DEFINE_OUTPUT( m_OnPlayerPickup, "OnPlayerPickup"),
  2702. DEFINE_OUTPUT( m_OnNPCPickup, "OnNPCPickup"),
  2703. DEFINE_OUTPUT( m_OnCacheInteraction, "OnCacheInteraction" ),
  2704. END_DATADESC()
  2705. //-----------------------------------------------------------------------------
  2706. // Purpose: Only send to local player if this weapon is the active weapon
  2707. // Input : *pStruct -
  2708. // *pVarData -
  2709. // *pRecipients -
  2710. // objectID -
  2711. // Output : void*
  2712. //-----------------------------------------------------------------------------
  2713. void* SendProxy_SendActiveLocalWeaponDataTable( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID )
  2714. {
  2715. // Get the weapon entity
  2716. CBaseCombatWeapon *pWeapon = (CBaseCombatWeapon*)pVarData;
  2717. if ( pWeapon )
  2718. {
  2719. // Only send this chunk of data to the player carrying this weapon
  2720. CBasePlayer *pPlayer = ToBasePlayer( pWeapon->GetOwner() );
  2721. if ( pPlayer /*&& pPlayer->GetActiveWeapon() == pWeapon*/ )
  2722. {
  2723. pRecipients->SetOnly( pPlayer->GetClientIndex() );
  2724. return (void*)pVarData;
  2725. }
  2726. }
  2727. return NULL;
  2728. }
  2729. REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_SendActiveLocalWeaponDataTable );
  2730. //-----------------------------------------------------------------------------
  2731. // Purpose: Only send the LocalWeaponData to the player carrying the weapon
  2732. //-----------------------------------------------------------------------------
  2733. void* SendProxy_SendLocalWeaponDataTable( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID )
  2734. {
  2735. // Get the weapon entity
  2736. CBaseCombatWeapon *pWeapon = (CBaseCombatWeapon*)pVarData;
  2737. if ( pWeapon )
  2738. {
  2739. // Only send this chunk of data to the player carrying this weapon
  2740. CBasePlayer *pPlayer = ToBasePlayer( pWeapon->GetOwner() );
  2741. if ( pPlayer )
  2742. {
  2743. pRecipients->SetOnly( pPlayer->GetClientIndex() );
  2744. return (void*)pVarData;
  2745. }
  2746. }
  2747. return NULL;
  2748. }
  2749. REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_SendLocalWeaponDataTable );
  2750. //-----------------------------------------------------------------------------
  2751. // Purpose: Only send to non-local players
  2752. //-----------------------------------------------------------------------------
  2753. void* SendProxy_SendNonLocalWeaponDataTable( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID )
  2754. {
  2755. pRecipients->SetAllRecipients();
  2756. CBaseCombatWeapon *pWeapon = (CBaseCombatWeapon*)pVarData;
  2757. if ( pWeapon )
  2758. {
  2759. CBasePlayer *pPlayer = ToBasePlayer( pWeapon->GetOwner() );
  2760. if ( pPlayer )
  2761. {
  2762. pRecipients->ClearRecipient( pPlayer->GetClientIndex() );
  2763. return ( void * )pVarData;
  2764. }
  2765. }
  2766. return NULL;
  2767. }
  2768. REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_SendNonLocalWeaponDataTable );
  2769. #endif
  2770. #if PREDICTION_ERROR_CHECK_LEVEL > 1
  2771. #define SendPropTime SendPropFloat
  2772. #define RecvPropTime RecvPropFloat
  2773. #endif
  2774. //-----------------------------------------------------------------------------
  2775. // Purpose: Propagation data for weapons. Only sent when a player's holding it.
  2776. //-----------------------------------------------------------------------------
  2777. BEGIN_NETWORK_TABLE_NOBASE( CBaseCombatWeapon, DT_LocalActiveWeaponData )
  2778. #if !defined( CLIENT_DLL )
  2779. SendPropTime( SENDINFO( m_flNextPrimaryAttack ) ),
  2780. SendPropTime( SENDINFO( m_flNextSecondaryAttack ) ),
  2781. SendPropInt( SENDINFO( m_nNextThinkTick ) ),
  2782. SendPropTime( SENDINFO( m_flTimeWeaponIdle ) ),
  2783. #if defined( TF_DLL )
  2784. SendPropExclude( "DT_AnimTimeMustBeFirst" , "m_flAnimTime" ),
  2785. #endif
  2786. #else
  2787. RecvPropTime( RECVINFO( m_flNextPrimaryAttack ) ),
  2788. RecvPropTime( RECVINFO( m_flNextSecondaryAttack ) ),
  2789. RecvPropInt( RECVINFO( m_nNextThinkTick ) ),
  2790. RecvPropTime( RECVINFO( m_flTimeWeaponIdle ) ),
  2791. #endif
  2792. END_NETWORK_TABLE()
  2793. //-----------------------------------------------------------------------------
  2794. // Purpose: Propagation data for weapons. Only sent when a player's holding it.
  2795. //-----------------------------------------------------------------------------
  2796. BEGIN_NETWORK_TABLE_NOBASE( CBaseCombatWeapon, DT_LocalWeaponData )
  2797. #if !defined( CLIENT_DLL )
  2798. SendPropInt( SENDINFO(m_iPrimaryAmmoType ), 8 ),
  2799. SendPropInt( SENDINFO(m_iSecondaryAmmoType ), 8 ),
  2800. SendPropInt( SENDINFO( m_nViewModelIndex ), VIEWMODEL_INDEX_BITS, SPROP_UNSIGNED ),
  2801. SendPropInt( SENDINFO( m_bFlipViewModel ) ),
  2802. SendPropInt( SENDINFO( m_iWeaponOrigin ) ),
  2803. SendPropInt( SENDINFO(m_iWeaponModule), 8),
  2804. #if defined( TF_DLL )
  2805. SendPropExclude( "DT_AnimTimeMustBeFirst" , "m_flAnimTime" ),
  2806. #endif
  2807. #else
  2808. RecvPropInt( RECVINFO(m_iPrimaryAmmoType )),
  2809. RecvPropInt( RECVINFO(m_iSecondaryAmmoType )),
  2810. RecvPropInt( RECVINFO( m_nViewModelIndex ) ),
  2811. RecvPropBool( RECVINFO( m_bFlipViewModel ) ),
  2812. RecvPropInt( RECVINFO( m_iWeaponOrigin ) ),
  2813. RecvPropInt( RECVINFO(m_iWeaponModule)),
  2814. #endif
  2815. END_NETWORK_TABLE()
  2816. #if defined( CLIENT_DLL )
  2817. void RecvProxy_State( const CRecvProxyData *pData, void *pStruct, void *pOut )
  2818. {
  2819. *(int *)pOut = pData->m_Value.m_Int;
  2820. ( (C_BaseEntity*) pStruct )->UpdateVisibility();
  2821. }
  2822. #endif
  2823. BEGIN_NETWORK_TABLE(CBaseCombatWeapon, DT_BaseCombatWeapon)
  2824. #if !defined( CLIENT_DLL )
  2825. SendPropDataTable("LocalWeaponData", 0, &REFERENCE_SEND_TABLE(DT_LocalWeaponData), SendProxy_SendLocalWeaponDataTable ),
  2826. SendPropDataTable("LocalActiveWeaponData", 0, &REFERENCE_SEND_TABLE(DT_LocalActiveWeaponData), SendProxy_SendActiveLocalWeaponDataTable ),
  2827. SendPropModelIndex( SENDINFO(m_iViewModelIndex) ),
  2828. SendPropModelIndex( SENDINFO(m_iWorldModelIndex) ),
  2829. SendPropModelIndex( SENDINFO(m_iWorldDroppedModelIndex) ),
  2830. SendPropInt( SENDINFO( m_iState ), 2, SPROP_UNSIGNED ),
  2831. SendPropEHandle( SENDINFO(m_hOwner) ),
  2832. SendPropIntWithMinusOneFlag( SENDINFO(m_iClip1 ), 8 ),
  2833. SendPropIntWithMinusOneFlag( SENDINFO(m_iClip2 ), 8 ),
  2834. SendPropInt( SENDINFO( m_iPrimaryReserveAmmoCount ), 10),
  2835. SendPropInt( SENDINFO( m_iSecondaryReserveAmmoCount), 10),
  2836. SendPropEHandle( SENDINFO(m_hWeaponWorldModel) ),
  2837. SendPropInt( SENDINFO( m_iNumEmptyAttacks ), 8 ),
  2838. #else
  2839. RecvPropDataTable("LocalWeaponData", 0, 0, &REFERENCE_RECV_TABLE(DT_LocalWeaponData)),
  2840. RecvPropDataTable("LocalActiveWeaponData", 0, 0, &REFERENCE_RECV_TABLE(DT_LocalActiveWeaponData)),
  2841. RecvPropInt( RECVINFO(m_iViewModelIndex)),
  2842. RecvPropInt( RECVINFO(m_iWorldModelIndex)),
  2843. RecvPropInt( RECVINFO(m_iWorldDroppedModelIndex)),
  2844. RecvPropInt( RECVINFO( m_iState ), 0, RecvProxy_State ),
  2845. RecvPropEHandle( RECVINFO(m_hOwner ) ),
  2846. RecvPropIntWithMinusOneFlag( RECVINFO(m_iClip1 )),
  2847. RecvPropIntWithMinusOneFlag( RECVINFO(m_iClip2 )),
  2848. RecvPropInt( RECVINFO( m_iPrimaryReserveAmmoCount)),
  2849. RecvPropInt( RECVINFO( m_iSecondaryReserveAmmoCount)),
  2850. RecvPropEHandle( RECVINFO(m_hWeaponWorldModel) ),
  2851. RecvPropInt( RECVINFO( m_iNumEmptyAttacks )),
  2852. #endif
  2853. END_NETWORK_TABLE()
  2854. // float CBaseCombatWeapon::GetAttributeFloat( const char* szAttribClassName ) const
  2855. // {
  2856. // return GetWpnData().GetAttributeFloat( szAttribClassName, GetEconItemView() );
  2857. // }
  2858. //
  2859. // int CBaseCombatWeapon::GetAttributeInt( const char* szAttribClassName ) const
  2860. // {
  2861. // return GetWpnData().GetAttributeInt( szAttribClassName, GetEconItemView() );
  2862. // }
  2863. //
  2864. // bool CBaseCombatWeapon::GetAttributeBool( const char* szAttribClassName ) const
  2865. // {
  2866. // return GetWpnData().GetAttributeBool( szAttribClassName, GetEconItemView() );
  2867. // }
  2868. const CEconItemView* CBaseCombatWeapon::GetEconItemView( void ) const
  2869. {
  2870. return nullptr;
  2871. }
  2872. CEconItemView* CBaseCombatWeapon::GetEconItemView( void )
  2873. {
  2874. return nullptr;
  2875. }
  2876. int CBaseCombatWeapon::GetReserveAmmoCount( AmmoPosition_t nAmmoPosition, CBaseCombatCharacter * pForcedOwner/* = NULL*/ )
  2877. {
  2878. // LEGACY SUPPORT HERE
  2879. // Except for exhaustible weapons ( i.e. grenades ) we now store ammo on the weapon and not the player
  2880. bool bForceSetAmmoOnPlayer = pForcedOwner ? true : false;
  2881. CBaseCombatCharacter * pPlayer = pForcedOwner ? pForcedOwner : GetOwner();
  2882. if ( pPlayer )
  2883. {
  2884. int nAmmoType = -1;
  2885. switch ( nAmmoPosition )
  2886. {
  2887. case AMMO_POSITION_PRIMARY: nAmmoType = GetPrimaryAmmoType(); break;
  2888. case AMMO_POSITION_SECONDARY: nAmmoType = GetSecondaryAmmoType(); break;
  2889. }
  2890. if ( nAmmoType > -1 )
  2891. {
  2892. if ( pPlayer->GetAmmoCount( nAmmoType ) || bForceSetAmmoOnPlayer )
  2893. return pPlayer->GetAmmoCount( nAmmoType );
  2894. }
  2895. }
  2896. // /LEGACY
  2897. switch( nAmmoPosition )
  2898. {
  2899. case AMMO_POSITION_PRIMARY: return m_iPrimaryReserveAmmoCount;
  2900. case AMMO_POSITION_SECONDARY: return m_iSecondaryReserveAmmoCount;
  2901. default: return -1;
  2902. }
  2903. }
  2904. int CBaseCombatWeapon::SetReserveAmmoCount( AmmoPosition_t nAmmoPosition, int nCount, bool bSuppressSound /* = false */, CBaseCombatCharacter * pForcedOwner/* = NULL*/ )
  2905. {
  2906. int iAdd = 0;
  2907. // LEGACY SUPPORT HERE
  2908. // Except for exhaustible weapons ( i.e. grenades ) we now store ammo on the weapon and not the player
  2909. bool bForceSetAmmoOnPlayer = pForcedOwner ? true : false;
  2910. CBaseCombatCharacter * pPlayer = pForcedOwner ? pForcedOwner : GetOwner();
  2911. if ( pPlayer )
  2912. {
  2913. int nAmmoType = -1;
  2914. switch ( nAmmoPosition )
  2915. {
  2916. case AMMO_POSITION_PRIMARY: nAmmoType = GetPrimaryAmmoType(); break;
  2917. case AMMO_POSITION_SECONDARY: nAmmoType = GetSecondaryAmmoType(); break;
  2918. }
  2919. if ( nAmmoType > -1 )
  2920. {
  2921. // use player ammo if a player entity was passed in or if there already is ammo in this position
  2922. if ( pPlayer->GetAmmoCount( nAmmoType ) || bForceSetAmmoOnPlayer )
  2923. {
  2924. int iMax = GetAmmoDef()->MaxCarry( nAmmoType, pPlayer );
  2925. iAdd = MIN( nCount, iMax - pPlayer->GetAmmoCount( nAmmoType ) );
  2926. int iTotal = MIN( nCount, iMax );
  2927. pPlayer->SetAmmoCount( iTotal, nAmmoType );
  2928. return iAdd;
  2929. }
  2930. }
  2931. }
  2932. // /LEGACY
  2933. iAdd = MIN( nCount, GetReserveAmmoMax( nAmmoPosition ) - GetReserveAmmoCount( nAmmoPosition ) );
  2934. switch( nAmmoPosition )
  2935. {
  2936. case AMMO_POSITION_PRIMARY: m_iPrimaryReserveAmmoCount = MIN( nCount, GetReserveAmmoMax( AMMO_POSITION_PRIMARY ) ); break;
  2937. case AMMO_POSITION_SECONDARY: m_iSecondaryReserveAmmoCount = MIN( nCount, GetReserveAmmoMax( AMMO_POSITION_SECONDARY ) ); break;
  2938. default: return 0;
  2939. }
  2940. // Ammo pickup sound
  2941. if ( !bSuppressSound )
  2942. {
  2943. EmitSound( "BaseCombatCharacter.AmmoPickup" );
  2944. }
  2945. return iAdd;
  2946. }
  2947. int CBaseCombatWeapon::GiveReserveAmmo( AmmoPosition_t nAmmoPosition, int nCount, bool bSuppressSound /* = false */, CBaseCombatCharacter * pForcedOwner/* = NULL*/ )
  2948. {
  2949. if ( nCount <= 0 )
  2950. {
  2951. extern ConVar sv_infinite_ammo;
  2952. if ( sv_infinite_ammo.GetInt() == 2 ) // infinite total ammo but magazine reloads are still required.
  2953. return 0;
  2954. // supress ammo pickup sound when we're depleting ammo
  2955. bSuppressSound = true;
  2956. }
  2957. return SetReserveAmmoCount( nAmmoPosition, GetReserveAmmoCount( nAmmoPosition, pForcedOwner ) + nCount, bSuppressSound, pForcedOwner );
  2958. }
  2959. int CBaseCombatWeapon::GetReserveAmmoMax( AmmoPosition_t nAmmoPosition ) const
  2960. {
  2961. // LEGACY SUPPORT HERE
  2962. // Except for exhaustible weapons ( i.e. grenades ) we now store ammo on the weapon and not the player
  2963. CBaseCombatCharacter * pPlayer = GetOwner();
  2964. if ( pPlayer )
  2965. {
  2966. int nAmmoType = -1;
  2967. switch ( nAmmoPosition )
  2968. {
  2969. case AMMO_POSITION_PRIMARY: nAmmoType = GetPrimaryAmmoType(); break;
  2970. case AMMO_POSITION_SECONDARY: nAmmoType = GetSecondaryAmmoType(); break;
  2971. }
  2972. if ( nAmmoType > -1 )
  2973. {
  2974. // use player ammo if there already is ammo in this position
  2975. if ( pPlayer->GetAmmoCount( nAmmoType ) )
  2976. {
  2977. return GetAmmoDef()->MaxCarry( nAmmoType, pPlayer );
  2978. }
  2979. }
  2980. }
  2981. switch( nAmmoPosition )
  2982. {
  2983. case AMMO_POSITION_PRIMARY: return GetWpnData().GetPrimaryReserveAmmoMax( GetEconItemView() );
  2984. case AMMO_POSITION_SECONDARY: return GetWpnData().GetSecondaryReserveAmmoMax( GetEconItemView() );
  2985. default: Assert(0); return 0;
  2986. }
  2987. }