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.

557 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Client side implementation of CBaseCombatWeapon.
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "history_resource.h"
  9. #include "iclientmode.h"
  10. #include "iinput.h"
  11. #include "weapon_selection.h"
  12. #include "hud_crosshair.h"
  13. #include "engine/ivmodelinfo.h"
  14. #include "tier0/vprof.h"
  15. #include "hltvcamera.h"
  16. #include "tier1/KeyValues.h"
  17. #include "toolframework/itoolframework.h"
  18. #include "toolframework_client.h"
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. //-----------------------------------------------------------------------------
  22. // Purpose: Gets the local client's active weapon, if any.
  23. //-----------------------------------------------------------------------------
  24. C_BaseCombatWeapon *GetActiveWeapon( void )
  25. {
  26. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
  27. if ( !player )
  28. return NULL;
  29. return player->GetActiveWeapon();
  30. }
  31. //-----------------------------------------------------------------------------
  32. // Purpose:
  33. //-----------------------------------------------------------------------------
  34. void C_BaseCombatWeapon::SetDormant( bool bDormant )
  35. {
  36. // If I'm going from active to dormant and I'm carried by another player, holster me.
  37. if ( !IsDormant() && bDormant && GetOwner() && !IsCarriedByLocalPlayer() )
  38. {
  39. Holster( NULL );
  40. }
  41. BaseClass::SetDormant( bDormant );
  42. }
  43. //-----------------------------------------------------------------------------
  44. // Purpose:
  45. //-----------------------------------------------------------------------------
  46. void C_BaseCombatWeapon::NotifyShouldTransmit( ShouldTransmitState_t state )
  47. {
  48. BaseClass::NotifyShouldTransmit(state);
  49. if (state == SHOULDTRANSMIT_END)
  50. {
  51. if (m_iState == WEAPON_IS_ACTIVE)
  52. {
  53. m_iState = WEAPON_IS_CARRIED_BY_PLAYER;
  54. }
  55. }
  56. else if( state == SHOULDTRANSMIT_START )
  57. {
  58. if( m_iState == WEAPON_IS_CARRIED_BY_PLAYER )
  59. {
  60. if( GetOwner() && GetOwner()->GetActiveWeapon() == this )
  61. {
  62. // Restore the Activeness of the weapon if we client-twiddled it off in the first case above.
  63. m_iState = WEAPON_IS_ACTIVE;
  64. }
  65. }
  66. }
  67. }
  68. //-----------------------------------------------------------------------------
  69. // Purpose: To wrap PORTAL mod specific functionality into one place
  70. //-----------------------------------------------------------------------------
  71. static inline bool ShouldDrawLocalPlayerViewModel( void )
  72. {
  73. #if defined( PORTAL )
  74. return false;
  75. #else
  76. return !C_BasePlayer::ShouldDrawLocalPlayer();
  77. #endif
  78. }
  79. //-----------------------------------------------------------------------------
  80. // Purpose:
  81. //-----------------------------------------------------------------------------
  82. void C_BaseCombatWeapon::OnRestore()
  83. {
  84. BaseClass::OnRestore();
  85. // if the player is holding this weapon,
  86. // mark it as just restored so it won't show as a new pickup
  87. if (GetOwner() == C_BasePlayer::GetLocalPlayer())
  88. {
  89. m_bJustRestored = true;
  90. }
  91. }
  92. int C_BaseCombatWeapon::GetWorldModelIndex( void )
  93. {
  94. if ( GameRules() )
  95. {
  96. const char *pBaseName = modelinfo->GetModelName( modelinfo->GetModel( m_iWorldModelIndex ) );
  97. const char *pTranslatedName = GameRules()->TranslateEffectForVisionFilter( "weapons", pBaseName );
  98. if ( pTranslatedName != pBaseName )
  99. {
  100. return modelinfo->GetModelIndex( pTranslatedName );
  101. }
  102. }
  103. return m_iWorldModelIndex;
  104. }
  105. //-----------------------------------------------------------------------------
  106. // Purpose:
  107. // Input : bnewentity -
  108. //-----------------------------------------------------------------------------
  109. void C_BaseCombatWeapon::OnDataChanged( DataUpdateType_t updateType )
  110. {
  111. BaseClass::OnDataChanged(updateType);
  112. CHandle< C_BaseCombatWeapon > handle = this;
  113. // If it's being carried by the *local* player, on the first update,
  114. // find the registered weapon for this ID
  115. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  116. C_BaseCombatCharacter *pOwner = GetOwner();
  117. // check if weapon is carried by local player
  118. bool bIsLocalPlayer = pPlayer && pPlayer == pOwner;
  119. if ( bIsLocalPlayer && ShouldDrawLocalPlayerViewModel() ) // TODO: figure out the purpose of the ShouldDrawLocalPlayer() test.
  120. {
  121. // If I was just picked up, or created & immediately carried, add myself to this client's list of weapons
  122. if ( (m_iState != WEAPON_NOT_CARRIED ) && (m_iOldState == WEAPON_NOT_CARRIED) )
  123. {
  124. // Tell the HUD this weapon's been picked up
  125. if ( ShouldDrawPickup() )
  126. {
  127. CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection();
  128. if ( pHudSelection )
  129. {
  130. pHudSelection->OnWeaponPickup( this );
  131. }
  132. pPlayer->EmitSound( "Player.PickupWeapon" );
  133. }
  134. }
  135. }
  136. else // weapon carried by other player or not at all
  137. {
  138. int overrideModelIndex = CalcOverrideModelIndex();
  139. if( overrideModelIndex != -1 && overrideModelIndex != GetModelIndex() )
  140. {
  141. SetModelIndex( overrideModelIndex );
  142. }
  143. }
  144. if ( updateType == DATA_UPDATE_CREATED )
  145. {
  146. UpdateVisibility();
  147. }
  148. m_iOldState = m_iState;
  149. m_bJustRestored = false;
  150. }
  151. //-----------------------------------------------------------------------------
  152. // Is anyone carrying it?
  153. //-----------------------------------------------------------------------------
  154. bool C_BaseCombatWeapon::IsBeingCarried() const
  155. {
  156. return ( m_hOwner.Get() != NULL );
  157. }
  158. //-----------------------------------------------------------------------------
  159. // Is the carrier alive?
  160. //-----------------------------------------------------------------------------
  161. bool C_BaseCombatWeapon::IsCarrierAlive() const
  162. {
  163. if ( !m_hOwner.Get() )
  164. return false;
  165. return m_hOwner.Get()->GetHealth() > 0;
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Should this object cast shadows?
  169. //-----------------------------------------------------------------------------
  170. ShadowType_t C_BaseCombatWeapon::ShadowCastType()
  171. {
  172. if ( IsEffectActive( /*EF_NODRAW |*/ EF_NOSHADOW ) )
  173. return SHADOWS_NONE;
  174. if (!IsBeingCarried())
  175. return SHADOWS_RENDER_TO_TEXTURE;
  176. if (IsCarriedByLocalPlayer() && !C_BasePlayer::ShouldDrawLocalPlayer())
  177. return SHADOWS_NONE;
  178. return SHADOWS_RENDER_TO_TEXTURE;
  179. }
  180. //-----------------------------------------------------------------------------
  181. // Purpose: This weapon is the active weapon, and it should now draw anything
  182. // it wants to. This gets called every frame.
  183. //-----------------------------------------------------------------------------
  184. void C_BaseCombatWeapon::Redraw()
  185. {
  186. if ( g_pClientMode->ShouldDrawCrosshair() )
  187. {
  188. DrawCrosshair();
  189. }
  190. // ammo drawing has been moved into hud_ammo.cpp
  191. }
  192. //-----------------------------------------------------------------------------
  193. // Purpose: Draw the weapon's crosshair
  194. //-----------------------------------------------------------------------------
  195. void C_BaseCombatWeapon::DrawCrosshair()
  196. {
  197. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
  198. if ( !player )
  199. return;
  200. Color clr = gHUD.m_clrNormal;
  201. /*
  202. // TEST: if the thing under your crosshair is on a different team, light the crosshair with a different color.
  203. Vector vShootPos, vShootAngles;
  204. GetShootPosition( vShootPos, vShootAngles );
  205. Vector vForward;
  206. AngleVectors( vShootAngles, &vForward );
  207. // Change the color depending on if we're looking at a friend or an enemy.
  208. CPartitionFilterListMask filter( PARTITION_ALL_CLIENT_EDICTS );
  209. trace_t tr;
  210. traceline->TraceLine( vShootPos, vShootPos + vForward * 10000, COLLISION_GROUP_NONE, MASK_SHOT, &tr, true, ~0, &filter );
  211. if ( tr.index != 0 && tr.index != INVALID_CLIENTENTITY_HANDLE )
  212. {
  213. C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( tr.index );
  214. if ( pEnt )
  215. {
  216. if ( pEnt->GetTeamNumber() != player->GetTeamNumber() )
  217. {
  218. g = b = 0;
  219. }
  220. }
  221. }
  222. */
  223. CHudCrosshair *pCrosshair = GET_HUDELEMENT( CHudCrosshair );
  224. if ( !pCrosshair )
  225. return;
  226. // Find out if this weapon's auto-aimed onto a target
  227. bool bOnTarget = ( m_iState == WEAPON_IS_ONTARGET );
  228. if ( player->GetFOV() >= 90 )
  229. {
  230. // normal crosshairs
  231. if ( bOnTarget && GetWpnData().iconAutoaim )
  232. {
  233. clr[3] = 255;
  234. pCrosshair->SetCrosshair( GetWpnData().iconAutoaim, clr );
  235. }
  236. else if ( GetWpnData().iconCrosshair )
  237. {
  238. clr[3] = 255;
  239. pCrosshair->SetCrosshair( GetWpnData().iconCrosshair, clr );
  240. }
  241. else
  242. {
  243. pCrosshair->ResetCrosshair();
  244. }
  245. }
  246. else
  247. {
  248. Color white( 255, 255, 255, 255 );
  249. // zoomed crosshairs
  250. if (bOnTarget && GetWpnData().iconZoomedAutoaim)
  251. pCrosshair->SetCrosshair(GetWpnData().iconZoomedAutoaim, white);
  252. else if ( GetWpnData().iconZoomedCrosshair )
  253. pCrosshair->SetCrosshair( GetWpnData().iconZoomedCrosshair, white );
  254. else
  255. pCrosshair->ResetCrosshair();
  256. }
  257. }
  258. //-----------------------------------------------------------------------------
  259. // Purpose: This weapon is the active weapon, and the viewmodel for it was just drawn.
  260. //-----------------------------------------------------------------------------
  261. void C_BaseCombatWeapon::ViewModelDrawn( C_BaseViewModel *pViewModel )
  262. {
  263. }
  264. //-----------------------------------------------------------------------------
  265. // Purpose: Returns true if this client's carrying this weapon
  266. //-----------------------------------------------------------------------------
  267. bool C_BaseCombatWeapon::IsCarriedByLocalPlayer( void )
  268. {
  269. if ( !GetOwner() )
  270. return false;
  271. return ( GetOwner() == C_BasePlayer::GetLocalPlayer() );
  272. }
  273. //-----------------------------------------------------------------------------
  274. // Purpose: Returns true if this client is carrying this weapon and is
  275. // using the view models
  276. //-----------------------------------------------------------------------------
  277. bool C_BaseCombatWeapon::ShouldDrawUsingViewModel( void )
  278. {
  279. return IsCarriedByLocalPlayer() && !C_BasePlayer::ShouldDrawLocalPlayer();
  280. }
  281. //-----------------------------------------------------------------------------
  282. // Purpose: Returns true if this weapon is the local client's currently wielded weapon
  283. //-----------------------------------------------------------------------------
  284. bool C_BaseCombatWeapon::IsActiveByLocalPlayer( void )
  285. {
  286. if ( IsCarriedByLocalPlayer() )
  287. {
  288. return (m_iState == WEAPON_IS_ACTIVE);
  289. }
  290. return false;
  291. }
  292. bool C_BaseCombatWeapon::GetShootPosition( Vector &vOrigin, QAngle &vAngles )
  293. {
  294. // Get the entity because the weapon doesn't have the right angles.
  295. C_BaseCombatCharacter *pEnt = ToBaseCombatCharacter( GetOwner() );
  296. if ( pEnt )
  297. {
  298. if ( pEnt == C_BasePlayer::GetLocalPlayer() )
  299. {
  300. vAngles = pEnt->EyeAngles();
  301. }
  302. else
  303. {
  304. vAngles = pEnt->GetRenderAngles();
  305. }
  306. }
  307. else
  308. {
  309. vAngles.Init();
  310. }
  311. QAngle vDummy;
  312. if ( IsActiveByLocalPlayer() && ShouldDrawLocalPlayerViewModel() )
  313. {
  314. C_BasePlayer *player = ToBasePlayer( pEnt );
  315. C_BaseViewModel *vm = player ? player->GetViewModel( 0 ) : NULL;
  316. if ( vm )
  317. {
  318. int iAttachment = vm->LookupAttachment( "muzzle" );
  319. if ( vm->GetAttachment( iAttachment, vOrigin, vDummy ) )
  320. {
  321. return true;
  322. }
  323. }
  324. }
  325. else
  326. {
  327. // Thirdperson
  328. int iAttachment = LookupAttachment( "muzzle" );
  329. if ( GetAttachment( iAttachment, vOrigin, vDummy ) )
  330. {
  331. return true;
  332. }
  333. }
  334. vOrigin = GetRenderOrigin();
  335. return false;
  336. }
  337. //-----------------------------------------------------------------------------
  338. // Purpose:
  339. // Output : Returns true on success, false on failure.
  340. //-----------------------------------------------------------------------------
  341. bool C_BaseCombatWeapon::ShouldDraw( void )
  342. {
  343. if ( m_iWorldModelIndex == 0 )
  344. return false;
  345. // FIXME: All weapons with owners are set to transmit in CBaseCombatWeapon::UpdateTransmitState,
  346. // even if they have EF_NODRAW set, so we have to check this here. Ideally they would never
  347. // transmit except for the weapons owned by the local player.
  348. if ( IsEffectActive( EF_NODRAW ) )
  349. return false;
  350. C_BaseCombatCharacter *pOwner = GetOwner();
  351. // weapon has no owner, always draw it
  352. if ( !pOwner )
  353. return true;
  354. bool bIsActive = ( m_iState == WEAPON_IS_ACTIVE );
  355. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  356. // carried by local player?
  357. if ( pOwner == pLocalPlayer )
  358. {
  359. // Only ever show the active weapon
  360. if ( !bIsActive )
  361. return false;
  362. if ( !pOwner->ShouldDraw() )
  363. {
  364. // Our owner is invisible.
  365. // This also tests whether the player is zoomed in, in which case you don't want to draw the weapon.
  366. return false;
  367. }
  368. // 3rd person mode?
  369. if ( !ShouldDrawLocalPlayerViewModel() )
  370. return true;
  371. // don't draw active weapon if not in some kind of 3rd person mode, the viewmodel will do that
  372. return false;
  373. }
  374. // If it's a player, then only show active weapons
  375. if ( pOwner->IsPlayer() )
  376. {
  377. // Show it if it's active...
  378. return bIsActive;
  379. }
  380. // FIXME: We may want to only show active weapons on NPCs
  381. // These are carried by AIs; always show them
  382. return true;
  383. }
  384. //-----------------------------------------------------------------------------
  385. // Purpose: Return true if a weapon-pickup icon should be displayed when this weapon is received
  386. //-----------------------------------------------------------------------------
  387. bool C_BaseCombatWeapon::ShouldDrawPickup( void )
  388. {
  389. if ( GetWeaponFlags() & ITEM_FLAG_NOITEMPICKUP )
  390. return false;
  391. if ( m_bJustRestored )
  392. return false;
  393. return true;
  394. }
  395. //-----------------------------------------------------------------------------
  396. // Purpose: Render the weapon. Draw the Viewmodel if the weapon's being carried
  397. // by this player, otherwise draw the worldmodel.
  398. //-----------------------------------------------------------------------------
  399. int C_BaseCombatWeapon::DrawModel( int flags )
  400. {
  401. VPROF_BUDGET( "C_BaseCombatWeapon::DrawModel", VPROF_BUDGETGROUP_MODEL_RENDERING );
  402. if ( !m_bReadyToDraw )
  403. return 0;
  404. if ( !IsVisible() )
  405. return 0;
  406. // check if local player chases owner of this weapon in first person
  407. C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer();
  408. if ( localplayer && localplayer->IsObserver() && GetOwner() )
  409. {
  410. // don't draw weapon if chasing this guy as spectator
  411. // we don't check that in ShouldDraw() since this may change
  412. // without notification
  413. if ( localplayer->GetObserverMode() == OBS_MODE_IN_EYE &&
  414. localplayer->GetObserverTarget() == GetOwner() )
  415. return false;
  416. }
  417. return BaseClass::DrawModel( flags );
  418. }
  419. //-----------------------------------------------------------------------------
  420. // Allows the client-side entity to override what the network tells it to use for
  421. // a model. This is used for third person mode, specifically in HL2 where the
  422. // the weapon timings are on the view model and not the world model. That means the
  423. // server needs to use the view model, but the client wants to use the world model.
  424. //-----------------------------------------------------------------------------
  425. int C_BaseCombatWeapon::CalcOverrideModelIndex()
  426. {
  427. C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer();
  428. if ( localplayer &&
  429. localplayer == GetOwner() &&
  430. ShouldDrawLocalPlayerViewModel() )
  431. {
  432. return BaseClass::CalcOverrideModelIndex();
  433. }
  434. else
  435. {
  436. return GetWorldModelIndex();
  437. }
  438. }
  439. //-----------------------------------------------------------------------------
  440. // tool recording
  441. //-----------------------------------------------------------------------------
  442. void C_BaseCombatWeapon::GetToolRecordingState( KeyValues *msg )
  443. {
  444. if ( !ToolsEnabled() )
  445. return;
  446. int nModelIndex = GetModelIndex();
  447. int nWorldModelIndex = GetWorldModelIndex();
  448. if ( nModelIndex != nWorldModelIndex )
  449. {
  450. SetModelIndex( nWorldModelIndex );
  451. }
  452. BaseClass::GetToolRecordingState( msg );
  453. if ( m_iState == WEAPON_NOT_CARRIED )
  454. {
  455. BaseEntityRecordingState_t *pBaseEntity = (BaseEntityRecordingState_t*)msg->GetPtr( "baseentity" );
  456. pBaseEntity->m_nOwner = -1;
  457. }
  458. else
  459. {
  460. msg->SetInt( "worldmodel", 1 );
  461. if ( m_iState == WEAPON_IS_ACTIVE )
  462. {
  463. BaseEntityRecordingState_t *pBaseEntity = (BaseEntityRecordingState_t*)msg->GetPtr( "baseentity" );
  464. pBaseEntity->m_bVisible = true;
  465. }
  466. }
  467. if ( nModelIndex != nWorldModelIndex )
  468. {
  469. SetModelIndex( nModelIndex );
  470. }
  471. }