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.

346 lines
9.5 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "tf_weapon_invis.h"
  8. #include "in_buttons.h"
  9. #if !defined( CLIENT_DLL )
  10. #include "vguiscreen.h"
  11. #include "tf_player.h"
  12. #else
  13. #include "c_tf_player.h"
  14. #endif
  15. extern ConVar tf_spy_invis_unstealth_time;
  16. extern ConVar tf_spy_cloak_consume_rate;
  17. extern ConVar tf_spy_cloak_regen_rate;
  18. //=============================================================================
  19. //
  20. // TFWeaponBase Melee tables.
  21. //
  22. IMPLEMENT_NETWORKCLASS_ALIASED( TFWeaponInvis, DT_TFWeaponInvis )
  23. BEGIN_NETWORK_TABLE( CTFWeaponInvis, DT_TFWeaponInvis )
  24. END_NETWORK_TABLE()
  25. BEGIN_PREDICTION_DATA( CTFWeaponInvis )
  26. END_PREDICTION_DATA()
  27. LINK_ENTITY_TO_CLASS( tf_weapon_invis, CTFWeaponInvis );
  28. PRECACHE_WEAPON_REGISTER( tf_weapon_invis );
  29. // Server specific.
  30. #if !defined( CLIENT_DLL )
  31. BEGIN_DATADESC( CTFWeaponInvis )
  32. END_DATADESC()
  33. #endif
  34. //-----------------------------------------------------------------------------
  35. // Purpose: Use the offhand view model
  36. //-----------------------------------------------------------------------------
  37. void CTFWeaponInvis::Spawn( void )
  38. {
  39. BaseClass::Spawn();
  40. SetViewModelIndex( 1 );
  41. }
  42. //-----------------------------------------------------------------------------
  43. // Purpose:
  44. //-----------------------------------------------------------------------------
  45. void CTFWeaponInvis::OnActiveStateChanged( int iOldState )
  46. {
  47. BaseClass::OnActiveStateChanged( iOldState );
  48. // If we are being removed, we need to remove all stealth effects from our owner
  49. if ( m_iState == WEAPON_NOT_CARRIED && iOldState != WEAPON_NOT_CARRIED )
  50. {
  51. CleanupInvisibilityWatch();
  52. }
  53. }
  54. //-----------------------------------------------------------------------------
  55. // Purpose: Clear out the view model when we hide
  56. //-----------------------------------------------------------------------------
  57. void CTFWeaponInvis::HideThink( void )
  58. {
  59. SetWeaponVisible( false );
  60. }
  61. //-----------------------------------------------------------------------------
  62. // Purpose:
  63. //-----------------------------------------------------------------------------
  64. const char *CTFWeaponInvis::GetViewModel( int viewmodelindex ) const
  65. {
  66. // Watch uses the player model as its viewmodel, because it's never seen being carried by the player
  67. const CEconItemView *pItem = GetAttributeContainer()->GetItem();
  68. if ( pItem->IsValid() )
  69. {
  70. int iClass = 0;
  71. int iTeam = 0;
  72. CTFPlayer *pTFPlayer = ToTFPlayer( GetOwnerEntity() );
  73. if ( pTFPlayer )
  74. {
  75. iClass = pTFPlayer->GetPlayerClass()->GetClassIndex();
  76. iTeam = pTFPlayer->GetTeamNumber();
  77. }
  78. return pItem->GetPlayerDisplayModel( iClass, iTeam );
  79. }
  80. return BaseClass::GetViewModel( viewmodelindex );
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Purpose: Show/hide weapon and corresponding view model if any
  84. // Input : visible -
  85. //-----------------------------------------------------------------------------
  86. void CTFWeaponInvis::SetWeaponVisible( bool visible )
  87. {
  88. CBaseViewModel *vm = NULL;
  89. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  90. if ( pOwner )
  91. {
  92. vm = pOwner->GetViewModel( m_nViewModelIndex );
  93. }
  94. if ( visible )
  95. {
  96. RemoveEffects( EF_NODRAW );
  97. if ( vm )
  98. {
  99. vm->RemoveEffects( EF_NODRAW );
  100. }
  101. }
  102. else
  103. {
  104. AddEffects( EF_NODRAW );
  105. if ( vm )
  106. {
  107. vm->AddEffects( EF_NODRAW );
  108. }
  109. }
  110. }
  111. //-----------------------------------------------------------------------------
  112. bool CTFWeaponInvis::Deploy( void )
  113. {
  114. bool b = BaseClass::Deploy();
  115. SetWeaponIdleTime( gpGlobals->curtime + 1.5 );
  116. return b;
  117. }
  118. //-----------------------------------------------------------------------------
  119. bool CTFWeaponInvis::Holster( CBaseCombatWeapon *pSwitchingTo )
  120. {
  121. bool bHolster = BaseClass::Holster( pSwitchingTo );
  122. // far in the future
  123. SetWeaponIdleTime( gpGlobals->curtime + 10 );
  124. return bHolster;
  125. }
  126. //-----------------------------------------------------------------------------
  127. void CTFWeaponInvis::PrimaryAttack( void )
  128. {
  129. // do nothing
  130. }
  131. //-----------------------------------------------------------------------------
  132. void CTFWeaponInvis::SecondaryAttack( void )
  133. {
  134. // do nothing
  135. }
  136. //-----------------------------------------------------------------------------
  137. void CTFWeaponInvis::ItemBusyFrame( void )
  138. {
  139. // do nothing
  140. }
  141. //-----------------------------------------------------------------------------
  142. // Purpose: the player alt-fired or otherwise activated the functionality of
  143. // the invisibility watch
  144. //-----------------------------------------------------------------------------
  145. bool CTFWeaponInvis::ActivateInvisibilityWatch( void )
  146. {
  147. CTFPlayer *pOwner = ToTFPlayer( GetOwner() );
  148. if ( !pOwner )
  149. return false;
  150. SetCloakRates();
  151. bool bDoSkill = false;
  152. // If we're in TF_COND_STEALTHED - which means we gave it ourselves - always remove it
  153. // If we're in TF_COND_STEALTHED_USER_BUFF and we have Dead Ringer, allow it to be toggled
  154. // since we're allowed to fire from stealth
  155. if ( pOwner->m_Shared.InCond( TF_COND_STEALTHED ) )
  156. {
  157. // De-cloak.
  158. float flDecloakRate = 0.0f;
  159. CALL_ATTRIB_HOOK_FLOAT( flDecloakRate, mult_decloak_rate );
  160. if ( flDecloakRate <= 0.0f )
  161. flDecloakRate = 1.0f;
  162. pOwner->m_Shared.FadeInvis( 1.0f );
  163. }
  164. else
  165. {
  166. if ( HasFeignDeath() )
  167. {
  168. if ( pOwner->m_Shared.IsFeignDeathReady() )
  169. {
  170. // Turn it off...
  171. SetFeignDeathState( false );
  172. }
  173. else if ( pOwner->m_Shared.GetSpyCloakMeter() == 100.f )
  174. {
  175. // Turn it on...
  176. SetFeignDeathState( true );
  177. }
  178. }
  179. else if ( pOwner->CanGoInvisible() && ( pOwner->m_Shared.GetSpyCloakMeter() > 8.0f ) ) // must have over 10% cloak to start
  180. {
  181. // Do standard cloak.
  182. pOwner->m_Shared.AddCond( TF_COND_STEALTHED, -1.f, pOwner );
  183. #ifdef STAGING_ONLY
  184. if ( pOwner->m_Shared.HasPhaseCloakAbility() )
  185. {
  186. pOwner->m_Shared.AddCond( TF_COND_STEALTHED_PHASE, -1.f, pOwner );
  187. }
  188. #endif // STAGING_ONLY
  189. bDoSkill = true;
  190. }
  191. }
  192. if ( bDoSkill )
  193. {
  194. pOwner->m_Shared.SetNextStealthTime( gpGlobals->curtime + 0.5 );
  195. }
  196. else
  197. {
  198. pOwner->m_Shared.SetNextStealthTime( gpGlobals->curtime + 0.1 );
  199. }
  200. return bDoSkill;
  201. }
  202. //-----------------------------------------------------------------------------
  203. // Purpose: the player has changed loadouts or done something else that causes
  204. // us to clean up any side effects of our watch
  205. //-----------------------------------------------------------------------------
  206. void CTFWeaponInvis::CleanupInvisibilityWatch( void )
  207. {
  208. CTFPlayer *pOwner = ToTFPlayer( GetOwner() );
  209. if ( !pOwner )
  210. return;
  211. pOwner->m_Shared.SetFeignDeathReady( false );
  212. if ( pOwner->m_Shared.IsStealthed() )
  213. {
  214. // De-cloak.
  215. pOwner->m_Shared.FadeInvis( 1.0f );
  216. }
  217. pOwner->HolsterOffHandWeapon();
  218. }
  219. //-----------------------------------------------------------------------------
  220. // Purpose:
  221. //-----------------------------------------------------------------------------
  222. void CTFWeaponInvis::SetFeignDeathState( bool bEnabled )
  223. {
  224. CTFPlayer *pOwner = ToTFPlayer( GetOwner() );
  225. if ( !pOwner )
  226. return;
  227. if ( pOwner->m_Shared.InCond( TF_COND_GRAPPLINGHOOK ) )
  228. return;
  229. if ( bEnabled )
  230. {
  231. pOwner->m_Shared.SetFeignDeathReady( true );
  232. pOwner->SetOffHandWeapon( this );
  233. pOwner->m_Shared.SetNextStealthTime( gpGlobals->curtime + 0.5 );
  234. }
  235. else
  236. {
  237. pOwner->m_Shared.SetFeignDeathReady( false );
  238. if ( !pOwner->m_Shared.InCond( TF_COND_STEALTHED ) )
  239. {
  240. pOwner->HolsterOffHandWeapon();
  241. if ( pOwner->GetActiveWeapon() )
  242. {
  243. pOwner->GetActiveWeapon()->m_flNextPrimaryAttack = gpGlobals->curtime + 0.1f;
  244. }
  245. }
  246. }
  247. }
  248. //-----------------------------------------------------------------------------
  249. // Purpose: Set the correct cloak consume & regen rates for this item.
  250. //-----------------------------------------------------------------------------
  251. void CTFWeaponInvis::SetCloakRates( void )
  252. {
  253. CTFPlayer *pOwner = ToTFPlayer( GetOwner() );
  254. float fCloakConsumeRate = tf_spy_cloak_consume_rate.GetFloat();
  255. float fCloakConsumeFactor = 1.0f;
  256. CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pOwner, fCloakConsumeFactor, mult_cloak_meter_consume_rate ); // Ask the owner since this attr may come from another weapon
  257. // This value is a inverse scale and does not match expectations on description
  258. // so we subtract and invert to make it align
  259. // ie 25% (0.75% in schema) makes 10seconds go to 13.3 when we want 12.5
  260. // 2 - 0.75 = 1.25... 1 / 1.25 = 0.8.. Consume rate "8". 10s / 0.8 = 12.5s
  261. if ( fCloakConsumeFactor < 1.0f )
  262. {
  263. fCloakConsumeFactor = 1.0f / (2.0f - fCloakConsumeFactor);
  264. }
  265. pOwner->m_Shared.SetCloakConsumeRate( fCloakConsumeRate * fCloakConsumeFactor );
  266. float fCloakRegenRate = tf_spy_cloak_regen_rate.GetFloat();
  267. float fCloakRegenFactor = 1.0f;
  268. CALL_ATTRIB_HOOK_FLOAT( fCloakRegenFactor, mult_cloak_meter_regen_rate );
  269. pOwner->m_Shared.SetCloakRegenRate( fCloakRegenRate * fCloakRegenFactor );
  270. }
  271. #ifndef CLIENT_DLL
  272. //-----------------------------------------------------------------------------
  273. // Purpose: Return the right pda panel for the watch model we're using
  274. //-----------------------------------------------------------------------------
  275. void CTFWeaponInvis::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName )
  276. {
  277. const char *pszViewModel = GetViewModel(0);
  278. if ( Q_stristr( pszViewModel, "pocket" ) )
  279. {
  280. pPanelName = "pda_panel_spy_invis_pocket";
  281. }
  282. else if ( Q_stristr( pszViewModel, "ttg_watch_spy" ) )
  283. {
  284. pPanelName = "pda_panel_spy_invis_pocket_ttg";
  285. }
  286. else if ( Q_stristr( pszViewModel, "hm_watch" ) )
  287. {
  288. pPanelName = "pda_panel_spy_invis_pocket_hm";
  289. }
  290. else
  291. {
  292. pPanelName = "pda_panel_spy_invis";
  293. }
  294. }
  295. #endif