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.

786 lines
21 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "tf_item_powerup_bottle.h"
  8. #include "tf_gamerules.h"
  9. #ifdef GAME_DLL
  10. #include "tf_player.h"
  11. #include "tf_obj_sentrygun.h"
  12. #include "tf_weapon_medigun.h"
  13. #endif
  14. // memdbgon must be the last include file in a .cpp file!!!
  15. #include "tier0/memdbgon.h"
  16. #ifndef GAME_DLL
  17. extern ConVar cl_hud_minmode;
  18. #endif
  19. LINK_ENTITY_TO_CLASS( tf_powerup_bottle, CTFPowerupBottle );
  20. IMPLEMENT_NETWORKCLASS_ALIASED( TFPowerupBottle, DT_TFPowerupBottle )
  21. // Network Table --
  22. BEGIN_NETWORK_TABLE( CTFPowerupBottle, DT_TFPowerupBottle )
  23. #if defined( GAME_DLL )
  24. SendPropBool( SENDINFO( m_bActive ) ),
  25. SendPropInt( SENDINFO( m_usNumCharges ), -1, SPROP_UNSIGNED ),
  26. #else
  27. RecvPropBool( RECVINFO( m_bActive ) ),
  28. RecvPropInt( RECVINFO( m_usNumCharges ) ),
  29. #endif // GAME_DLL
  30. END_NETWORK_TABLE()
  31. // -- Network Table
  32. // Data Desc --
  33. BEGIN_DATADESC( CTFPowerupBottle )
  34. END_DATADESC()
  35. // -- Data Desc
  36. PRECACHE_REGISTER( tf_powerup_bottle );
  37. //-----------------------------------------------------------------------------
  38. // SHARED CODE
  39. //-----------------------------------------------------------------------------
  40. CTFPowerupBottle::CTFPowerupBottle() : CTFWearable()
  41. {
  42. m_bActive = false;
  43. m_usNumCharges = 0;
  44. m_flLastSpawnTime = 0.f;
  45. #ifdef TF_CLIENT_DLL
  46. ListenForGameEvent( "player_spawn" );
  47. #endif
  48. }
  49. void CTFPowerupBottle::Precache( void )
  50. {
  51. PrecacheModel( "models/player/items/mvm_loot/all_class/mvm_flask_generic.mdl" );
  52. PrecacheModel( "models/player/items/mvm_loot/all_class/mvm_flask_krit.mdl" );
  53. PrecacheModel( "models/player/items/mvm_loot/all_class/mvm_flask_uber.mdl" );
  54. PrecacheModel( "models/player/items/mvm_loot/all_class/mvm_flask_tele.mdl" );
  55. PrecacheModel( "models/player/items/mvm_loot/all_class/mvm_flask_ammo.mdl" );
  56. PrecacheModel( "models/player/items/mvm_loot/all_class/mvm_flask_build.mdl" );
  57. BaseClass::Precache();
  58. }
  59. //-----------------------------------------------------------------------------
  60. // Purpose: Reset the bottle to its initial state
  61. //-----------------------------------------------------------------------------
  62. void CTFPowerupBottle::Reset( void )
  63. {
  64. m_bActive = false;
  65. SetNumCharges( 0 );
  66. #ifdef GAME_DLL
  67. class CAttributeIterator_ZeroRefundableCurrency : public IEconItemUntypedAttributeIterator
  68. {
  69. public:
  70. CAttributeIterator_ZeroRefundableCurrency( CAttributeList *pAttrList )
  71. : m_pAttrList( pAttrList )
  72. {
  73. Assert( m_pAttrList );
  74. }
  75. private:
  76. virtual bool OnIterateAttributeValueUntyped( const CEconItemAttributeDefinition *pAttrDef )
  77. {
  78. if ( ::FindAttribute( m_pAttrList, pAttrDef ) )
  79. {
  80. m_pAttrList->SetRuntimeAttributeRefundableCurrency( pAttrDef, 0 );
  81. }
  82. return true;
  83. }
  84. CAttributeList *m_pAttrList;
  85. };
  86. CAttributeIterator_ZeroRefundableCurrency it( GetAttributeList() );
  87. GetAttributeList()->IterateAttributes( &it );
  88. #endif
  89. }
  90. PowerupBottleType_t CTFPowerupBottle::GetPowerupType( void ) const
  91. {
  92. int iHasCritBoost = 0;
  93. CALL_ATTRIB_HOOK_INT( iHasCritBoost, critboost );
  94. if ( iHasCritBoost )
  95. {
  96. return POWERUP_BOTTLE_CRITBOOST;
  97. }
  98. int iHasUbercharge = 0;
  99. CALL_ATTRIB_HOOK_INT( iHasUbercharge, ubercharge );
  100. if ( iHasUbercharge )
  101. {
  102. return POWERUP_BOTTLE_UBERCHARGE;
  103. }
  104. int iHasRecall = 0;
  105. CALL_ATTRIB_HOOK_INT( iHasRecall, recall );
  106. if ( iHasRecall )
  107. {
  108. return POWERUP_BOTTLE_RECALL;
  109. }
  110. int iHasRefillAmmo = 0;
  111. CALL_ATTRIB_HOOK_INT( iHasRefillAmmo, refill_ammo );
  112. if ( iHasRefillAmmo )
  113. {
  114. return POWERUP_BOTTLE_REFILL_AMMO;
  115. }
  116. int iHasInstaBuildingUpgrade = 0;
  117. CALL_ATTRIB_HOOK_INT( iHasInstaBuildingUpgrade, building_instant_upgrade );
  118. if ( iHasInstaBuildingUpgrade )
  119. {
  120. return POWERUP_BOTTLE_BUILDINGS_INSTANT_UPGRADE;
  121. }
  122. #ifdef STAGING_ONLY
  123. int iSeeCashThroughWall = 0;
  124. CALL_ATTRIB_HOOK_INT( iSeeCashThroughWall, mvm_see_cash_through_wall );
  125. if ( iSeeCashThroughWall )
  126. {
  127. return POWERUP_BOTTLE_SEE_CASH_THROUGH_WALL;
  128. }
  129. #endif
  130. return POWERUP_BOTTLE_NONE;
  131. }
  132. //-----------------------------------------------------------------------------
  133. // Purpose:
  134. //-----------------------------------------------------------------------------
  135. void CTFPowerupBottle::ReapplyProvision( void )
  136. {
  137. // let the base class do what it needs to do in terms of adding/removing itself from old and new owners
  138. BaseClass::ReapplyProvision();
  139. CBaseEntity *pOwner = GetOwnerEntity();
  140. IHasAttributes *pOwnerAttribInterface = GetAttribInterface( pOwner );
  141. if ( pOwnerAttribInterface )
  142. {
  143. if ( m_bActive )
  144. {
  145. if ( !pOwnerAttribInterface->GetAttributeManager()->IsBeingProvidedToBy( this ) )
  146. {
  147. GetAttributeManager()->ProvideTo( pOwner );
  148. }
  149. }
  150. else
  151. {
  152. GetAttributeManager()->StopProvidingTo( pOwner );
  153. }
  154. #ifdef GAME_DLL
  155. bool bBottleShared = false;
  156. CTFPlayer *pTFPlayer = dynamic_cast< CTFPlayer* >( pOwner );
  157. if ( pTFPlayer )
  158. {
  159. float flDuration = 0;
  160. CALL_ATTRIB_HOOK_FLOAT( flDuration, powerup_duration );
  161. // Add extra time?
  162. CALL_ATTRIB_HOOK_INT_ON_OTHER( pTFPlayer, flDuration, canteen_specialist );
  163. // This block of code checks if a medic has the ability to
  164. // share bottle charges with their heal target
  165. int iShareBottle = 0;
  166. CWeaponMedigun *pMedigun = NULL;
  167. CTFPlayer *pHealTarget = NULL;
  168. if ( pTFPlayer->IsPlayerClass( TF_CLASS_MEDIC ) )
  169. {
  170. pMedigun = dynamic_cast<CWeaponMedigun *>( pTFPlayer->GetActiveWeapon() );
  171. if ( pMedigun )
  172. {
  173. pHealTarget = ToTFPlayer( pMedigun->GetHealTarget() );
  174. if ( pHealTarget )
  175. {
  176. CALL_ATTRIB_HOOK_INT_ON_OTHER( pTFPlayer, iShareBottle, canteen_specialist );
  177. }
  178. }
  179. }
  180. // special stuff for conditions
  181. int iHasCritBoost = 0;
  182. CALL_ATTRIB_HOOK_INT( iHasCritBoost, critboost );
  183. if ( iHasCritBoost != 0 )
  184. {
  185. if ( m_bActive )
  186. {
  187. pTFPlayer->m_Shared.AddCond( TF_COND_CRITBOOSTED_USER_BUFF, flDuration );
  188. if ( iShareBottle && pHealTarget )
  189. {
  190. pHealTarget->m_Shared.AddCond( TF_COND_CRITBOOSTED_USER_BUFF, flDuration );
  191. bBottleShared = true;
  192. }
  193. }
  194. else
  195. {
  196. pTFPlayer->m_Shared.RemoveCond( TF_COND_CRITBOOSTED_USER_BUFF, true );
  197. }
  198. }
  199. int iHasUbercharge = 0;
  200. CALL_ATTRIB_HOOK_INT( iHasUbercharge, ubercharge );
  201. if ( iHasUbercharge )
  202. {
  203. if ( m_bActive )
  204. {
  205. pTFPlayer->m_Shared.AddCond( TF_COND_INVULNERABLE_USER_BUFF, flDuration );
  206. // Shield sentries
  207. if ( pTFPlayer->IsPlayerClass( TF_CLASS_ENGINEER ) )
  208. {
  209. for ( int i = pTFPlayer->GetObjectCount()-1; i >= 0; i-- )
  210. {
  211. CObjectSentrygun *pSentry = dynamic_cast<CObjectSentrygun *>( pTFPlayer->GetObject(i) );
  212. if ( pSentry && !pSentry->IsCarried() )
  213. {
  214. pSentry->SetShieldLevel( SHIELD_MAX, flDuration );
  215. }
  216. }
  217. }
  218. else if ( iShareBottle && pHealTarget )
  219. {
  220. pHealTarget->m_Shared.AddCond( TF_COND_INVULNERABLE_USER_BUFF, flDuration, pTFPlayer );
  221. bBottleShared = true;
  222. }
  223. }
  224. else
  225. {
  226. pTFPlayer->m_Shared.RemoveCond( TF_COND_INVULNERABLE_USER_BUFF, true );
  227. }
  228. }
  229. int iHasRecall = 0;
  230. CALL_ATTRIB_HOOK_INT( iHasRecall, recall );
  231. if ( iHasRecall )
  232. {
  233. if ( m_bActive )
  234. {
  235. pTFPlayer->ForceRespawn();
  236. pTFPlayer->m_Shared.AddCond( TF_COND_SPEED_BOOST, 7.f );
  237. }
  238. }
  239. int iHasRefillAmmo = 0;
  240. CALL_ATTRIB_HOOK_INT( iHasRefillAmmo, refill_ammo );
  241. if ( iHasRefillAmmo )
  242. {
  243. if ( m_bActive )
  244. {
  245. // Refill weapon clips
  246. for ( int i = 0; i < MAX_WEAPONS; i++ )
  247. {
  248. CBaseCombatWeapon *pWeapon = pTFPlayer->GetWeapon(i);
  249. if ( !pWeapon )
  250. continue;
  251. // ACHIEVEMENT_TF_MVM_USE_AMMO_BOTTLE
  252. if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
  253. {
  254. if ( ( pWeapon->UsesPrimaryAmmo() && !pWeapon->HasPrimaryAmmo() ) ||
  255. ( pWeapon->UsesSecondaryAmmo() && !pWeapon->HasSecondaryAmmo() ) )
  256. {
  257. pTFPlayer->AwardAchievement( ACHIEVEMENT_TF_MVM_USE_AMMO_BOTTLE );
  258. }
  259. }
  260. pWeapon->GiveDefaultAmmo();
  261. if ( iShareBottle && pHealTarget )
  262. {
  263. CBaseCombatWeapon *pPatientWeapon = pHealTarget->GetWeapon(i);
  264. if ( !pPatientWeapon )
  265. continue;
  266. pPatientWeapon->GiveDefaultAmmo();
  267. bBottleShared = true;
  268. }
  269. }
  270. // And give the player ammo
  271. for ( int iAmmo = 0; iAmmo < TF_AMMO_COUNT; ++iAmmo )
  272. {
  273. pTFPlayer->GiveAmmo( pTFPlayer->GetMaxAmmo(iAmmo), iAmmo, true, kAmmoSource_Resupply );
  274. if ( iShareBottle && pHealTarget )
  275. {
  276. pHealTarget->GiveAmmo( pHealTarget->GetMaxAmmo(iAmmo), iAmmo, true, kAmmoSource_Resupply );
  277. bBottleShared = true;
  278. }
  279. }
  280. }
  281. }
  282. int iHasInstaBuildingUpgrade = 0;
  283. CALL_ATTRIB_HOOK_INT( iHasInstaBuildingUpgrade, building_instant_upgrade );
  284. if ( iHasInstaBuildingUpgrade )
  285. {
  286. if ( m_bActive )
  287. {
  288. for ( int i = pTFPlayer->GetObjectCount()-1; i >= 0; i-- )
  289. {
  290. CBaseObject *pObj = pTFPlayer->GetObject(i);
  291. if ( pObj )
  292. {
  293. int nMaxLevel = pObj->GetMaxUpgradeLevel();
  294. // If object is carried, set the target max and move on
  295. if ( pObj->IsCarried() )
  296. {
  297. pObj->SetHighestUpgradeLevel( nMaxLevel );
  298. continue;
  299. }
  300. // If we're already at max level, heal
  301. if ( pObj->GetUpgradeLevel() == nMaxLevel )
  302. {
  303. pObj->SetHealth( pObj->GetMaxHealth() );
  304. }
  305. else
  306. {
  307. if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
  308. {
  309. if ( pObj->GetType() == OBJ_SENTRYGUN )
  310. {
  311. IGameEvent *event = gameeventmanager->CreateEvent( "mvm_quick_sentry_upgrade" );
  312. if ( event )
  313. {
  314. event->SetInt( "player", GetOwnerEntity()->entindex() );
  315. gameeventmanager->FireEvent( event );
  316. }
  317. }
  318. }
  319. pObj->DoQuickBuild( true );
  320. }
  321. }
  322. }
  323. }
  324. }
  325. // ACHIEVEMENT_TF_MVM_MEDIC_SHARE_BOTTLES
  326. if ( bBottleShared )
  327. {
  328. IGameEvent *event = gameeventmanager->CreateEvent( "mvm_medic_powerup_shared" );
  329. if ( event )
  330. {
  331. event->SetInt( "player", pTFPlayer->entindex() );
  332. gameeventmanager->FireEvent( event );
  333. }
  334. }
  335. }
  336. #endif
  337. }
  338. }
  339. //-----------------------------------------------------------------------------
  340. // Purpose: Removes the item and deactivates any effect
  341. //-----------------------------------------------------------------------------
  342. void CTFPowerupBottle::UnEquip( CBasePlayer* pOwner )
  343. {
  344. BaseClass::UnEquip( pOwner );
  345. RemoveEffect();
  346. }
  347. //-----------------------------------------------------------------------------
  348. // Purpose:
  349. //-----------------------------------------------------------------------------
  350. bool CTFPowerupBottle::Use()
  351. {
  352. if ( !m_bActive && GetNumCharges() > 0 )
  353. {
  354. if ( !AllowedToUse() )
  355. return false;
  356. #ifdef GAME_DLL
  357. // Use up one charge worth of refundable money when a charge is used
  358. class CAttributeIterator_ConsumeOneRefundableCharge : public IEconItemUntypedAttributeIterator
  359. {
  360. public:
  361. CAttributeIterator_ConsumeOneRefundableCharge( CAttributeList *pAttrList, int iNumCharges )
  362. : m_pAttrList( pAttrList )
  363. , m_iNumCharges( iNumCharges )
  364. {
  365. Assert( m_pAttrList );
  366. Assert( m_iNumCharges > 0 );
  367. }
  368. private:
  369. virtual bool OnIterateAttributeValueUntyped( const CEconItemAttributeDefinition *pAttrDef )
  370. {
  371. if ( ::FindAttribute( m_pAttrList, pAttrDef ) )
  372. {
  373. int nRefundableCurrency = m_pAttrList->GetRuntimeAttributeRefundableCurrency( pAttrDef );
  374. if ( nRefundableCurrency > 0 )
  375. {
  376. m_pAttrList->SetRuntimeAttributeRefundableCurrency( pAttrDef, nRefundableCurrency - (nRefundableCurrency / m_iNumCharges) );
  377. }
  378. }
  379. // Backwards compatibility -- assume any number of attributes.
  380. return true;
  381. }
  382. CAttributeList *m_pAttrList;
  383. int m_iNumCharges;
  384. };
  385. CAttributeIterator_ConsumeOneRefundableCharge it( GetAttributeList(), GetNumCharges() );
  386. GetAttributeList()->IterateAttributes( &it );
  387. #endif
  388. float flDuration = 0;
  389. CALL_ATTRIB_HOOK_FLOAT( flDuration, powerup_duration );
  390. // Add extra time?
  391. CTFPlayer *pOwner = ToTFPlayer( GetOwnerEntity() );
  392. if ( pOwner )
  393. {
  394. CALL_ATTRIB_HOOK_INT_ON_OTHER( pOwner, flDuration, canteen_specialist );
  395. }
  396. IGameEvent *event = gameeventmanager->CreateEvent( "player_used_powerup_bottle" );
  397. if ( event )
  398. {
  399. event->SetInt( "player", GetOwnerEntity()->entindex() );
  400. event->SetInt( "type", GetPowerupType() );
  401. event->SetFloat( "time", flDuration );
  402. gameeventmanager->FireEvent( event );
  403. }
  404. #ifdef GAME_DLL
  405. if ( pOwner )
  406. {
  407. EconEntity_OnOwnerKillEaterEventNoPartner( dynamic_cast<CEconEntity *>( this ), pOwner, kKillEaterEvent_PowerupBottlesUsed );
  408. // we consumed an upgrade - forget it
  409. pOwner->ForgetFirstUpgradeForItem( GetAttributeContainer()->GetItem() );
  410. }
  411. #endif
  412. SetNumCharges( GetNumCharges() - 1 );
  413. m_bActive = true;
  414. ReapplyProvision();
  415. SetContextThink( &CTFPowerupBottle::StatusThink, gpGlobals->curtime + flDuration, "PowerupBottleThink" );
  416. return true;
  417. }
  418. return false;
  419. }
  420. //-----------------------------------------------------------------------------
  421. // Purpose:
  422. //-----------------------------------------------------------------------------
  423. void CTFPowerupBottle::StatusThink()
  424. {
  425. RemoveEffect();
  426. }
  427. //-----------------------------------------------------------------------------
  428. // Purpose:
  429. //-----------------------------------------------------------------------------
  430. void CTFPowerupBottle::RemoveEffect()
  431. {
  432. m_bActive = false;
  433. ReapplyProvision();
  434. SetContextThink( NULL, 0, "PowerupBottleThink" );
  435. }
  436. //-----------------------------------------------------------------------------
  437. // Purpose:
  438. //-----------------------------------------------------------------------------
  439. void CTFPowerupBottle::SetNumCharges( uint8 usNumCharges )
  440. {
  441. static CSchemaAttributeDefHandle pAttrDef_PowerupCharges( "powerup charges" );
  442. m_usNumCharges = usNumCharges;
  443. if ( !pAttrDef_PowerupCharges )
  444. return;
  445. CEconItemView *pEconItemView = GetAttributeContainer()->GetItem();
  446. if ( !pEconItemView )
  447. return;
  448. pEconItemView->GetAttributeList()->SetRuntimeAttributeValue( pAttrDef_PowerupCharges, float( usNumCharges ) );
  449. }
  450. //-----------------------------------------------------------------------------
  451. // Purpose:
  452. //-----------------------------------------------------------------------------
  453. uint8 CTFPowerupBottle::GetNumCharges() const
  454. {
  455. return m_usNumCharges;
  456. }
  457. //-----------------------------------------------------------------------------
  458. // Purpose:
  459. //-----------------------------------------------------------------------------
  460. uint8 CTFPowerupBottle::GetMaxNumCharges() const
  461. {
  462. int iMaxNumCharges = 0;
  463. CALL_ATTRIB_HOOK_INT( iMaxNumCharges, powerup_max_charges );
  464. // Default canteen has 3 charges. Medic canteen specialist allows purchasing 3 more charges.
  465. // If anything else increases max charges, we need to refactor how canteen specialist is handled.
  466. Assert( iMaxNumCharges >= 0 && iMaxNumCharges <= 6 );
  467. iMaxNumCharges = Min( iMaxNumCharges, 6 );
  468. return (uint8)iMaxNumCharges;
  469. }
  470. //-----------------------------------------------------------------------------
  471. // Purpose:
  472. //-----------------------------------------------------------------------------
  473. bool CTFPowerupBottle::AllowedToUse()
  474. {
  475. if ( TFGameRules() && !( TFGameRules()->State_Get() == GR_STATE_BETWEEN_RNDS || TFGameRules()->State_Get() == GR_STATE_RND_RUNNING ) )
  476. return false;
  477. CTFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
  478. if ( !pPlayer )
  479. return false;
  480. if ( pPlayer->IsObserver() || !pPlayer->IsAlive() )
  481. return false;
  482. #ifdef GAME_DLL
  483. m_flLastSpawnTime = pPlayer->GetSpawnTime();
  484. #endif
  485. if ( gpGlobals->curtime < m_flLastSpawnTime + 0.7f )
  486. return false;
  487. return true;
  488. }
  489. const char* CTFPowerupBottle::GetEffectLabelText( void )
  490. {
  491. #ifndef GAME_DLL
  492. if ( cl_hud_minmode.GetBool() )
  493. {
  494. return "#TF_PVE_UsePowerup_MinMode";
  495. }
  496. #endif
  497. switch ( GetPowerupType() )
  498. {
  499. case POWERUP_BOTTLE_CRITBOOST:
  500. return "#TF_PVE_UsePowerup_CritBoost";
  501. case POWERUP_BOTTLE_UBERCHARGE:
  502. return "#TF_PVE_UsePowerup_Ubercharge";
  503. case POWERUP_BOTTLE_RECALL:
  504. return "#TF_PVE_UsePowerup_Recall";
  505. case POWERUP_BOTTLE_REFILL_AMMO:
  506. return "#TF_PVE_UsePowerup_RefillAmmo";
  507. case POWERUP_BOTTLE_BUILDINGS_INSTANT_UPGRADE:
  508. return "#TF_PVE_UsePowerup_BuildinginstaUpgrade";
  509. case POWERUP_BOTTLE_RADIUS_STEALTH:
  510. return "#TF_PVE_UsePowerup_RadiusStealth";
  511. #ifdef STAGING_ONLY
  512. case POWERUP_BOTTLE_SEE_CASH_THROUGH_WALL:
  513. return "#TF_PVE_UsePowerup_SeeCashThroughWall";
  514. #endif
  515. }
  516. return "#TF_PVE_UsePowerup_CritBoost";
  517. }
  518. const char* CTFPowerupBottle::GetEffectIconName( void )
  519. {
  520. switch ( GetPowerupType() )
  521. {
  522. case POWERUP_BOTTLE_CRITBOOST:
  523. return "../hud/ico_powerup_critboost_red";
  524. case POWERUP_BOTTLE_UBERCHARGE:
  525. return "../hud/ico_powerup_ubercharge_red";
  526. case POWERUP_BOTTLE_RECALL:
  527. return "../hud/ico_powerup_recall_red";
  528. case POWERUP_BOTTLE_REFILL_AMMO:
  529. return "../hud/ico_powerup_refill_ammo_red";
  530. case POWERUP_BOTTLE_BUILDINGS_INSTANT_UPGRADE:
  531. return "../hud/ico_powerup_building_instant_red";
  532. case POWERUP_BOTTLE_RADIUS_STEALTH:
  533. return "../vgui/achievements/tf_soldier_kill_spy_killer";
  534. #ifdef STAGING_ONLY
  535. case POWERUP_BOTTLE_SEE_CASH_THROUGH_WALL:
  536. return "../vgui/achievements/tf_mvm_earn_money_bonus";
  537. #endif
  538. }
  539. return "../hud/ico_powerup_critboost_red";
  540. }
  541. #ifdef TF_CLIENT_DLL
  542. void CTFPowerupBottle::FireGameEvent( IGameEvent *event )
  543. {
  544. const char *pszEventName = event->GetName();
  545. if ( FStrEq( pszEventName, "player_spawn" ) )
  546. {
  547. CTFPlayer *pTFOwner = ToTFPlayer( GetOwnerEntity() );
  548. if ( !pTFOwner )
  549. return;
  550. const int nUserID = event->GetInt( "userid" );
  551. CTFPlayer *pPlayer = ToTFPlayer( UTIL_PlayerByUserId( nUserID ) );
  552. if ( pPlayer && pPlayer == pTFOwner )
  553. {
  554. m_flLastSpawnTime = gpGlobals->curtime;
  555. }
  556. }
  557. }
  558. int CTFPowerupBottle::GetWorldModelIndex( void )
  559. {
  560. if ( IsBasePowerUpBottle() && ( GetNumCharges() > 0 ) )
  561. {
  562. switch ( GetPowerupType() )
  563. {
  564. case POWERUP_BOTTLE_CRITBOOST:
  565. return modelinfo->GetModelIndex( "models/player/items/mvm_loot/all_class/mvm_flask_krit.mdl" );
  566. case POWERUP_BOTTLE_UBERCHARGE:
  567. return modelinfo->GetModelIndex( "models/player/items/mvm_loot/all_class/mvm_flask_uber.mdl" );
  568. case POWERUP_BOTTLE_RECALL:
  569. return modelinfo->GetModelIndex( "models/player/items/mvm_loot/all_class/mvm_flask_tele.mdl" );
  570. case POWERUP_BOTTLE_REFILL_AMMO:
  571. return modelinfo->GetModelIndex( "models/player/items/mvm_loot/all_class/mvm_flask_ammo.mdl" );
  572. case POWERUP_BOTTLE_BUILDINGS_INSTANT_UPGRADE:
  573. return modelinfo->GetModelIndex( "models/player/items/mvm_loot/all_class/mvm_flask_build.mdl" );
  574. case POWERUP_BOTTLE_RADIUS_STEALTH:
  575. #ifdef STAGING_ONLY
  576. case POWERUP_BOTTLE_SEE_CASH_THROUGH_WALL:
  577. #endif
  578. return modelinfo->GetModelIndex( "models/player/items/mvm_loot/all_class/mvm_flask_tele.mdl" );
  579. }
  580. }
  581. return BaseClass::GetWorldModelIndex();
  582. }
  583. #endif
  584. int CTFPowerupBottle::GetSkin()
  585. {
  586. if ( !IsBasePowerUpBottle() )
  587. {
  588. return ( ( GetNumCharges() > 0 ) ? 1 : 0 );
  589. }
  590. return BaseClass::GetSkin();
  591. }
  592. #ifdef CLIENT_DLL
  593. // ******************************************************************************************
  594. // CEquipMvMCanteenNotification - Client notification to equip a canteen
  595. // ******************************************************************************************
  596. void CEquipMvMCanteenNotification::Accept()
  597. {
  598. m_bHasTriggered = true;
  599. CPlayerInventory *pLocalInv = TFInventoryManager()->GetLocalInventory();
  600. if ( !pLocalInv )
  601. {
  602. MarkForDeletion();
  603. return;
  604. }
  605. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  606. if ( !pLocalPlayer )
  607. {
  608. MarkForDeletion();
  609. return;
  610. }
  611. // try to equip non-stock-spellbook first
  612. static CSchemaItemDefHandle pItemDef_Robo( "Battery Canteens" );
  613. static CSchemaItemDefHandle pItemDef_KritzOrTreat( "Kritz Or Treat Canteen" );
  614. static CSchemaItemDefHandle pItemDef_Canteen( "Power Up Canteen (MvM)" );
  615. static CSchemaItemDefHandle pItemDef_DefaultCanteen( "Default Power Up Canteen (MvM)" );
  616. CEconItemView *pCanteen= NULL;
  617. Assert( pItemDef_Robo );
  618. Assert( pItemDef_KritzOrTreat );
  619. Assert( pItemDef_Canteen );
  620. Assert( pItemDef_DefaultCanteen );
  621. for ( int i = 0; i < pLocalInv->GetItemCount(); ++i )
  622. {
  623. CEconItemView *pItem = pLocalInv->GetItem( i );
  624. Assert( pItem );
  625. if ( pItem->GetItemDefinition() == pItemDef_Robo
  626. || pItem->GetItemDefinition() == pItemDef_KritzOrTreat
  627. || pItem->GetItemDefinition() == pItemDef_Canteen
  628. || pItem->GetItemDefinition() == pItemDef_DefaultCanteen
  629. ) {
  630. pCanteen = pItem;
  631. break;
  632. }
  633. }
  634. // Default item becomes a spellbook in this mode
  635. itemid_t iItemId = INVALID_ITEM_ID;
  636. if ( pCanteen )
  637. {
  638. iItemId = pCanteen->GetItemID();
  639. }
  640. TFInventoryManager()->EquipItemInLoadout( pLocalPlayer->GetPlayerClass()->GetClassIndex(), LOADOUT_POSITION_ACTION, iItemId );
  641. // Tell the GC to tell server that we should respawn if we're in a respawn room
  642. GCSDK::CGCMsg< GCSDK::MsgGCEmpty_t > msg( k_EMsgGCRespawnPostLoadoutChange );
  643. GCClientSystem()->BSendMessage( msg );
  644. MarkForDeletion();
  645. }
  646. //===========================================================================================
  647. void CEquipMvMCanteenNotification::UpdateTick()
  648. {
  649. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  650. if ( pLocalPlayer )
  651. {
  652. CTFPowerupBottle *pCanteen = dynamic_cast<CTFPowerupBottle*>( TFInventoryManager()->GetItemInLoadoutForClass( pLocalPlayer->GetPlayerClass()->GetClassIndex(), LOADOUT_POSITION_ACTION ) );
  653. if ( pCanteen )
  654. {
  655. MarkForDeletion();
  656. }
  657. }
  658. }
  659. #endif // client