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.

499 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // TF Rocket Launcher
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "tf_weapon_particle_cannon.h"
  8. #include "tf_fx_shared.h"
  9. #include "in_buttons.h"
  10. // Client specific.
  11. #ifdef CLIENT_DLL
  12. #include "c_tf_player.h"
  13. #include <vgui_controls/Panel.h>
  14. #include <vgui/ISurface.h>
  15. #include "soundenvelope.h"
  16. #include "particle_property.h"
  17. #include "c_tf_gamestats.h"
  18. // Server specific.
  19. #else
  20. #include "tf_gamestats.h"
  21. #include "tf_player.h"
  22. #include "tf_projectile_energy_ball.h"
  23. #endif
  24. //=============================================================================
  25. //
  26. // Particle cannon tables.
  27. //
  28. IMPLEMENT_NETWORKCLASS_ALIASED( TFParticleCannon, DT_ParticleCannon )
  29. BEGIN_NETWORK_TABLE( CTFParticleCannon, DT_ParticleCannon )
  30. #ifdef CLIENT_DLL
  31. RecvPropFloat( RECVINFO( m_flChargeBeginTime ) ),
  32. RecvPropInt( RECVINFO( m_iChargeEffect ) )
  33. #else
  34. SendPropFloat( SENDINFO( m_flChargeBeginTime ) ),
  35. SendPropInt( SENDINFO( m_iChargeEffect ) )
  36. #endif
  37. END_NETWORK_TABLE()
  38. BEGIN_PREDICTION_DATA( CTFParticleCannon )
  39. END_PREDICTION_DATA()
  40. LINK_ENTITY_TO_CLASS( tf_weapon_particle_cannon, CTFParticleCannon );
  41. PRECACHE_WEAPON_REGISTER( tf_weapon_particle_cannon );
  42. // Server specific.
  43. #ifndef CLIENT_DLL
  44. BEGIN_DATADESC( CTFParticleCannon )
  45. END_DATADESC()
  46. #endif
  47. //-----------------------------------------------------------------------------
  48. // Purpose:
  49. //-----------------------------------------------------------------------------
  50. CTFParticleCannon::CTFParticleCannon() : CTFRocketLauncher()
  51. {
  52. #ifdef CLIENT_DLL
  53. m_bEffectsThinking = false;
  54. m_iChargeEffectBase = 0;
  55. #endif
  56. }
  57. //-----------------------------------------------------------------------------
  58. // Purpose:
  59. //-----------------------------------------------------------------------------
  60. float CTFParticleCannon::GetProjectileSpeed( void )
  61. {
  62. return 1100.f;
  63. }
  64. //-----------------------------------------------------------------------------
  65. // Purpose:
  66. //-----------------------------------------------------------------------------
  67. float CTFParticleCannon::GetProjectileGravity( void )
  68. {
  69. return 0.f;
  70. }
  71. //-----------------------------------------------------------------------------
  72. // Purpose:
  73. //-----------------------------------------------------------------------------
  74. bool CTFParticleCannon::IsViewModelFlipped( void )
  75. {
  76. return !BaseClass::IsViewModelFlipped(); // Invert because arrows are backwards by default.
  77. }
  78. //-----------------------------------------------------------------------------
  79. // Purpose: Reset the charge when we holster
  80. //-----------------------------------------------------------------------------
  81. bool CTFParticleCannon::Holster( CBaseCombatWeapon *pSwitchingTo )
  82. {
  83. CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
  84. if ( pPlayer && pPlayer->m_Shared.InCond( TF_COND_AIMING ) )
  85. return false;
  86. m_flChargeBeginTime = 0;
  87. #ifdef CLIENT_DLL
  88. ParticleProp()->Init( this );
  89. ParticleProp()->StopParticlesNamed( "drg_cowmangler_idle", true );
  90. m_bEffectsThinking = false;
  91. #endif
  92. StopSound( "Weapon_CowMangler.Charging" );
  93. return BaseClass::Holster( pSwitchingTo );
  94. }
  95. //-----------------------------------------------------------------------------
  96. // Purpose: Reset the charge when we deploy
  97. //-----------------------------------------------------------------------------
  98. bool CTFParticleCannon::Deploy( void )
  99. {
  100. m_flChargeBeginTime = 0;
  101. #ifdef CLIENT_DLL
  102. m_bEffectsThinking = true;
  103. SetContextThink( &CTFParticleCannon::ClientEffectsThink, gpGlobals->curtime + rand() % 5, "PC_EFFECTS_THINK" );
  104. #endif
  105. return BaseClass::Deploy();
  106. }
  107. //-----------------------------------------------------------------------------
  108. // Purpose:
  109. //-----------------------------------------------------------------------------
  110. void CTFParticleCannon::WeaponReset( void )
  111. {
  112. BaseClass::WeaponReset();
  113. m_flChargeBeginTime = 0.0f;
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Purpose:
  117. //-----------------------------------------------------------------------------
  118. void CTFParticleCannon::ItemPostFrame( void )
  119. {
  120. BaseClass::ItemPostFrame();
  121. if ( m_flChargeBeginTime > 0 )
  122. {
  123. CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
  124. if ( !pPlayer )
  125. return;
  126. // If we're not holding down the attack button, launch our grenade
  127. float flTotalChargeTime = gpGlobals->curtime - m_flChargeBeginTime;
  128. if ( flTotalChargeTime >= GetChargeForceReleaseTime() )
  129. {
  130. FireChargedShot();
  131. }
  132. }
  133. #ifdef CLIENT_DLL
  134. if ( !m_bEffectsThinking )
  135. {
  136. m_bEffectsThinking = true;
  137. SetContextThink( &CTFParticleCannon::ClientEffectsThink, gpGlobals->curtime + rand() % 5, "PC_EFFECTS_THINK" );
  138. }
  139. #endif
  140. }
  141. //-----------------------------------------------------------------------------
  142. // Purpose:
  143. //-----------------------------------------------------------------------------
  144. void CTFParticleCannon::PrimaryAttack( void )
  145. {
  146. if ( m_flChargeBeginTime > 0 )
  147. return;
  148. if ( !Energy_HasEnergy() )
  149. return;
  150. m_bChargedShot = false;
  151. BaseClass::PrimaryAttack();
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Purpose:
  155. //-----------------------------------------------------------------------------
  156. void CTFParticleCannon::SecondaryAttack( void )
  157. {
  158. // Check for ammunition.
  159. if ( !Energy_FullyCharged() )
  160. {
  161. Reload();
  162. return;
  163. }
  164. // Are we capable of firing again?
  165. if ( m_flNextPrimaryAttack > gpGlobals->curtime )
  166. return;
  167. if ( m_flChargeBeginTime > 0 )
  168. return;
  169. if ( !CanAttack() )
  170. {
  171. m_flChargeBeginTime = 0;
  172. return;
  173. }
  174. m_bChargedShot = true;
  175. // Set the weapon mode.
  176. m_iWeaponMode = TF_WEAPON_PRIMARY_MODE;
  177. // save that we had the attack button down
  178. m_flChargeBeginTime = gpGlobals->curtime;
  179. CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
  180. if ( pPlayer )
  181. {
  182. SendWeaponAnim( ACT_PRIMARY_VM_PRIMARYATTACK_3 );
  183. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_PRIMARY_SUPER );
  184. }
  185. WeaponSound( SPECIAL1 );
  186. pPlayer->m_Shared.AddCond( TF_COND_AIMING );
  187. pPlayer->TeamFortress_SetSpeed();
  188. m_iChargeEffect++;
  189. }
  190. #ifdef CLIENT_DLL
  191. //-----------------------------------------------------------------------------
  192. // Purpose:
  193. //-----------------------------------------------------------------------------
  194. void CTFParticleCannon::CreateChargeEffect()
  195. {
  196. CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
  197. if ( pPlayer )
  198. {
  199. DispatchParticleEffect( "drg_cowmangler_muzzleflash_chargeup", PATTACH_POINT_FOLLOW, GetAppropriateWorldOrViewModel(), "muzzle", GetParticleColor( 1 ), GetParticleColor( 2 ) );
  200. }
  201. }
  202. #endif
  203. //-----------------------------------------------------------------------------
  204. // Purpose:
  205. //-----------------------------------------------------------------------------
  206. void CTFParticleCannon::FireChargedShot()
  207. {
  208. CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
  209. if ( !pPlayer )
  210. return;
  211. if ( !pPlayer->IsAlive() )
  212. return;
  213. pPlayer->m_Shared.RemoveCond( TF_COND_AIMING );
  214. pPlayer->TeamFortress_SetSpeed();
  215. #ifndef CLIENT_DLL
  216. CTF_GameStats.Event_PlayerFiredWeapon( pPlayer, false );
  217. #else
  218. C_CTF_GameStats.Event_PlayerFiredWeapon( pPlayer, false );
  219. #endif
  220. // SendWeaponAnim( ACT_VM_PRIMARYATTACK );
  221. // pPlayer->SetAnimation( PLAYER_ATTACK1 );
  222. CBaseEntity* pProj = FireProjectile( pPlayer );
  223. ModifyProjectile( pProj );
  224. float flFireDelay = ApplyFireDelay( m_pWeaponInfo->GetWeaponData( m_iWeaponMode ).m_flTimeFireDelay );
  225. m_flNextPrimaryAttack = gpGlobals->curtime + flFireDelay;
  226. SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() );
  227. m_iReloadMode.Set( TF_RELOAD_START );
  228. m_flChargeBeginTime = 0.0f;
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Purpose:
  232. //-----------------------------------------------------------------------------
  233. void CTFParticleCannon::ModifyProjectile( CBaseEntity* pProj )
  234. {
  235. #ifdef GAME_DLL
  236. CTFProjectile_EnergyBall* pEnergyBall = dynamic_cast<CTFProjectile_EnergyBall*>( pProj );
  237. if ( pEnergyBall == NULL )
  238. return;
  239. pEnergyBall->SetChargedShot( m_bChargedShot );
  240. pEnergyBall->SetColor( 1, GetParticleColor( 1 ) );
  241. pEnergyBall->SetColor( 2, GetParticleColor( 2 ) );
  242. #endif
  243. if ( m_bChargedShot )
  244. {
  245. Energy_DrainEnergy( Energy_GetMaxEnergy() );
  246. }
  247. else
  248. {
  249. Energy_DrainEnergy();
  250. }
  251. }
  252. //-----------------------------------------------------------------------------
  253. // Purpose:
  254. //-----------------------------------------------------------------------------
  255. float CTFParticleCannon::GetProgress( void )
  256. {
  257. return Energy_GetEnergy() / Energy_GetMaxEnergy();
  258. }
  259. //-----------------------------------------------------------------------------
  260. // Purpose:
  261. //-----------------------------------------------------------------------------
  262. const char *CTFParticleCannon::GetMuzzleFlashParticleEffect( void )
  263. {
  264. if ( m_bChargedShot )
  265. {
  266. return ( GetTeamNumber() == TF_TEAM_RED ) ? "drg_cow_muzzleflash_charged" : "drg_cow_muzzleflash_charged_blue";
  267. }
  268. else
  269. {
  270. return ( GetTeamNumber() == TF_TEAM_RED ) ? "drg_cow_muzzleflash_normal" : "drg_cow_muzzleflash_normal_blue";
  271. }
  272. }
  273. #ifndef CLIENT_DLL
  274. //-----------------------------------------------------------------------------
  275. // Purpose:
  276. //-----------------------------------------------------------------------------
  277. void CTFParticleCannon::Precache()
  278. {
  279. BaseClass::Precache();
  280. PrecacheParticleSystem( "drg_cow_explosioncore_charged" );
  281. PrecacheParticleSystem( "drg_cow_explosioncore_charged_blue" );
  282. PrecacheParticleSystem( "drg_cow_explosioncore_normal" );
  283. PrecacheParticleSystem( "drg_cow_explosioncore_normal_blue" );
  284. PrecacheParticleSystem( "drg_cow_muzzleflash_charged" );
  285. PrecacheParticleSystem( "drg_cow_muzzleflash_charged_blue" );
  286. PrecacheParticleSystem( "drg_cow_muzzleflash_normal" );
  287. PrecacheParticleSystem( "drg_cow_muzzleflash_normal_blue" );
  288. PrecacheParticleSystem( "drg_cow_idle" );
  289. PrecacheScriptSound( "Weapon_CowMangler.ReloadFinal" );
  290. }
  291. #endif
  292. #ifdef CLIENT_DLL
  293. //-----------------------------------------------------------------------------
  294. // Purpose:
  295. //-----------------------------------------------------------------------------
  296. void CTFParticleCannon::OnDataChanged( DataUpdateType_t updateType )
  297. {
  298. BaseClass::OnDataChanged( updateType );
  299. if ( IsCarrierAlive() && ( WeaponState() == WEAPON_IS_ACTIVE ) )
  300. {
  301. if ( m_iChargeEffect != m_iChargeEffectBase )
  302. {
  303. CreateChargeEffect();
  304. m_iChargeEffectBase = m_iChargeEffect;
  305. }
  306. }
  307. }
  308. //-----------------------------------------------------------------------------
  309. // Purpose:
  310. //-----------------------------------------------------------------------------
  311. void CTFParticleCannon::ClientEffectsThink( void )
  312. {
  313. CTFPlayer *pPlayer = GetTFPlayerOwner();
  314. if ( !pPlayer )
  315. return;
  316. if ( !pPlayer->IsLocalPlayer() )
  317. return;
  318. if ( !pPlayer->GetViewModel() )
  319. return;
  320. if ( !m_bEffectsThinking )
  321. return;
  322. SetContextThink( &CTFParticleCannon::ClientEffectsThink, gpGlobals->curtime + 2 + rand() % 5, "PC_EFFECTS_THINK" );
  323. if ( pPlayer->m_Shared.InCond( TF_COND_TAUNTING ) )
  324. return;
  325. const char* mounts[4] =
  326. {
  327. "crit_frontspark1",
  328. "crit_frontspark2",
  329. "crit_frontspark3",
  330. "crit_frontspark4"
  331. };
  332. int iPoint = rand() % 4;
  333. ParticleProp()->Init( this );
  334. const char *pszIdleParticle = ( GetTeamNumber() == TF_TEAM_RED ) ? "drg_cow_idle" : "drg_cow_idle_blue";
  335. CNewParticleEffect* pEffect = ParticleProp()->Create( pszIdleParticle, PATTACH_POINT_FOLLOW, mounts[iPoint] );
  336. if ( pEffect )
  337. {
  338. pEffect->SetControlPoint( CUSTOM_COLOR_CP1, GetParticleColor( 1 ) );
  339. pEffect->SetControlPoint( CUSTOM_COLOR_CP2, GetParticleColor( 2 ) );
  340. }
  341. }
  342. //-----------------------------------------------------------------------------
  343. // Purpose:
  344. //-----------------------------------------------------------------------------
  345. void CTFParticleCannon::DispatchMuzzleFlash( const char* effectName, C_BaseEntity* pAttachEnt )
  346. {
  347. DispatchParticleEffect( effectName, PATTACH_POINT_FOLLOW, pAttachEnt, "muzzle", GetParticleColor( 1 ), GetParticleColor( 2 ) );
  348. }
  349. //-----------------------------------------------------------------------------
  350. // Purpose:
  351. //-----------------------------------------------------------------------------
  352. void CTFParticleCannon::CreateMuzzleFlashEffects( C_BaseEntity *pAttachEnt, int nIndex )
  353. {
  354. // Don't call direct parent. We don't want back blast effects.
  355. CTFWeaponBaseGun::CreateMuzzleFlashEffects( pAttachEnt, nIndex );
  356. }
  357. #endif
  358. //-----------------------------------------------------------------------------
  359. // Purpose: Utility function for default colors.
  360. //-----------------------------------------------------------------------------
  361. Vector GetParticleColorForTeam( int iTeam, int iColor )
  362. {
  363. if ( iColor == 1 )
  364. {
  365. if ( iTeam == TF_TEAM_RED )
  366. return TF_PARTICLE_WEAPON_RED_1;
  367. else
  368. return TF_PARTICLE_WEAPON_BLUE_1;
  369. }
  370. else
  371. {
  372. if ( iTeam == TF_TEAM_RED )
  373. return TF_PARTICLE_WEAPON_RED_2;
  374. else
  375. return TF_PARTICLE_WEAPON_BLUE_2;
  376. }
  377. }
  378. //-----------------------------------------------------------------------------
  379. // Purpose:
  380. //-----------------------------------------------------------------------------
  381. void CTFParticleCannon::PlayWeaponShootSound( void )
  382. {
  383. if ( m_bChargedShot )
  384. {
  385. // WeaponSound( BURST );
  386. }
  387. else
  388. {
  389. WeaponSound( SINGLE );
  390. }
  391. }
  392. //-----------------------------------------------------------------------------
  393. // Purpose:
  394. //-----------------------------------------------------------------------------
  395. char const *CTFParticleCannon::GetShootSound( int iIndex ) const
  396. {
  397. if ( iIndex == RELOAD )
  398. {
  399. bool bLastReload = (Energy_GetEnergy()+Energy_GetRechargeCost()) == Energy_GetMaxEnergy();
  400. if ( bLastReload )
  401. {
  402. return "Weapon_CowMangler.ReloadFinal";
  403. }
  404. }
  405. return BaseClass::GetShootSound(iIndex);
  406. }
  407. //-----------------------------------------------------------------------------
  408. // Purpose:
  409. //-----------------------------------------------------------------------------
  410. bool CTFParticleCannon::OwnerCanTaunt( void )
  411. {
  412. if ( m_flChargeBeginTime > 0 )
  413. {
  414. return false;
  415. }
  416. else
  417. {
  418. return true;
  419. }
  420. }