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
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: CTF CurrencyPack.
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "items.h"
  8. #include "tf_gamerules.h"
  9. #include "tf_shareddefs.h"
  10. #include "tf_player.h"
  11. #include "tf_team.h"
  12. #include "engine/IEngineSound.h"
  13. #include "entity_currencypack.h"
  14. #include "tf_gamestats.h"
  15. #include "tf_mann_vs_machine_stats.h"
  16. #include "world.h"
  17. #include "particle_parse.h"
  18. #include "player_vs_environment/tf_population_manager.h"
  19. #include "collisionutils.h"
  20. #include "tf_objective_resource.h"
  21. //=============================================================================
  22. //
  23. // CTF CurrencyPack defines.
  24. //
  25. #define TF_CURRENCYPACK_PICKUP_SOUND "MVM.MoneyPickup"
  26. #define TF_CURRENCYPACK_VANISH_SOUND "MVM.MoneyVanish"
  27. #define TF_CURRENCYPACK_BLINK_PERIOD 5.0f // how long pack blinks before it vanishes
  28. #define TF_CURRENCYPACK_BLINK_DURATION 0.25f // how long a blink lasts
  29. #define TF_CURRENCYPACK_GLOW_THINK_TIME 0.1f // how often should we check if cash should glow
  30. LINK_ENTITY_TO_CLASS( item_currencypack_large, CCurrencyPack );
  31. LINK_ENTITY_TO_CLASS( item_currencypack_medium, CCurrencyPackMedium );
  32. LINK_ENTITY_TO_CLASS( item_currencypack_small, CCurrencyPackSmall );
  33. LINK_ENTITY_TO_CLASS( item_currencypack_custom, CCurrencyPackCustom );
  34. IMPLEMENT_SERVERCLASS_ST( CCurrencyPack, DT_CurrencyPack )
  35. SendPropBool( SENDINFO( m_bDistributed ) ),
  36. END_SEND_TABLE()
  37. IMPLEMENT_AUTO_LIST( ICurrencyPackAutoList );
  38. //=============================================================================
  39. //
  40. // CTF CurrencyPack functions.
  41. //
  42. //-----------------------------------------------------------------------------
  43. // Purpose:
  44. //-----------------------------------------------------------------------------
  45. CCurrencyPack::CCurrencyPack()
  46. {
  47. m_nAmount = 0;
  48. m_nWaveNumber = MannVsMachineStats_GetCurrentWave();
  49. m_bTouched = false;
  50. m_bClaimed = false;
  51. m_bDistributed = false;
  52. }
  53. //-----------------------------------------------------------------------------
  54. // Purpose:
  55. //-----------------------------------------------------------------------------
  56. CCurrencyPack::~CCurrencyPack()
  57. {
  58. }
  59. //-----------------------------------------------------------------------------
  60. // Purpose:
  61. //-----------------------------------------------------------------------------
  62. void CCurrencyPack::UpdateOnRemove( void )
  63. {
  64. BaseClass::UpdateOnRemove();
  65. if ( g_pPopulationManager && !m_bTouched )
  66. {
  67. if ( !m_bDistributed )
  68. {
  69. g_pPopulationManager->OnCurrencyPackFade();
  70. }
  71. DispatchParticleEffect( "mvm_cash_explosion", GetAbsOrigin(), GetAbsAngles() );
  72. }
  73. if ( !m_bDistributed && TFObjectiveResource() )
  74. {
  75. TFObjectiveResource()->AddMvMWorldMoney( -m_nAmount );
  76. }
  77. }
  78. //-----------------------------------------------------------------------------
  79. // Purpose: Always transmitted to clients
  80. //-----------------------------------------------------------------------------
  81. int CCurrencyPack::UpdateTransmitState( void )
  82. {
  83. return SetTransmitState( FL_EDICT_ALWAYS );
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Purpose:
  87. //-----------------------------------------------------------------------------
  88. int CCurrencyPack::ShouldTransmit( const CCheckTransmitInfo *pInfo )
  89. {
  90. return FL_EDICT_ALWAYS;
  91. }
  92. //-----------------------------------------------------------------------------
  93. // Purpose:
  94. //-----------------------------------------------------------------------------
  95. void CCurrencyPack::Spawn( void )
  96. {
  97. BaseClass::Spawn();
  98. m_blinkCount = 0;
  99. m_blinkTimer.Invalidate();
  100. SetContextThink( &CCurrencyPack::BlinkThink, gpGlobals->curtime + GetLifeTime() - TF_CURRENCYPACK_BLINK_PERIOD - RandomFloat( 0.0, TF_CURRENCYPACK_BLINK_DURATION ), "CurrencyPackWaitingToBlinkThink" );
  101. // Force collision size to see if this fixes a bunch of stuck-in-geo issues goes away
  102. SetCollisionBounds( Vector( -10, -10, -10 ), Vector( 10, 10, 10 ) );
  103. if ( m_bDistributed )
  104. {
  105. DispatchParticleEffect( "mvm_cash_embers_red", PATTACH_ABSORIGIN_FOLLOW, this );
  106. }
  107. else
  108. {
  109. DispatchParticleEffect( "mvm_cash_embers", PATTACH_ABSORIGIN_FOLLOW, this );
  110. }
  111. // Store when this drops for time-based accounting - like with wave collection bonus
  112. m_nWaveNumber = MannVsMachineStats_GetCurrentWave();
  113. // if m_nAmount != 0, we already call SetAmount
  114. m_nAmount = m_nAmount == 0 ? TFGameRules()->CalculateCurrencyAmount_ByType( GetPackSize() ) : m_nAmount;
  115. MannVsMachineStats_RoundEvent_CreditsDropped( m_nWaveNumber, m_nAmount );
  116. if ( !m_bDistributed && TFObjectiveResource() )
  117. {
  118. TFObjectiveResource()->AddMvMWorldMoney( m_nAmount );
  119. }
  120. }
  121. //-----------------------------------------------------------------------------
  122. // Purpose: Blink off/on when about to expire and play expire sound
  123. //-----------------------------------------------------------------------------
  124. void CCurrencyPack::BlinkThink( void )
  125. {
  126. // This means the pack was claimed by a player via Radius Currency Collection and
  127. // is likely flying toward them. Regardless, one second later it fires Touch().
  128. if ( IsClaimed() )
  129. return;
  130. ++m_blinkCount;
  131. SetRenderMode( kRenderTransAlpha );
  132. if ( m_blinkCount & 0x1 )
  133. {
  134. SetRenderColorA( 25 );
  135. }
  136. else
  137. {
  138. SetRenderColorA( 255 );
  139. }
  140. SetContextThink( &CCurrencyPack::BlinkThink, gpGlobals->curtime + TF_CURRENCYPACK_BLINK_DURATION, "CurrencyPackBlinkThink" );
  141. }
  142. //-----------------------------------------------------------------------------
  143. // Become touchable when we are at rest
  144. //-----------------------------------------------------------------------------
  145. void CCurrencyPack::ComeToRest( void )
  146. {
  147. BaseClass::ComeToRest();
  148. if ( IsClaimed() || m_bDistributed )
  149. return;
  150. // if we've come to rest in an area with no nav, just grant the money to the player
  151. if ( TheNavMesh->GetNavArea( GetAbsOrigin() ) == NULL )
  152. {
  153. TFGameRules()->DistributeCurrencyAmount( m_nAmount );
  154. m_bTouched = true;
  155. UTIL_Remove( this );
  156. return;
  157. }
  158. // See if we've come to rest in a trigger_hurt
  159. for ( int i = 0; i < ITriggerHurtAutoList::AutoList().Count(); i++ )
  160. {
  161. CTriggerHurt *pTrigger = static_cast<CTriggerHurt*>( ITriggerHurtAutoList::AutoList()[i] );
  162. if ( !pTrigger->m_bDisabled )
  163. {
  164. Vector vecMins, vecMaxs;
  165. pTrigger->GetCollideable()->WorldSpaceSurroundingBounds( &vecMins, &vecMaxs );
  166. if ( IsPointInBox( GetCollideable()->GetCollisionOrigin(), vecMins, vecMaxs ) )
  167. {
  168. TFGameRules()->DistributeCurrencyAmount( m_nAmount );
  169. m_bTouched = true;
  170. UTIL_Remove( this );
  171. }
  172. }
  173. }
  174. }
  175. //-----------------------------------------------------------------------------
  176. // Purpose: Sets the value of a custom pack
  177. //-----------------------------------------------------------------------------
  178. void CCurrencyPack::SetAmount( float nAmount )
  179. {
  180. Assert( GetPackSize() == TF_CURRENCY_PACK_CUSTOM ); // Never set an amount unless we're custom
  181. m_nAmount = nAmount;
  182. }
  183. //-----------------------------------------------------------------------------
  184. // Purpose: Distribute the money right away
  185. //-----------------------------------------------------------------------------
  186. void CCurrencyPack::DistributedBy( CBasePlayer* pMoneyMaker )
  187. {
  188. TFGameRules()->DistributeCurrencyAmount( m_nAmount );
  189. if ( pMoneyMaker )
  190. {
  191. CTF_GameStats.Event_PlayerCollectedCurrency( pMoneyMaker, m_nAmount );
  192. }
  193. m_bDistributed = true;
  194. }
  195. //-----------------------------------------------------------------------------
  196. // Purpose:
  197. //-----------------------------------------------------------------------------
  198. void CCurrencyPack::Precache( void )
  199. {
  200. PrecacheScriptSound( TF_CURRENCYPACK_PICKUP_SOUND );
  201. PrecacheScriptSound( TF_CURRENCYPACK_VANISH_SOUND );
  202. PrecacheParticleSystem( "mvm_cash_embers" );
  203. PrecacheParticleSystem( "mvm_cash_explosion" );
  204. BaseClass::Precache();
  205. }
  206. //-----------------------------------------------------------------------------
  207. // Purpose:
  208. //-----------------------------------------------------------------------------
  209. bool CCurrencyPack::MyTouch( CBasePlayer *pPlayer )
  210. {
  211. if ( ValidTouch( pPlayer ) && !m_bTouched )
  212. {
  213. CTFPlayer *pTFTouchPlayer = ToTFPlayer( pPlayer );
  214. if ( !pTFTouchPlayer )
  215. return false;
  216. if ( pTFTouchPlayer->IsBot() )
  217. return false;
  218. if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
  219. {
  220. // Prevent losing team from grabbing money - screws up stats in checkpoints
  221. if ( TFGameRules()->State_Get() == GR_STATE_TEAM_WIN )
  222. {
  223. if ( TFGameRules()->GetWinningTeam() != pTFTouchPlayer->GetTeamNumber() )
  224. return false;
  225. }
  226. // Scouts gain health when grabbing currency packs
  227. if ( pTFTouchPlayer->GetPlayerClass()->GetClassIndex() == TF_CLASS_SCOUT )
  228. {
  229. const int nCurHealth = pTFTouchPlayer->GetHealth();
  230. const int nMaxHealth = pTFTouchPlayer->GetMaxHealth();
  231. int nHealth = nCurHealth < nMaxHealth ? 50 : 25;
  232. // If we cross the border into insanity, scale the reward
  233. const int nHealthCap = nMaxHealth * 4;
  234. if ( nCurHealth > nHealthCap )
  235. {
  236. nHealth = RemapValClamped( nCurHealth, nHealthCap, (nHealthCap * 1.5f), 20, 5 );
  237. }
  238. pTFTouchPlayer->TakeHealth( nHealth, DMG_IGNORE_MAXHEALTH );
  239. }
  240. MannVsMachineStats_PlayerEvent_PickedUpCredits( pTFTouchPlayer, m_nWaveNumber, m_nAmount );
  241. IGameEvent *event = gameeventmanager->CreateEvent( "mvm_pickup_currency" );
  242. if ( event )
  243. {
  244. event->SetInt( "player", pTFTouchPlayer->entindex() );
  245. event->SetInt( "currency", m_nAmount );
  246. gameeventmanager->FireEvent( event );
  247. }
  248. // is the money blinking and about to burn up?
  249. if ( m_blinkCount > 0 )
  250. {
  251. pTFTouchPlayer->AwardAchievement( ACHIEVEMENT_TF_MVM_PICKUP_MONEY_ABOUT_TO_EXPIRE );
  252. }
  253. }
  254. CReliableBroadcastRecipientFilter filter;
  255. EmitSound( filter, entindex(), TF_CURRENCYPACK_PICKUP_SOUND );
  256. if ( !m_bDistributed )
  257. {
  258. TFGameRules()->DistributeCurrencyAmount( m_nAmount, pTFTouchPlayer );
  259. CTF_GameStats.Event_PlayerCollectedCurrency( pTFTouchPlayer, m_nAmount );
  260. }
  261. if ( ( !pTFTouchPlayer->IsPlayerClass( TF_CLASS_SPY ) ) ||
  262. ( !pTFTouchPlayer->m_Shared.IsStealthed() && !pTFTouchPlayer->m_Shared.InCond( TF_COND_STEALTHED_BLINK ) && !pTFTouchPlayer->m_Shared.InCond( TF_COND_DISGUISED ) ) )
  263. {
  264. pTFTouchPlayer->SpeakConceptIfAllowed( MP_CONCEPT_MVM_MONEY_PICKUP );
  265. }
  266. pTFTouchPlayer->SetLastObjectiveTime( gpGlobals->curtime );
  267. m_bTouched = true;
  268. }
  269. return m_bTouched;
  270. }
  271. //-----------------------------------------------------------------------------
  272. // Purpose:
  273. //-----------------------------------------------------------------------------
  274. const char *CCurrencyPackCustom::GetDefaultPowerupModel( void )
  275. {
  276. // Custom packs should always be set to a value by hand
  277. Assert( m_nAmount > 0 );
  278. // Try to pick a model that's appropriate to our drop amount (which is in our multiplier)
  279. if ( m_nAmount >= 25 )
  280. return "models/items/currencypack_large.mdl";
  281. if ( m_nAmount >= 10 )
  282. return "models/items/currencypack_medium.mdl";
  283. return "models/items/currencypack_small.mdl";
  284. }