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.

498 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "tf_weapon_buff_item.h"
  8. #include "tf_gamerules.h"
  9. // Client specific.
  10. #ifdef CLIENT_DLL
  11. #include "c_tf_player.h"
  12. #include "c_baseentity.h"
  13. // Server specific.
  14. #else
  15. #include "tf_player.h"
  16. #include "tf_gamestats.h"
  17. #endif
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. //=============================================================================
  21. //
  22. // Weapon Buff Item tables.
  23. //
  24. IMPLEMENT_NETWORKCLASS_ALIASED( TFBuffItem, DT_TFWeaponBuffItem )
  25. BEGIN_NETWORK_TABLE( CTFBuffItem, DT_TFWeaponBuffItem )
  26. END_NETWORK_TABLE()
  27. BEGIN_PREDICTION_DATA( CTFBuffItem )
  28. END_PREDICTION_DATA()
  29. LINK_ENTITY_TO_CLASS( tf_weapon_buff_item, CTFBuffItem );
  30. PRECACHE_WEAPON_REGISTER( tf_weapon_buff_item );
  31. // Models and Buffs need to be aligned
  32. const char* BannerModels[] =
  33. {
  34. "models/weapons/c_models/c_buffbanner/c_buffbanner.mdl",
  35. #ifdef STAGING_ONLY
  36. "models/workshop/weapons/c_models/c_battalion_buffbanner/c_battalion_buffbanner.mdl",
  37. "models/workshop_partner/weapons/c_models/c_shogun_warbanner/c_shogun_warbanner.mdl",
  38. #else
  39. "models/weapons/c_models/c_battalion_buffbanner/c_batt_buffbanner.mdl",
  40. "models/weapons/c_models/c_shogun_warbanner/c_shogun_warbanner.mdl",
  41. #endif
  42. "models/workshop/weapons/c_models/c_paratooper_pack/c_paratrooper_parachute.mdl"
  43. };
  44. #define CLOSED_PARACHUTE_MDL "models/workshop/weapons/c_models/c_paratooper_pack/c_paratrooper_pack.mdl"
  45. #define OPEN_PARACHUTE_MDL "models/workshop/weapons/c_models/c_paratooper_pack/c_paratrooper_pack_open.mdl"
  46. COMPILE_TIME_ASSERT( ARRAYSIZE( BannerModels ) == NUM_BUFF_ITEM_TYPES );
  47. //=============================================================================
  48. //
  49. // Weapon Buff Item functions.
  50. //
  51. //-----------------------------------------------------------------------------
  52. // Purpose:
  53. //-----------------------------------------------------------------------------
  54. CTFBuffItem::CTFBuffItem()
  55. {
  56. #ifdef CLIENT_DLL
  57. ListenForGameEvent( "deploy_buff_banner" );
  58. m_iBuffType = -1;
  59. m_hBannerEntity = NULL;
  60. #endif
  61. m_bPlayingHorn = false;
  62. UseClientSideAnimation();
  63. }
  64. //-----------------------------------------------------------------------------
  65. // Purpose:
  66. //-----------------------------------------------------------------------------
  67. CTFBuffItem::~CTFBuffItem()
  68. {
  69. #ifdef CLIENT_DLL
  70. if ( m_hBannerEntity )
  71. {
  72. m_hBannerEntity->Release();
  73. m_hBannerEntity = NULL;
  74. }
  75. #endif
  76. }
  77. //-----------------------------------------------------------------------------
  78. // Purpose:
  79. //-----------------------------------------------------------------------------
  80. void CTFBuffItem::Precache()
  81. {
  82. // Need to make this dynamic, but the item data isn't available here?
  83. for ( int i=0; i<ARRAYSIZE(BannerModels); i++ )
  84. {
  85. PrecacheModel( BannerModels[i] );
  86. }
  87. PrecacheModel( "models/weapons/c_models/c_buffpack/c_buffpack.mdl" );
  88. #ifdef STAGING_ONLY
  89. PrecacheModel( "models/workshop/weapons/c_models/c_battalion_buffpack/c_battalion_buffpack.mdl" );
  90. PrecacheModel( "models/workshop_partner/weapons/c_models/c_shogun_warpack/c_shogun_warpack.mdl" );
  91. #else
  92. PrecacheModel( "models/weapons/c_models/c_battalion_buffpack/c_batt_buffpack.mdl" );
  93. PrecacheModel( "models/weapons/c_models/c_shogun_warpack/c_shogun_warpack.mdl" );
  94. #endif
  95. PrecacheModel( OPEN_PARACHUTE_MDL );
  96. PrecacheModel( CLOSED_PARACHUTE_MDL );
  97. PrecacheScriptSound( "Weapon_BuffBanner.HornRed" );
  98. PrecacheScriptSound( "Weapon_BuffBanner.HornBlue" );
  99. PrecacheScriptSound( "Weapon_BattalionsBackup.HornRed" );
  100. PrecacheScriptSound( "Weapon_BattalionsBackup.HornBlue" );
  101. PrecacheScriptSound( "Weapon_BuffBanner.Flag" );
  102. PrecacheScriptSound( "Samurai.Conch" );
  103. BaseClass::Precache();
  104. }
  105. // -----------------------------------------------------------------------------
  106. // Purpose:
  107. // -----------------------------------------------------------------------------
  108. void CTFBuffItem::PrimaryAttack()
  109. {
  110. if ( !CanAttack() )
  111. return;
  112. CTFPlayer* pPlayer = ToTFPlayer( GetPlayerOwner() );
  113. if ( !pPlayer )
  114. return;
  115. if ( pPlayer->m_Shared.GetRageMeter() < 100.f )
  116. return;
  117. if ( m_bPlayingHorn )
  118. return;
  119. if ( pPlayer->GetTeamNumber() == TF_TEAM_RED )
  120. {
  121. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_PRIMARY );
  122. SendWeaponAnim( ACT_VM_PRIMARYATTACK );
  123. }
  124. else
  125. {
  126. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_SECONDARY );
  127. SendWeaponAnim( ACT_VM_SECONDARYATTACK );
  128. }
  129. SetContextThink( &CTFBuffItem::BlowHorn, gpGlobals->curtime + 0.22f, "BlowHorn" );
  130. }
  131. //-----------------------------------------------------------------------------
  132. // Purpose: Attaches the item to the player.
  133. //-----------------------------------------------------------------------------
  134. void CTFBuffItem::Equip( CBaseCombatCharacter* pOwner )
  135. {
  136. BaseClass::Equip( pOwner );
  137. CTFPlayer *pTFPlayer = ToTFPlayer( pOwner );
  138. if ( pTFPlayer )
  139. {
  140. pTFPlayer->m_Shared.SetParachuteEquipped( true );
  141. }
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Purpose: Remove item from the player.
  145. //-----------------------------------------------------------------------------
  146. void CTFBuffItem::Detach( void )
  147. {
  148. CTFPlayer *pTFPlayer = GetTFPlayerOwner();
  149. if ( pTFPlayer )
  150. {
  151. pTFPlayer->m_Shared.SetParachuteEquipped( false );
  152. }
  153. BaseClass::Detach();
  154. }
  155. //-----------------------------------------------------------------------------
  156. // Purpose:
  157. //-----------------------------------------------------------------------------
  158. void CTFBuffItem::BlowHorn( void )
  159. {
  160. CTFPlayer* pPlayer = ToTFPlayer( GetPlayerOwner() );
  161. if ( !pPlayer )
  162. return;
  163. if ( !pPlayer->IsAlive() )
  164. return;
  165. #ifdef GAME_DLL
  166. // Use the buff type to try and figure out what sort of mesh we have and what
  167. // sort of sound to play. This isn't the cleanest thing in the world.
  168. int iBuffType = 0;
  169. CALL_ATTRIB_HOOK_INT( iBuffType, set_buff_type );
  170. // Samurai conch shell.
  171. if ( iBuffType == EConcheror )
  172. {
  173. pPlayer->EmitSound( "Samurai.Conch" );
  174. }
  175. // Bugle.
  176. else if ( iBuffType == EBuffBanner )
  177. {
  178. if ( pPlayer->GetTeamNumber() == TF_TEAM_BLUE )
  179. {
  180. pPlayer->EmitSound( "Weapon_BuffBanner.HornBlue" );
  181. }
  182. else
  183. {
  184. pPlayer->EmitSound( "Weapon_BuffBanner.HornRed" );
  185. }
  186. }
  187. else if ( iBuffType == EBattalion )
  188. {
  189. if ( pPlayer->GetTeamNumber() == TF_TEAM_BLUE )
  190. {
  191. pPlayer->EmitSound( "Weapon_BattalionsBackup.HornBlue" );
  192. }
  193. else
  194. {
  195. pPlayer->EmitSound( "Weapon_BattalionsBackup.HornRed" );
  196. }
  197. }
  198. // Strange Tracking
  199. if ( !pPlayer->IsBot() )
  200. {
  201. EconEntity_OnOwnerKillEaterEventNoPartner( dynamic_cast<CEconEntity *>( this ), pPlayer, kKillEaterEvent_BannersDeployed );
  202. }
  203. #endif
  204. m_bPlayingHorn = true;
  205. }
  206. //-----------------------------------------------------------------------------
  207. // Purpose:
  208. //-----------------------------------------------------------------------------
  209. void CTFBuffItem::RaiseFlag( void )
  210. {
  211. CTFPlayer* pPlayer = ToTFPlayer( GetPlayerOwner() );
  212. if ( !pPlayer )
  213. return;
  214. if ( !pPlayer->IsAlive() )
  215. return;
  216. m_bPlayingHorn = false;
  217. int iBuffType = 0;
  218. CALL_ATTRIB_HOOK_INT( iBuffType, set_buff_type );
  219. #if GAME_DLL
  220. // this event needs to be sent before we call ActivateSoldierBuff() below
  221. IGameEvent* event = gameeventmanager->CreateEvent( "deploy_buff_banner" );
  222. if ( event )
  223. {
  224. event->SetInt( "buff_type", iBuffType );
  225. event->SetInt( "buff_owner", pPlayer->GetUserID() );
  226. gameeventmanager->FireEvent( event );
  227. }
  228. pPlayer->EmitSound( "Weapon_BuffBanner.Flag" );
  229. pPlayer->SpeakConceptIfAllowed( MP_CONCEPT_PLAYER_BATTLECRY );
  230. #endif
  231. pPlayer->m_Shared.ActivateRageBuff( this, iBuffType );
  232. pPlayer->SelectLastItem();
  233. }
  234. //-----------------------------------------------------------------------------
  235. // Don't let them holster while they are blowing the horn.
  236. //-----------------------------------------------------------------------------
  237. bool CTFBuffItem::Holster( CBaseCombatWeapon *pSwitchingTo )
  238. {
  239. if ( m_bPlayingHorn )
  240. {
  241. return false;
  242. }
  243. else
  244. {
  245. return BaseClass::Holster( pSwitchingTo );
  246. }
  247. }
  248. //-----------------------------------------------------------------------------
  249. // Purpose:
  250. //-----------------------------------------------------------------------------
  251. void CTFBuffItem::FireGameEvent( IGameEvent* event )
  252. {
  253. #ifdef CLIENT_DLL
  254. const char *name = event->GetName();
  255. if ( 0 == Q_strcmp( name, "deploy_buff_banner" ) )
  256. {
  257. CTFPlayer* pPlayer = ToTFPlayer( ClientEntityList().GetEnt( engine->GetPlayerForUserID( event->GetInt( "buff_owner" ) ) ) );
  258. if ( pPlayer == GetOwner() )
  259. {
  260. CreateBanner();
  261. }
  262. }
  263. BaseClass::FireGameEvent( event );
  264. #endif
  265. }
  266. // -----------------------------------------------------------------------------
  267. // Purpose:
  268. // -----------------------------------------------------------------------------
  269. void CTFBuffItem::CreateBanner()
  270. {
  271. #ifdef CLIENT_DLL
  272. if ( m_hBannerEntity == NULL )
  273. {
  274. CTFPlayer* pPlayer = ToTFPlayer( GetPlayerOwner() );
  275. if ( !pPlayer || !pPlayer->IsAlive() )
  276. return;
  277. C_TFBuffBanner* pBanner = new C_TFBuffBanner;
  278. if ( !pBanner )
  279. return;
  280. //Assert( iBuffType > 0 );
  281. //Assert( iBuffType <= ARRAYSIZE(BannerModels) );
  282. pBanner->m_nSkin = 0;
  283. pBanner->InitializeAsClientEntity( BannerModels[GetBuffType()-1], RENDER_GROUP_OPAQUE_ENTITY );
  284. pBanner->SetBuffItem( this );
  285. pBanner->SetBuffType( GetBuffType() );
  286. pBanner->ForceClientSideAnimationOn();
  287. SetBanner( pBanner );
  288. int iSpine = pPlayer->LookupBone( "bip_spine_3" );
  289. Assert( iSpine != -1 );
  290. if ( iSpine != -1 )
  291. {
  292. pBanner->AttachEntityToBone( pPlayer, iSpine );
  293. }
  294. }
  295. #endif
  296. }
  297. #ifdef CLIENT_DLL
  298. //-----------------------------------------------------------------------------
  299. void CTFBuffItem::NotifyShouldTransmit( ShouldTransmitState_t state )
  300. {
  301. if ( state == SHOULDTRANSMIT_END )
  302. {
  303. // Kill the item - It will be recreated later
  304. if ( m_hBannerEntity )
  305. {
  306. m_hBannerEntity->Release();
  307. m_hBannerEntity = NULL;
  308. }
  309. }
  310. BaseClass::NotifyShouldTransmit( state );
  311. }
  312. void CTFBuffItem::OnDataChanged( DataUpdateType_t updateType )
  313. {
  314. if ( updateType == DATA_UPDATE_CREATED )
  315. {
  316. SetNextClientThink( CLIENT_THINK_ALWAYS );
  317. }
  318. BaseClass::OnDataChanged( updateType );
  319. }
  320. void CTFBuffItem::ClientThink( void )
  321. {
  322. if ( m_iBuffType == -1 || m_iBuffType == 0 )
  323. {
  324. m_iBuffType = GetBuffType();
  325. if ( m_iBuffType != EParachute )
  326. {
  327. SetNextClientThink( CLIENT_THINK_NEVER );
  328. }
  329. }
  330. }
  331. #endif // CLIENT_DLL
  332. //-----------------------------------------------------------------------------
  333. // Purpose:
  334. //-----------------------------------------------------------------------------
  335. void CTFBuffItem::WeaponReset( void )
  336. {
  337. BaseClass::WeaponReset();
  338. m_bPlayingHorn = false;
  339. }
  340. //-----------------------------------------------------------------------------
  341. // Purpose:
  342. //-----------------------------------------------------------------------------
  343. bool CTFBuffItem::SendWeaponAnim( int iActivity )
  344. {
  345. CTFPlayer *pPlayer = GetTFPlayerOwner();
  346. if ( !pPlayer )
  347. return BaseClass::SendWeaponAnim( iActivity );
  348. switch ( iActivity )
  349. {
  350. case ACT_VM_DRAW:
  351. iActivity = ACT_ITEM1_VM_DRAW;
  352. break;
  353. case ACT_VM_HOLSTER:
  354. iActivity = ACT_ITEM1_VM_HOLSTER;
  355. break;
  356. case ACT_VM_IDLE:
  357. if ( m_bPlayingHorn )
  358. {
  359. RaiseFlag();
  360. iActivity = ACT_RESET;
  361. }
  362. else
  363. {
  364. iActivity = ACT_ITEM1_VM_IDLE;
  365. }
  366. break;
  367. case ACT_VM_PULLBACK:
  368. iActivity = ACT_ITEM1_VM_PULLBACK;
  369. break;
  370. case ACT_VM_PRIMARYATTACK:
  371. m_bPlayingHorn = true;
  372. iActivity = ACT_ITEM1_VM_PRIMARYATTACK;
  373. break;
  374. case ACT_VM_SECONDARYATTACK:
  375. m_bPlayingHorn = true;
  376. iActivity = ACT_ITEM1_VM_SECONDARYATTACK;
  377. break;
  378. case ACT_VM_IDLE_TO_LOWERED:
  379. iActivity = ACT_ITEM1_VM_IDLE_TO_LOWERED;
  380. break;
  381. case ACT_VM_IDLE_LOWERED:
  382. iActivity = ACT_ITEM1_VM_IDLE_LOWERED;
  383. break;
  384. case ACT_VM_LOWERED_TO_IDLE:
  385. iActivity = ACT_ITEM1_VM_LOWERED_TO_IDLE;
  386. break;
  387. default:
  388. break;
  389. }
  390. return BaseClass::SendWeaponAnim( iActivity );
  391. }
  392. bool CTFBuffItem::CanReload( void )
  393. {
  394. return false;
  395. }
  396. //-----------------------------------------------------------------------------
  397. // Purpose: UI Progress
  398. //-----------------------------------------------------------------------------
  399. float CTFBuffItem::GetProgress( void )
  400. {
  401. CTFPlayer *pPlayer = GetTFPlayerOwner();
  402. if ( !pPlayer )
  403. return 0.f;
  404. return pPlayer->m_Shared.GetRageMeter() / 100.0f;
  405. }
  406. //-----------------------------------------------------------------------------
  407. // Purpose: UI Progress (same as GetProgress() without the division by 100.0f)
  408. //-----------------------------------------------------------------------------
  409. bool CTFBuffItem::IsFull( void )
  410. {
  411. CTFPlayer *pPlayer = GetTFPlayerOwner();
  412. if ( !pPlayer )
  413. return false;
  414. return ( pPlayer->m_Shared.GetRageMeter() >= 100.0f );
  415. }
  416. //-----------------------------------------------------------------------------
  417. // Purpose:
  418. //-----------------------------------------------------------------------------
  419. bool CTFBuffItem::EffectMeterShouldFlash( void )
  420. {
  421. CTFPlayer *pPlayer = GetTFPlayerOwner();
  422. if ( !pPlayer )
  423. return false;
  424. if ( pPlayer && (IsFull() || pPlayer->m_Shared.IsRageDraining()) )
  425. return true;
  426. else
  427. return false;
  428. }