Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1416 lines
36 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "in_buttons.h"
  9. #include "takedamageinfo.h"
  10. #include "weapon_dodbase.h"
  11. #include "ammodef.h"
  12. #include "dod_gamerules.h"
  13. #ifdef CLIENT_DLL
  14. extern IVModelInfoClient* modelinfo;
  15. #else
  16. extern IVModelInfo* modelinfo;
  17. #include "ilagcompensationmanager.h"
  18. #endif
  19. #if defined( CLIENT_DLL )
  20. #include "vgui/ISurface.h"
  21. #include "vgui_controls/Controls.h"
  22. #include "c_dod_player.h"
  23. #include "hud_crosshair.h"
  24. #include "SoundEmitterSystem/isoundemittersystembase.h"
  25. #else
  26. #include "dod_player.h"
  27. #endif
  28. #include "effect_dispatch_data.h"
  29. // ----------------------------------------------------------------------------- //
  30. // Global functions.
  31. // ----------------------------------------------------------------------------- //
  32. bool IsAmmoType( int iAmmoType, const char *pAmmoName )
  33. {
  34. return GetAmmoDef()->Index( pAmmoName ) == iAmmoType;
  35. }
  36. //--------------------------------------------------------------------------------------------------------
  37. //
  38. // Given a weapon ID, return its alias
  39. //
  40. const char *WeaponIDToAlias( int id )
  41. {
  42. if ( (id >= WEAPON_MAX) || (id < 0) )
  43. return NULL;
  44. return s_WeaponAliasInfo[id];
  45. }
  46. // ----------------------------------------------------------------------------- //
  47. // CWeaponDODBase tables.
  48. // ----------------------------------------------------------------------------- //
  49. IMPLEMENT_NETWORKCLASS_ALIASED( WeaponDODBase, DT_WeaponDODBase )
  50. BEGIN_NETWORK_TABLE( CWeaponDODBase, DT_WeaponDODBase )
  51. #ifdef CLIENT_DLL
  52. RecvPropInt( RECVINFO(m_iReloadModelIndex) ),
  53. RecvPropVector( RECVINFO( m_vInitialDropVelocity ) ),
  54. RecvPropTime( RECVINFO( m_flSmackTime ) )
  55. #else
  56. SendPropVector( SENDINFO( m_vInitialDropVelocity ),
  57. 20, // nbits
  58. 0, // flags
  59. -3000, // low value
  60. 3000 // high value
  61. ),
  62. SendPropModelIndex( SENDINFO(m_iReloadModelIndex) ),
  63. SendPropTime( SENDINFO( m_flSmackTime ) )
  64. #endif
  65. END_NETWORK_TABLE()
  66. LINK_ENTITY_TO_CLASS( weapon_dod_base, CWeaponDODBase );
  67. #ifdef GAME_DLL
  68. BEGIN_DATADESC( CWeaponDODBase )
  69. DEFINE_FUNCTION( FallThink ),
  70. DEFINE_FUNCTION( Die ),
  71. DEFINE_FUNCTION( Smack )
  72. END_DATADESC()
  73. #else
  74. BEGIN_PREDICTION_DATA( CWeaponDODBase )
  75. DEFINE_PRED_FIELD( m_flSmackTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), // for rifle melee attacks
  76. DEFINE_FIELD( m_bInAttack, FIELD_BOOLEAN )
  77. END_PREDICTION_DATA()
  78. #endif
  79. Vector head_hull_mins( -16, -16, -18 );
  80. Vector head_hull_maxs( 16, 16, 18 );
  81. void FindHullIntersection( const Vector &vecSrc, trace_t &tr, const Vector &mins, const Vector &maxs, CBaseEntity *pEntity )
  82. {
  83. int i, j, k;
  84. float distance;
  85. Vector minmaxs[2] = {mins, maxs};
  86. trace_t tmpTrace;
  87. Vector vecHullEnd = tr.endpos;
  88. Vector vecEnd;
  89. CTraceFilterSimple filter( pEntity, COLLISION_GROUP_NONE );
  90. distance = 1e6f;
  91. vecHullEnd = vecSrc + ((vecHullEnd - vecSrc)*2);
  92. UTIL_TraceLine( vecSrc, vecHullEnd, MASK_SOLID, &filter, &tmpTrace );
  93. if ( tmpTrace.fraction < 1.0 )
  94. {
  95. tr = tmpTrace;
  96. return;
  97. }
  98. for ( i = 0; i < 2; i++ )
  99. {
  100. for ( j = 0; j < 2; j++ )
  101. {
  102. for ( k = 0; k < 2; k++ )
  103. {
  104. vecEnd.x = vecHullEnd.x + minmaxs[i][0];
  105. vecEnd.y = vecHullEnd.y + minmaxs[j][1];
  106. vecEnd.z = vecHullEnd.z + minmaxs[k][2];
  107. UTIL_TraceLine( vecSrc, vecEnd, MASK_SOLID, &filter, &tmpTrace );
  108. if ( tmpTrace.fraction < 1.0 )
  109. {
  110. float thisDistance = (tmpTrace.endpos - vecSrc).Length();
  111. if ( thisDistance < distance )
  112. {
  113. tr = tmpTrace;
  114. distance = thisDistance;
  115. }
  116. }
  117. }
  118. }
  119. }
  120. }
  121. // ----------------------------------------------------------------------------- //
  122. // CWeaponDODBase implementation.
  123. // ----------------------------------------------------------------------------- //
  124. CWeaponDODBase::CWeaponDODBase()
  125. {
  126. SetPredictionEligible( true );
  127. m_bInAttack = false;
  128. m_iAltFireHint = 0;
  129. AddSolidFlags( FSOLID_TRIGGER ); // Nothing collides with these but it gets touches.
  130. m_flNextPrimaryAttack = 0;
  131. }
  132. bool CWeaponDODBase::IsPredicted() const
  133. {
  134. return true;
  135. }
  136. bool CWeaponDODBase::PlayEmptySound()
  137. {
  138. CPASAttenuationFilter filter( this );
  139. filter.UsePredictionRules();
  140. EmitSound( filter, entindex(), "Default.ClipEmpty_Rifle" );
  141. return false;
  142. }
  143. CBasePlayer* CWeaponDODBase::GetPlayerOwner() const
  144. {
  145. return dynamic_cast< CBasePlayer* >( GetOwner() );
  146. }
  147. CDODPlayer* CWeaponDODBase::GetDODPlayerOwner() const
  148. {
  149. return dynamic_cast< CDODPlayer* >( GetOwner() );
  150. }
  151. bool CWeaponDODBase::SendWeaponAnim( int iActivity )
  152. {
  153. return BaseClass::SendWeaponAnim( iActivity );
  154. }
  155. bool CWeaponDODBase::CanAttack( void )
  156. {
  157. CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
  158. if ( pPlayer )
  159. {
  160. return pPlayer->CanAttack();
  161. }
  162. return false;
  163. }
  164. bool CWeaponDODBase::ShouldAutoReload( void )
  165. {
  166. CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
  167. if ( pPlayer )
  168. {
  169. return pPlayer->ShouldAutoReload();
  170. }
  171. return false;
  172. }
  173. void CWeaponDODBase::ItemPostFrame()
  174. {
  175. if ( m_flSmackTime > 0 && gpGlobals->curtime > m_flSmackTime )
  176. {
  177. Smack();
  178. m_flSmackTime = -1;
  179. }
  180. CBasePlayer *pPlayer = GetPlayerOwner();
  181. if ( !pPlayer )
  182. return;
  183. #ifdef _DEBUG
  184. CDODGameRules *mp = DODGameRules();
  185. #endif
  186. assert( mp );
  187. if ((m_bInReload) && (pPlayer->m_flNextAttack <= gpGlobals->curtime))
  188. {
  189. // complete the reload.
  190. int j = MIN( GetMaxClip1() - m_iClip1, pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) );
  191. // Add them to the clip
  192. m_iClip1 += j;
  193. pPlayer->RemoveAmmo( j, m_iPrimaryAmmoType );
  194. m_bInReload = false;
  195. FinishReload();
  196. }
  197. if ((pPlayer->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime))
  198. {
  199. if ( m_iClip2 != -1 && !pPlayer->GetAmmoCount( GetSecondaryAmmoType() ) )
  200. {
  201. m_bFireOnEmpty = TRUE;
  202. }
  203. SecondaryAttack();
  204. pPlayer->m_nButtons &= ~IN_ATTACK2;
  205. }
  206. else if ((pPlayer->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime ) && !m_bInAttack )
  207. {
  208. if ( (m_iClip1 == 0/* && pszAmmo1()*/) || (GetMaxClip1() == -1 && !pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) ) )
  209. {
  210. m_bFireOnEmpty = TRUE;
  211. }
  212. if( CanAttack() )
  213. PrimaryAttack();
  214. }
  215. else if ( pPlayer->m_nButtons & IN_RELOAD && GetMaxClip1() != WEAPON_NOCLIP && !m_bInReload && m_flNextPrimaryAttack < gpGlobals->curtime)
  216. {
  217. // reload when reload is pressed, or if no buttons are down and weapon is empty.
  218. Reload();
  219. }
  220. else if ( !(pPlayer->m_nButtons & (IN_ATTACK|IN_ATTACK2) ) )
  221. {
  222. // no fire buttons down
  223. m_bFireOnEmpty = false;
  224. m_bInAttack = false; //reset semi-auto
  225. if ( !IsUseable() && m_flNextPrimaryAttack < gpGlobals->curtime )
  226. {
  227. // Intentionally blank -- used to switch weapons here
  228. }
  229. else if( ShouldAutoReload() )
  230. {
  231. // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
  232. if ( m_iClip1 == 0 && !(GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->curtime )
  233. {
  234. Reload();
  235. return;
  236. }
  237. }
  238. WeaponIdle( );
  239. return;
  240. }
  241. }
  242. void CWeaponDODBase::WeaponIdle()
  243. {
  244. if (m_flTimeWeaponIdle > gpGlobals->curtime)
  245. return;
  246. SendWeaponAnim( GetIdleActivity() );
  247. m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
  248. }
  249. Activity CWeaponDODBase::GetIdleActivity( void )
  250. {
  251. return ACT_VM_IDLE;
  252. }
  253. const CDODWeaponInfo &CWeaponDODBase::GetDODWpnData() const
  254. {
  255. const FileWeaponInfo_t *pWeaponInfo = &GetWpnData();
  256. const CDODWeaponInfo *pDODInfo;
  257. #ifdef _DEBUG
  258. pDODInfo = dynamic_cast< const CDODWeaponInfo* >( pWeaponInfo );
  259. Assert( pDODInfo );
  260. #else
  261. pDODInfo = static_cast< const CDODWeaponInfo* >( pWeaponInfo );
  262. #endif
  263. return *pDODInfo;
  264. }
  265. //-----------------------------------------------------------------------------
  266. // Purpose:
  267. //-----------------------------------------------------------------------------
  268. const char *CWeaponDODBase::GetViewModel( int /*viewmodelindex = 0 -- this is ignored in the base class here*/ ) const
  269. {
  270. if ( GetPlayerOwner() == NULL )
  271. {
  272. return BaseClass::GetViewModel();
  273. }
  274. return GetWpnData().szViewModel;
  275. }
  276. void CWeaponDODBase::Precache( void )
  277. {
  278. // precache base first, it loads weapon scripts
  279. BaseClass::Precache();
  280. PrecacheScriptSound( "Default.ClipEmpty_Rifle" );
  281. PrecacheParticleSystem( "muzzle_pistols" );
  282. PrecacheParticleSystem( "muzzle_fullyautomatic" );
  283. PrecacheParticleSystem( "muzzle_rifles" );
  284. PrecacheParticleSystem( "muzzle_rockets" );
  285. PrecacheParticleSystem( "muzzle_mg42" );
  286. PrecacheParticleSystem( "view_muzzle_pistols" );
  287. PrecacheParticleSystem( "view_muzzle_fullyautomatic" );
  288. PrecacheParticleSystem( "view_muzzle_rifles" );
  289. PrecacheParticleSystem( "view_muzzle_rockets" );
  290. PrecacheParticleSystem( "view_muzzle_mg42" );
  291. const CDODWeaponInfo &info = GetDODWpnData();
  292. int iWpnNameLen = Q_strlen(info.m_szReloadModel);
  293. #ifdef DEBUG
  294. // Make sure that if we declare an alt weapon, that we have criteria to show it
  295. // and vice-versa
  296. //Assert( ((info.m_iAltWpnCriteria & (ALTWPN_CRITERIA_RELOADING | ALTWPN_CRITERIA_FIRING)) > 0 ) ==
  297. // (iWpnNameLen > 0) );
  298. #endif
  299. if( iWpnNameLen > 0 )
  300. m_iReloadModelIndex = CBaseEntity::PrecacheModel( info.m_szReloadModel );
  301. }
  302. bool CWeaponDODBase::DefaultDeploy( char *szViewModel, char *szWeaponModel, int iActivity, char *szAnimExt )
  303. {
  304. CBasePlayer *pOwner = GetPlayerOwner();
  305. if ( !pOwner )
  306. {
  307. return false;
  308. }
  309. pOwner->SetAnimationExtension( szAnimExt );
  310. SetViewModel();
  311. SendWeaponAnim( iActivity );
  312. pOwner->SetNextAttack( gpGlobals->curtime + SequenceDuration() );
  313. m_flNextPrimaryAttack = MAX( m_flNextPrimaryAttack, gpGlobals->curtime );
  314. m_flNextSecondaryAttack = gpGlobals->curtime;
  315. SetWeaponVisible( true );
  316. SetWeaponModelIndex( szWeaponModel );
  317. CBaseViewModel *vm = pOwner->GetViewModel( m_nViewModelIndex );
  318. Assert( vm );
  319. if( vm )
  320. {
  321. //set sleeves to proper team
  322. switch( pOwner->GetTeamNumber() )
  323. {
  324. case TEAM_ALLIES:
  325. vm->m_nSkin = SLEEVE_ALLIES;
  326. break;
  327. case TEAM_AXIS:
  328. vm->m_nSkin = SLEEVE_AXIS;
  329. break;
  330. default:
  331. Assert( !"TEAM_UNASSIGNED or spectator getting a view model assigned" );
  332. break;
  333. }
  334. }
  335. return true;
  336. }
  337. void CWeaponDODBase::SetWeaponModelIndex( const char *pName )
  338. {
  339. m_iWorldModelIndex = modelinfo->GetModelIndex( pName );
  340. }
  341. bool CWeaponDODBase::CanBeSelected( void )
  342. {
  343. if ( !VisibleInWeaponSelection() )
  344. return false;
  345. return true;
  346. }
  347. bool CWeaponDODBase::CanDeploy( void )
  348. {
  349. return BaseClass::CanDeploy();
  350. }
  351. bool CWeaponDODBase::CanHolster( void )
  352. {
  353. return BaseClass::CanHolster();
  354. }
  355. void CWeaponDODBase::Drop( const Vector &vecVelocity )
  356. {
  357. #ifndef CLIENT_DLL
  358. if ( m_iAltFireHint )
  359. {
  360. CDODPlayer *pPlayer = GetDODPlayerOwner();
  361. if ( pPlayer )
  362. {
  363. pPlayer->StopHintTimer( m_iAltFireHint );
  364. }
  365. }
  366. #endif
  367. // cancel any reload in progress
  368. m_bInReload = false;
  369. m_flSmackTime = -1;
  370. m_vInitialDropVelocity = vecVelocity;
  371. BaseClass::Drop( m_vInitialDropVelocity );
  372. }
  373. bool CWeaponDODBase::Holster( CBaseCombatWeapon *pSwitchingTo )
  374. {
  375. #ifndef CLIENT_DLL
  376. CDODPlayer *pPlayer = GetDODPlayerOwner();
  377. if ( pPlayer )
  378. {
  379. pPlayer->SetFOV( pPlayer, 0 ); // reset the default FOV.
  380. if ( m_iAltFireHint )
  381. {
  382. pPlayer->StopHintTimer( m_iAltFireHint );
  383. }
  384. }
  385. #endif
  386. m_bInReload = false;
  387. m_flSmackTime = -1;
  388. return BaseClass::Holster( pSwitchingTo );
  389. }
  390. bool CWeaponDODBase::Deploy()
  391. {
  392. #ifndef CLIENT_DLL
  393. CDODPlayer *pPlayer = GetDODPlayerOwner();
  394. if ( pPlayer )
  395. {
  396. pPlayer->SetFOV( pPlayer, 0 );
  397. if ( m_iAltFireHint )
  398. {
  399. pPlayer->StartHintTimer( m_iAltFireHint );
  400. }
  401. }
  402. #endif
  403. return BaseClass::Deploy();
  404. }
  405. #ifdef CLIENT_DLL
  406. void CWeaponDODBase::PostDataUpdate( DataUpdateType_t updateType )
  407. {
  408. // We need to do this before the C_BaseAnimating code starts to drive
  409. // clientside animation sequences on this model, which will be using bad sequences for the world model.
  410. int iDesiredModelIndex = 0;
  411. C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer();
  412. if ( localplayer && localplayer == GetOwner() && !C_BasePlayer::ShouldDrawLocalPlayer() ) // FIXME: use localplayer->ShouldDrawThisPlayer() instead.
  413. {
  414. iDesiredModelIndex = m_iViewModelIndex;
  415. }
  416. else
  417. {
  418. iDesiredModelIndex = GetWorldModelIndex();
  419. // Our world models never animate
  420. SetSequence( 0 );
  421. }
  422. if ( GetModelIndex() != iDesiredModelIndex )
  423. {
  424. SetModelIndex( iDesiredModelIndex );
  425. }
  426. BaseClass::PostDataUpdate( updateType );
  427. }
  428. void CWeaponDODBase::OnDataChanged( DataUpdateType_t type )
  429. {
  430. if ( m_iState == WEAPON_NOT_CARRIED && m_iOldState != WEAPON_NOT_CARRIED )
  431. {
  432. // we are being notified of the weapon being dropped
  433. // add an interpolation history so the movement is smoother
  434. // Now stick our initial velocity into the interpolation history
  435. CInterpolatedVar< Vector > &interpolator = GetOriginInterpolator();
  436. interpolator.ClearHistory();
  437. float changeTime = GetLastChangeTime( LATCH_SIMULATION_VAR );
  438. // Add a sample 1 second back.
  439. Vector vCurOrigin = GetLocalOrigin() - m_vInitialDropVelocity;
  440. interpolator.AddToHead( changeTime - 1.0, &vCurOrigin, false );
  441. // Add the current sample.
  442. vCurOrigin = GetLocalOrigin();
  443. interpolator.AddToHead( changeTime, &vCurOrigin, false );
  444. Vector estVel;
  445. EstimateAbsVelocity( estVel );
  446. /*Msg( "estimated velocity ( %.1f %.1f %.1f ) initial velocity ( %.1f %.1f %.1f )\n",
  447. estVel.x,
  448. estVel.y,
  449. estVel.z,
  450. m_vInitialDropVelocity.m_Value.x,
  451. m_vInitialDropVelocity.m_Value.y,
  452. m_vInitialDropVelocity.m_Value.z );*/
  453. OnWeaponDropped();
  454. }
  455. BaseClass::OnDataChanged( type );
  456. if ( GetPredictable() && !ShouldPredict() )
  457. ShutdownPredictable();
  458. }
  459. int CWeaponDODBase::GetWorldModelIndex( void )
  460. {
  461. if( m_bUseAltWeaponModel && GetOwner() != NULL )
  462. return m_iReloadModelIndex;
  463. else
  464. return m_iWorldModelIndex;
  465. }
  466. bool CWeaponDODBase::ShouldPredict()
  467. {
  468. if ( GetOwner() && GetOwner() == C_BasePlayer::GetLocalPlayer() )
  469. return true;
  470. return BaseClass::ShouldPredict();
  471. }
  472. void CWeaponDODBase::ProcessMuzzleFlashEvent()
  473. {
  474. CDODPlayer *pPlayer = GetDODPlayerOwner();
  475. if ( pPlayer )
  476. pPlayer->ProcessMuzzleFlashEvent();
  477. BaseClass::ProcessMuzzleFlashEvent();
  478. }
  479. #else
  480. //-----------------------------------------------------------------------------
  481. // Purpose: Get the accuracy derived from weapon and player, and return it
  482. //-----------------------------------------------------------------------------
  483. const Vector& CWeaponDODBase::GetBulletSpread()
  484. {
  485. static Vector cone = VECTOR_CONE_8DEGREES;
  486. return cone;
  487. }
  488. //-----------------------------------------------------------------------------
  489. // Purpose:
  490. //-----------------------------------------------------------------------------
  491. void CWeaponDODBase::ItemBusyFrame()
  492. {
  493. if( ShouldAutoReload() && !m_bInReload )
  494. {
  495. // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
  496. if ( m_iClip1 == 0 && !(GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->curtime )
  497. {
  498. Reload();
  499. }
  500. }
  501. BaseClass::ItemBusyFrame();
  502. }
  503. //-----------------------------------------------------------------------------
  504. // Purpose: Match the anim speed to the weapon speed while crouching
  505. //-----------------------------------------------------------------------------
  506. float CWeaponDODBase::GetDefaultAnimSpeed()
  507. {
  508. return 1.0;
  509. }
  510. bool CWeaponDODBase::ShouldRemoveOnRoundRestart()
  511. {
  512. if ( GetPlayerOwner() )
  513. return false;
  514. else
  515. return true;
  516. }
  517. //=========================================================
  518. // Materialize - make a CWeaponDODBase visible and tangible
  519. //=========================================================
  520. void CWeaponDODBase::Materialize()
  521. {
  522. if ( IsEffectActive( EF_NODRAW ) )
  523. {
  524. RemoveEffects( EF_NODRAW );
  525. DoMuzzleFlash();
  526. }
  527. AddSolidFlags( FSOLID_TRIGGER );
  528. SetThink (&CWeaponDODBase::SUB_Remove);
  529. SetNextThink( gpGlobals->curtime + 1 );
  530. }
  531. //=========================================================
  532. // AttemptToMaterialize - the item is trying to rematerialize,
  533. // should it do so now or wait longer?
  534. //=========================================================
  535. void CWeaponDODBase::AttemptToMaterialize()
  536. {
  537. float time = g_pGameRules->FlWeaponTryRespawn( this );
  538. if ( time == 0 )
  539. {
  540. Materialize();
  541. return;
  542. }
  543. SetNextThink( gpGlobals->curtime + time );
  544. }
  545. //=========================================================
  546. // CheckRespawn - a player is taking this weapon, should
  547. // it respawn?
  548. //=========================================================
  549. void CWeaponDODBase::CheckRespawn()
  550. {
  551. //GOOSEMAN : Do not respawn weapons!
  552. return;
  553. }
  554. //=========================================================
  555. // Respawn- this item is already in the world, but it is
  556. // invisible and intangible. Make it visible and tangible.
  557. //=========================================================
  558. CBaseEntity* CWeaponDODBase::Respawn()
  559. {
  560. // make a copy of this weapon that is invisible and inaccessible to players (no touch function). The weapon spawn/respawn code
  561. // will decide when to make the weapon visible and touchable.
  562. CBaseEntity *pNewWeapon = CBaseEntity::Create( GetClassname(), g_pGameRules->VecWeaponRespawnSpot( this ), GetAbsAngles(), GetOwner() );
  563. if ( pNewWeapon )
  564. {
  565. pNewWeapon->AddEffects( EF_NODRAW );// invisible for now
  566. pNewWeapon->SetTouch( NULL );// no touch
  567. pNewWeapon->SetThink( &CWeaponDODBase::AttemptToMaterialize );
  568. UTIL_DropToFloor( this, MASK_SOLID );
  569. // not a typo! We want to know when the weapon the player just picked up should respawn! This new entity we created is the replacement,
  570. // but when it should respawn is based on conditions belonging to the weapon that was taken.
  571. pNewWeapon->SetNextThink( gpGlobals->curtime + g_pGameRules->FlWeaponRespawnTime( this ) );
  572. }
  573. else
  574. {
  575. Msg( "Respawn failed to create %s!\n", GetClassname() );
  576. }
  577. return pNewWeapon;
  578. }
  579. bool CWeaponDODBase::Reload()
  580. {
  581. return BaseClass::Reload();
  582. }
  583. void CWeaponDODBase::Spawn()
  584. {
  585. BaseClass::Spawn();
  586. // Set this here to allow players to shoot dropped weapons
  587. SetCollisionGroup( COLLISION_GROUP_WEAPON );
  588. SetExtraAmmoCount(0); //Start with no additional ammo
  589. CollisionProp()->UseTriggerBounds( true, 10.0f );
  590. }
  591. void CWeaponDODBase::SetDieThink( bool bDie )
  592. {
  593. if( bDie )
  594. SetContextThink( &CWeaponDODBase::Die, gpGlobals->curtime + 45.0f, "DieContext" );
  595. else
  596. SetContextThink( NULL, gpGlobals->curtime, "DieContext" );
  597. }
  598. void CWeaponDODBase::Die( void )
  599. {
  600. UTIL_Remove( this );
  601. }
  602. #endif
  603. void CWeaponDODBase::OnPickedUp( CBaseCombatCharacter *pNewOwner )
  604. {
  605. BaseClass::OnPickedUp( pNewOwner );
  606. #if !defined( CLIENT_DLL )
  607. SetDieThink( false );
  608. #endif
  609. }
  610. bool CWeaponDODBase::DefaultReload( int iClipSize1, int iClipSize2, int iActivity )
  611. {
  612. CBaseCombatCharacter *pOwner = GetOwner();
  613. if (!pOwner)
  614. return false;
  615. // If I don't have any spare ammo, I can't reload
  616. if ( pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
  617. return false;
  618. bool bReload = false;
  619. // If you don't have clips, then don't try to reload them.
  620. if ( UsesClipsForAmmo1() )
  621. {
  622. // need to reload primary clip?
  623. int primary = min(iClipSize1 - m_iClip1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));
  624. if ( primary != 0 )
  625. {
  626. bReload = true;
  627. }
  628. }
  629. if ( UsesClipsForAmmo2() )
  630. {
  631. // need to reload secondary clip?
  632. int secondary = min(iClipSize2 - m_iClip2, pOwner->GetAmmoCount(m_iSecondaryAmmoType));
  633. if ( secondary != 0 )
  634. {
  635. bReload = true;
  636. }
  637. }
  638. if ( !bReload )
  639. return false;
  640. CDODPlayer *pPlayer = GetDODPlayerOwner();
  641. if ( pPlayer )
  642. {
  643. #ifdef CLIENT_DLL
  644. PlayWorldReloadSound( pPlayer );
  645. #else
  646. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_RELOAD );
  647. #endif
  648. }
  649. SendWeaponAnim( iActivity );
  650. // Play the player's reload animation
  651. if ( pOwner->IsPlayer() )
  652. {
  653. ( ( CBasePlayer * )pOwner)->SetAnimation( PLAYER_RELOAD );
  654. }
  655. float flSequenceEndTime = gpGlobals->curtime + SequenceDuration();
  656. pOwner->SetNextAttack( flSequenceEndTime );
  657. m_flNextPrimaryAttack = m_flNextSecondaryAttack = flSequenceEndTime;
  658. m_bInReload = true;
  659. return true;
  660. }
  661. #ifdef CLIENT_DLL
  662. void CWeaponDODBase::PlayWorldReloadSound( CDODPlayer *pPlayer )
  663. {
  664. Assert( pPlayer );
  665. const char *shootsound = GetShootSound( RELOAD );
  666. if ( !shootsound || !shootsound[0] )
  667. return;
  668. CSoundParameters params;
  669. if ( !GetParametersForSound( shootsound, params, NULL ) )
  670. return;
  671. // Play weapon sound from the owner
  672. CPASAttenuationFilter filter( pPlayer, params.soundlevel );
  673. filter.RemoveRecipient( pPlayer ); // no local player, that is done in the model
  674. EmitSound( filter, pPlayer->entindex(), shootsound, NULL, 0.0 );
  675. }
  676. #endif
  677. bool CWeaponDODBase::IsUseable()
  678. {
  679. CBasePlayer *pPlayer = GetPlayerOwner();
  680. if ( Clip1() <= 0 )
  681. {
  682. if ( pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) <= 0 && GetMaxClip1() != -1 )
  683. {
  684. // clip is empty (or nonexistant) and the player has no more ammo of this type.
  685. return false;
  686. }
  687. }
  688. return true;
  689. }
  690. #ifndef CLIENT_DLL
  691. ConVar dod_meleeattackforcescale( "dod_meleeattackforcescale", "8.0", FCVAR_CHEAT | FCVAR_GAMEDLL );
  692. #endif
  693. void CWeaponDODBase::RifleButt( void )
  694. {
  695. //MeleeAttack( 60, MELEE_DMG_BUTTSTOCK | MELEE_DMG_SECONDARYATTACK, 0.2f, 0.9f );
  696. }
  697. void CWeaponDODBase::Bayonet( void )
  698. {
  699. //MeleeAttack( 60, MELEE_DMG_BAYONET | MELEE_DMG_SECONDARYATTACK, 0.2f, 0.9f );
  700. }
  701. void CWeaponDODBase::Punch( void )
  702. {
  703. MeleeAttack( 60, MELEE_DMG_FIST | MELEE_DMG_SECONDARYATTACK, 0.2f, 0.4f );
  704. }
  705. //--------------------------------------------
  706. // iDamageAmount - how much damage to give
  707. // iDamageType - DMG_ bits
  708. // flDmgDelay - delay between attack and the giving of damage, usually timed to animation
  709. // flAttackDelay - time until we can next attack
  710. //--------------------------------------------
  711. CBaseEntity *CWeaponDODBase::MeleeAttack( int iDamageAmount, int iDamageType, float flDmgDelay, float flAttackDelay )
  712. {
  713. if ( !CanAttack() )
  714. return NULL;
  715. CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
  716. #if !defined (CLIENT_DLL)
  717. // Move other players back to history positions based on local player's lag
  718. lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() );
  719. #endif
  720. Vector vForward, vRight, vUp;
  721. AngleVectors( pPlayer->EyeAngles(), &vForward, &vRight, &vUp );
  722. Vector vecSrc = pPlayer->Weapon_ShootPosition();
  723. Vector vecEnd = vecSrc + vForward * 48;
  724. CTraceFilterSimple filter( pPlayer, COLLISION_GROUP_NONE );
  725. int iTraceMask = MASK_SOLID | CONTENTS_HITBOX | CONTENTS_DEBRIS;
  726. trace_t tr;
  727. UTIL_TraceLine( vecSrc, vecEnd, iTraceMask, &filter, &tr );
  728. const float rayExtension = 40.0f;
  729. UTIL_ClipTraceToPlayers( vecSrc, vecEnd + vForward * rayExtension, iTraceMask, &filter, &tr );
  730. // If the exact forward trace did not hit, try a larger swept box
  731. if ( tr.fraction >= 1.0 )
  732. {
  733. Vector head_hull_mins( -16, -16, -18 );
  734. Vector head_hull_maxs( 16, 16, 18 );
  735. UTIL_TraceHull( vecSrc, vecEnd, head_hull_mins, head_hull_maxs, MASK_SOLID, &filter, &tr );
  736. if ( tr.fraction < 1.0 )
  737. {
  738. // Calculate the point of intersection of the line (or hull) and the object we hit
  739. // This is and approximation of the "best" intersection
  740. CBaseEntity *pHit = tr.m_pEnt;
  741. if ( !pHit || pHit->IsBSPModel() )
  742. FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, pPlayer );
  743. vecEnd = tr.endpos; // This is the point on the actual surface (the hull could have hit space)
  744. // Make sure it is in front of us
  745. Vector vecToEnd = vecEnd - vecSrc;
  746. VectorNormalize( vecToEnd );
  747. // if zero length, always hit
  748. if ( vecToEnd.Length() > 0 )
  749. {
  750. float dot = DotProduct( vForward, vecToEnd );
  751. // sanity that our hit is within range
  752. if ( abs(dot) < 0.95 )
  753. {
  754. // fake that we actually missed
  755. tr.fraction = 1.0;
  756. }
  757. }
  758. }
  759. }
  760. WeaponSound( MELEE_MISS );
  761. bool bDidHit = ( tr.fraction < 1.0f );
  762. if ( bDidHit ) //if the swing hit
  763. {
  764. // delay the decal a bit
  765. m_trHit = tr;
  766. // Store the ent in an EHANDLE, just in case it goes away by the time we get into our think function.
  767. m_pTraceHitEnt = tr.m_pEnt;
  768. m_iSmackDamage = iDamageAmount;
  769. m_iSmackDamageType = iDamageType;
  770. m_flSmackTime = gpGlobals->curtime + flDmgDelay;
  771. }
  772. SendWeaponAnim( GetMeleeActivity() );
  773. // player animation
  774. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_SECONDARY_ATTACK );
  775. m_flNextPrimaryAttack = gpGlobals->curtime + flAttackDelay;
  776. m_flNextSecondaryAttack = gpGlobals->curtime + flAttackDelay;
  777. m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
  778. #ifndef CLIENT_DLL
  779. IGameEvent * event = gameeventmanager->CreateEvent( "dod_stats_weapon_attack" );
  780. if ( event )
  781. {
  782. event->SetInt( "attacker", pPlayer->GetUserID() );
  783. event->SetInt( "weapon", GetAltWeaponID() );
  784. gameeventmanager->FireEvent( event );
  785. }
  786. lagcompensation->FinishLagCompensation( pPlayer );
  787. #endif //CLIENT_DLL
  788. return tr.m_pEnt;
  789. }
  790. //Think function to delay the impact decal until the animation is finished playing
  791. void CWeaponDODBase::Smack()
  792. {
  793. Assert( GetPlayerOwner() );
  794. if ( !GetPlayerOwner() )
  795. return;
  796. CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
  797. if ( !pPlayer )
  798. return;
  799. // Check that we are still facing the victim
  800. Vector vForward, vRight, vUp;
  801. AngleVectors( pPlayer->EyeAngles(), &vForward, &vRight, &vUp );
  802. Vector vecSrc = pPlayer->Weapon_ShootPosition();
  803. Vector vecEnd = vecSrc + vForward * 48;
  804. CTraceFilterSimple filter( pPlayer, COLLISION_GROUP_NONE );
  805. int iTraceMask = MASK_SOLID | CONTENTS_HITBOX | CONTENTS_DEBRIS;
  806. trace_t tr;
  807. UTIL_TraceLine( vecSrc, vecEnd, iTraceMask, &filter, &tr );
  808. const float rayExtension = 40.0f;
  809. UTIL_ClipTraceToPlayers( vecSrc, vecEnd + vForward * rayExtension, iTraceMask, &filter, &tr );
  810. if ( tr.fraction >= 1.0 )
  811. {
  812. Vector head_hull_mins( -16, -16, -18 );
  813. Vector head_hull_maxs( 16, 16, 18 );
  814. UTIL_TraceHull( vecSrc, vecEnd, head_hull_mins, head_hull_maxs, MASK_SOLID, &filter, &tr );
  815. if ( tr.fraction < 1.0 )
  816. {
  817. // Calculate the point of intersection of the line (or hull) and the object we hit
  818. // This is and approximation of the "best" intersection
  819. CBaseEntity *pHit = tr.m_pEnt;
  820. if ( !pHit || pHit->IsBSPModel() )
  821. FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, pPlayer );
  822. vecEnd = tr.endpos; // This is the point on the actual surface (the hull could have hit space)
  823. }
  824. }
  825. m_trHit = tr;
  826. if ( !m_trHit.m_pEnt || (m_trHit.surface.flags & SURF_SKY) )
  827. return;
  828. if ( m_trHit.fraction == 1.0 )
  829. return;
  830. CPASAttenuationFilter attenuationFilter( this );
  831. attenuationFilter.UsePredictionRules();
  832. if( m_trHit.m_pEnt->IsPlayer() )
  833. {
  834. if ( m_iSmackDamageType & MELEE_DMG_STRONGATTACK )
  835. WeaponSound( SPECIAL1 );
  836. else
  837. WeaponSound( MELEE_HIT );
  838. }
  839. else
  840. WeaponSound( MELEE_HIT_WORLD );
  841. int iDamageType = DMG_CLUB | DMG_NEVERGIB;
  842. #ifndef CLIENT_DLL
  843. //if they hit the bounding box, just assume a chest hit
  844. if( m_trHit.hitgroup == HITGROUP_GENERIC )
  845. m_trHit.hitgroup = HITGROUP_CHEST;
  846. float flDamage = (float)m_iSmackDamage;
  847. CTakeDamageInfo info( pPlayer, pPlayer, flDamage, iDamageType );
  848. if ( m_iSmackDamageType & MELEE_DMG_SECONDARYATTACK )
  849. info.SetDamageCustom( MELEE_DMG_SECONDARYATTACK );
  850. float flScale = (1.0f / flDamage) * dod_meleeattackforcescale.GetFloat();
  851. Vector vecForceDir = vForward;
  852. CalculateMeleeDamageForce( &info, vecForceDir, m_trHit.endpos, flScale );
  853. Assert( m_trHit.m_pEnt != GetPlayerOwner() );
  854. m_trHit.m_pEnt->DispatchTraceAttack( info, vForward, &m_trHit );
  855. ApplyMultiDamage();
  856. #endif
  857. // We've gotten minidumps where this happened.
  858. if ( !GetPlayerOwner() )
  859. return;
  860. CEffectData data;
  861. data.m_vOrigin = m_trHit.endpos;
  862. data.m_vStart = m_trHit.startpos;
  863. data.m_nSurfaceProp = m_trHit.surface.surfaceProps;
  864. data.m_nHitBox = m_trHit.hitbox;
  865. #ifdef CLIENT_DLL
  866. data.m_hEntity = m_trHit.m_pEnt->GetRefEHandle();
  867. #else
  868. data.m_nEntIndex = m_trHit.m_pEnt->entindex();
  869. #endif
  870. CPASFilter effectfilter( data.m_vOrigin );
  871. #ifndef CLIENT_DLL
  872. effectfilter.RemoveRecipient( GetPlayerOwner() );
  873. #endif
  874. data.m_vAngles = GetPlayerOwner()->GetAbsAngles();
  875. data.m_fFlags = 0x1; //IMPACT_NODECAL;
  876. data.m_nDamageType = iDamageType;
  877. bool bHitPlayer = m_trHit.m_pEnt && m_trHit.m_pEnt->IsPlayer();
  878. // don't do any impacts if we hit a teammate and ff is off
  879. if ( bHitPlayer &&
  880. m_trHit.m_pEnt->GetTeamNumber() == GetPlayerOwner()->GetTeamNumber() &&
  881. !friendlyfire.GetBool() )
  882. return;
  883. if ( bHitPlayer )
  884. {
  885. te->DispatchEffect( effectfilter, 0.0, data.m_vOrigin, "Impact", data );
  886. }
  887. else if ( m_iSmackDamageType & MELEE_DMG_EDGE )
  888. {
  889. data.m_nDamageType = DMG_SLASH;
  890. te->DispatchEffect( effectfilter, 0.0, data.m_vOrigin, "KnifeSlash", data );
  891. }
  892. }
  893. #if defined( CLIENT_DLL )
  894. float g_lateralBob = 0;
  895. float g_verticalBob = 0;
  896. static ConVar cl_bobcycle( "cl_bobcycle","0.8" );
  897. static ConVar cl_bob( "cl_bob","0.002" );
  898. static ConVar cl_bobup( "cl_bobup","0.5" );
  899. // Register these cvars if needed for easy tweaking
  900. static ConVar v_iyaw_cycle( "v_iyaw_cycle", "2"/*, FCVAR_UNREGISTERED*/ );
  901. static ConVar v_iroll_cycle( "v_iroll_cycle", "0.5"/*, FCVAR_UNREGISTERED*/ );
  902. static ConVar v_ipitch_cycle( "v_ipitch_cycle", "1"/*, FCVAR_UNREGISTERED*/ );
  903. static ConVar v_iyaw_level( "v_iyaw_level", "0.3"/*, FCVAR_UNREGISTERED*/ );
  904. static ConVar v_iroll_level( "v_iroll_level", "0.1"/*, FCVAR_UNREGISTERED*/ );
  905. static ConVar v_ipitch_level( "v_ipitch_level", "0.3"/*, FCVAR_UNREGISTERED*/ );
  906. //-----------------------------------------------------------------------------
  907. // Purpose:
  908. // Output : float
  909. //-----------------------------------------------------------------------------
  910. float CWeaponDODBase::CalcViewmodelBob( void )
  911. {
  912. static float bobtime;
  913. static float lastbobtime;
  914. static float lastspeed;
  915. float cycle;
  916. CBasePlayer *player = ToBasePlayer( GetOwner() );
  917. //Assert( player );
  918. //NOTENOTE: For now, let this cycle continue when in the air, because it snaps badly without it
  919. if ( ( !gpGlobals->frametime ) || ( player == NULL ) )
  920. {
  921. //NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!)
  922. return 0.0f;// just use old value
  923. }
  924. //Find the speed of the player
  925. float speed = player->GetLocalVelocity().Length2D();
  926. float flmaxSpeedDelta = MAX( 0, (gpGlobals->curtime - lastbobtime) * 320.0f );
  927. // don't allow too big speed changes
  928. speed = clamp( speed, lastspeed-flmaxSpeedDelta, lastspeed+flmaxSpeedDelta );
  929. speed = clamp( speed, -320, 320 );
  930. lastspeed = speed;
  931. //FIXME: This maximum speed value must come from the server.
  932. // MaxSpeed() is not sufficient for dealing with sprinting - jdw
  933. float bob_offset = RemapVal( speed, 0, 320, 0.0f, 1.0f );
  934. bobtime += ( gpGlobals->curtime - lastbobtime ) * bob_offset;
  935. lastbobtime = gpGlobals->curtime;
  936. //Calculate the vertical bob
  937. cycle = bobtime - (int)(bobtime/cl_bobcycle.GetFloat())*cl_bobcycle.GetFloat();
  938. cycle /= cl_bobcycle.GetFloat();
  939. if ( cycle < cl_bobup.GetFloat() )
  940. {
  941. cycle = M_PI * cycle / cl_bobup.GetFloat();
  942. }
  943. else
  944. {
  945. cycle = M_PI + M_PI*(cycle-cl_bobup.GetFloat())/(1.0 - cl_bobup.GetFloat());
  946. }
  947. g_verticalBob = speed*0.005f;
  948. g_verticalBob = g_verticalBob*0.3 + g_verticalBob*0.7*sin(cycle);
  949. g_verticalBob = clamp( g_verticalBob, -7.0f, 4.0f );
  950. //Calculate the lateral bob
  951. cycle = bobtime - (int)(bobtime/cl_bobcycle.GetFloat()*2)*cl_bobcycle.GetFloat()*2;
  952. cycle /= cl_bobcycle.GetFloat()*2;
  953. if ( cycle < cl_bobup.GetFloat() )
  954. {
  955. cycle = M_PI * cycle / cl_bobup.GetFloat();
  956. }
  957. else
  958. {
  959. cycle = M_PI + M_PI*(cycle-cl_bobup.GetFloat())/(1.0 - cl_bobup.GetFloat());
  960. }
  961. g_lateralBob = speed*0.005f;
  962. g_lateralBob = g_lateralBob*0.3 + g_lateralBob*0.7*sin(cycle);
  963. g_lateralBob = clamp( g_lateralBob, -7.0f, 4.0f );
  964. //NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!)
  965. return 0.0f;
  966. }
  967. //-----------------------------------------------------------------------------
  968. // Purpose:
  969. // Input : &origin -
  970. // &angles -
  971. // viewmodelindex -
  972. //-----------------------------------------------------------------------------
  973. void CWeaponDODBase::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles )
  974. {
  975. Vector forward, right;
  976. AngleVectors( angles, &forward, &right, NULL );
  977. CalcViewmodelBob();
  978. // Apply bob, but scaled down to 40%
  979. VectorMA( origin, g_verticalBob * 0.4f, forward, origin );
  980. // Z bob a bit more
  981. origin[2] += g_verticalBob * 0.1f;
  982. // bob the angles
  983. angles[ ROLL ] += g_verticalBob * 0.5f;
  984. angles[ PITCH ] -= g_verticalBob * 0.4f;
  985. angles[ YAW ] -= g_lateralBob * 0.3f;
  986. // VectorMA( origin, g_lateralBob * 0.2f, right, origin );
  987. }
  988. #include "c_te_effect_dispatch.h"
  989. #define NUM_MUZZLE_FLASH_TYPES 4
  990. bool CWeaponDODBase::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options )
  991. {
  992. if( event == 5001 )
  993. {
  994. if ( ShouldDrawMuzzleFlash() )
  995. {
  996. Assert( GetOwnerEntity() == C_BasePlayer::GetLocalPlayer() );
  997. const char *pszMuzzleFlashEffect;
  998. switch( GetDODWpnData().m_iMuzzleFlashType )
  999. {
  1000. case DOD_MUZZLEFLASH_PISTOL:
  1001. pszMuzzleFlashEffect = "view_muzzle_pistols";
  1002. break;
  1003. case DOD_MUZZLEFLASH_AUTO:
  1004. pszMuzzleFlashEffect = "view_muzzle_fullyautomatic";
  1005. break;
  1006. case DOD_MUZZLEFLASH_RIFLE:
  1007. pszMuzzleFlashEffect = "view_muzzle_rifles";
  1008. break;
  1009. case DOD_MUZZLEFLASH_MG:
  1010. pszMuzzleFlashEffect = "view_muzzle_miniguns";
  1011. break;
  1012. case DOD_MUZZLEFLASH_ROCKET:
  1013. pszMuzzleFlashEffect = "view_muzzle_rockets";
  1014. break;
  1015. case DOD_MUZZLEFLASH_MG42:
  1016. pszMuzzleFlashEffect = "view_muzzle_mg42";
  1017. break;
  1018. default:
  1019. pszMuzzleFlashEffect = NULL;
  1020. break;
  1021. }
  1022. if ( pszMuzzleFlashEffect )
  1023. {
  1024. pViewModel->ParticleProp()->Create( pszMuzzleFlashEffect, PATTACH_POINT_FOLLOW, 1 );
  1025. }
  1026. }
  1027. return true;
  1028. }
  1029. else if( event == 6002 )
  1030. {
  1031. CEffectData data;
  1032. data.m_nHitBox = atoi( options );
  1033. data.m_hEntity = GetPlayerOwner() ? GetPlayerOwner()->GetRefEHandle() : INVALID_EHANDLE_INDEX;
  1034. pViewModel->GetAttachment( 2, data.m_vOrigin, data.m_vAngles );
  1035. DispatchEffect( "DOD_EjectBrass", data );
  1036. return true;
  1037. }
  1038. return BaseClass::OnFireEvent( pViewModel, origin, angles, event, options );
  1039. }
  1040. bool CWeaponDODBase::ShouldAutoEjectBrass( void )
  1041. {
  1042. // Don't eject brass if further than N units from the local player
  1043. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  1044. if ( !pLocalPlayer )
  1045. return true;
  1046. float flMaxDistSqr = 250;
  1047. flMaxDistSqr *= flMaxDistSqr;
  1048. float flDistSqr = pLocalPlayer->EyePosition().DistToSqr( GetAbsOrigin() );
  1049. return ( flDistSqr < flMaxDistSqr );
  1050. }
  1051. bool CWeaponDODBase::GetEjectBrassShellType( void )
  1052. {
  1053. return 1;
  1054. }
  1055. void CWeaponDODBase::SetUseAltModel( bool bUseAltModel )
  1056. {
  1057. m_bUseAltWeaponModel = bUseAltModel;
  1058. }
  1059. void CWeaponDODBase::CheckForAltWeapon( int iCurrentState )
  1060. {
  1061. int iCriteria = GetDODWpnData().m_iAltWpnCriteria;
  1062. bool bUseAltModel = false;
  1063. if( ( iCriteria & iCurrentState ) != 0 )
  1064. bUseAltModel = true;
  1065. SetUseAltModel( bUseAltModel );
  1066. }
  1067. Vector CWeaponDODBase::GetDesiredViewModelOffset( C_DODPlayer *pOwner )
  1068. {
  1069. Vector viewOffset = pOwner->GetViewOffset();
  1070. float flPercent = ( viewOffset.z - VEC_PRONE_VIEW_SCALED( pOwner ).z ) / ( VEC_VIEW_SCALED( pOwner ).z - VEC_PRONE_VIEW_SCALED( pOwner ).z );
  1071. return ( flPercent * GetDODWpnData().m_vecViewNormalOffset +
  1072. ( 1.0 - flPercent ) * GetDODWpnData().m_vecViewProneOffset );
  1073. }
  1074. bool CWeaponDODBase::ShouldDraw( void )
  1075. {
  1076. if ( GetModel() == NULL )
  1077. {
  1078. // XXX(johns): Removed, doesn't seem to be the proper spot for this warning given that weapons can call
  1079. // ShouldDraw before their properties are filled.
  1080. // C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer();
  1081. // Warning( "BADNESS! Tell Matt that the weapon '%s' tried to draw with a null model ( %d, %d, %s ) \n",
  1082. // GetDODWpnData().szClassName,
  1083. // m_iWorldModelIndex.Get(), m_iReloadModelIndex.Get(), m_bUseAltWeaponModel ? "alt" : "not alt" );
  1084. return false;
  1085. }
  1086. return BaseClass::ShouldDraw();
  1087. }
  1088. #else
  1089. void CWeaponDODBase::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles )
  1090. {
  1091. }
  1092. float CWeaponDODBase::CalcViewmodelBob( void )
  1093. {
  1094. return 0.0f;
  1095. }
  1096. void CWeaponDODBase::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  1097. {
  1098. if ( CanDrop() == false )
  1099. return;
  1100. CDODPlayer *pPlayer = ToDODPlayer( pActivator );
  1101. if ( pPlayer )
  1102. {
  1103. pPlayer->PickUpWeapon( this );
  1104. }
  1105. }
  1106. #endif