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.

229 lines
6.4 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: CTF AmmoPack.
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "tf_halloween_souls_pickup.h"
  8. #ifdef CLIENT_DLL
  9. #include "tf_shareddefs.h"
  10. #else
  11. #include "tf_gamerules.h"
  12. #include "tf_player.h"
  13. #include "particle_parse.h"
  14. #endif
  15. #define TF_SOULS_TIMEOUT 10.0f // How long before dropped souls disappear
  16. LINK_ENTITY_TO_CLASS( halloween_souls_pack, CHalloweenSoulPack );
  17. PRECACHE_REGISTER( halloween_souls_pack );
  18. IMPLEMENT_NETWORKCLASS_ALIASED( HalloweenSoulPack, DT_HalloweenSoulPack )
  19. BEGIN_NETWORK_TABLE( CHalloweenSoulPack, DT_HalloweenSoulPack )
  20. #ifdef GAME_DLL
  21. SendPropEHandle( SENDINFO( m_hTarget ) ),
  22. SendPropVector( SENDINFO( m_vecPreCurvePos ) ),
  23. SendPropVector( SENDINFO( m_vecStartCurvePos ) ),
  24. SendPropFloat( SENDINFO( m_flDuration ) ),
  25. #else
  26. RecvPropEHandle( RECVINFO( m_hTarget) ),
  27. RecvPropVector( RECVINFO( m_vecPreCurvePos) ),
  28. RecvPropVector( RECVINFO( m_vecStartCurvePos) ),
  29. RecvPropFloat( RECVINFO( m_flDuration ) ),
  30. #endif
  31. END_NETWORK_TABLE()
  32. BEGIN_PREDICTION_DATA( CHalloweenSoulPack )
  33. END_PREDICTION_DATA()
  34. #define SOUND_PLAYER_COLLECT_SOULS "Player.ReceiveSouls"
  35. //-----------------------------------------------------------------------------
  36. // Purpose:
  37. //-----------------------------------------------------------------------------
  38. CHalloweenSoulPack::CHalloweenSoulPack()
  39. : m_flCreationTime( 0.f )
  40. #ifdef GAME_DLL
  41. , m_nAmount( 1 )
  42. #endif
  43. {
  44. m_hTarget = NULL;
  45. m_flDuration = 2.f;
  46. }
  47. CHalloweenSoulPack::~CHalloweenSoulPack()
  48. {}
  49. void CHalloweenSoulPack::Spawn()
  50. {
  51. BaseClass::Spawn();
  52. SetMoveType( MOVETYPE_NOCLIP, MOVECOLLIDE_DEFAULT );
  53. SetSolid( SOLID_BBOX );
  54. SetCollisionGroup( COLLISION_GROUP_DEBRIS );
  55. SetSolidFlags( FSOLID_TRIGGER );
  56. #ifdef GAME_DLL
  57. InitSplineData();
  58. SetTouch(&CHalloweenSoulPack::ItemTouch);
  59. #else
  60. SetNextClientThink( CLIENT_THINK_ALWAYS );
  61. #endif
  62. }
  63. void CHalloweenSoulPack::Precache()
  64. {
  65. PrecacheScriptSound( SOUND_PLAYER_COLLECT_SOULS );
  66. }
  67. void CHalloweenSoulPack::FlyThink( void )
  68. {
  69. FlyTowardsTargetEntity();
  70. }
  71. #ifdef CLIENT_DLL
  72. void CHalloweenSoulPack::OnDataChanged( DataUpdateType_t type )
  73. {
  74. BaseClass::OnDataChanged( type );
  75. if ( type == DATA_UPDATE_CREATED )
  76. {
  77. switch( GetTeamNumber() )
  78. {
  79. case TF_TEAM_RED:
  80. ParticleProp()->Create( "halloween_pickup_active_red", PATTACH_ABSORIGIN_FOLLOW );
  81. break;
  82. case TF_TEAM_BLUE:
  83. ParticleProp()->Create( "halloween_pickup_active", PATTACH_ABSORIGIN_FOLLOW );
  84. break;
  85. case TEAM_SPECTATOR:
  86. ParticleProp()->Create( "halloween_pickup_active_green", PATTACH_ABSORIGIN_FOLLOW );
  87. break;
  88. default:
  89. Assert( false );
  90. }
  91. ParticleProp()->Create( "eb_beam_angry_ring01", PATTACH_ABSORIGIN_FOLLOW );
  92. ParticleProp()->Create( "soul_trail", PATTACH_ABSORIGIN_FOLLOW );
  93. InitSplineData();
  94. }
  95. }
  96. void CHalloweenSoulPack::ClientThink()
  97. {
  98. FlyTowardsTargetEntity();
  99. }
  100. #endif
  101. #ifdef GAME_DLL
  102. int CHalloweenSoulPack::UpdateTransmitState()
  103. {
  104. return SetTransmitState( FL_EDICT_ALWAYS );
  105. }
  106. void CHalloweenSoulPack::ItemTouch( CBaseEntity *pOther )
  107. {
  108. // Only allow our target to pick us up, if we have one
  109. if ( pOther != m_hTarget && m_hTarget != NULL )
  110. return;
  111. // Only allow to be picked up when done travelling
  112. float flT = ( gpGlobals->curtime - m_flCreationTime ) / m_flDuration;
  113. if ( flT < 1.f )
  114. return;
  115. CTFPlayer * pPlayer = ToTFPlayer( pOther );
  116. if ( pPlayer )
  117. {
  118. CTFPlayer *pTargetPlayer = ToTFPlayer( m_hTarget );
  119. IGameEvent *pEvent = gameeventmanager->CreateEvent( "halloween_soul_collected" );
  120. if ( pEvent )
  121. {
  122. pEvent->SetInt( "intended_target", pTargetPlayer ? pTargetPlayer->GetUserID() : -1 );
  123. pEvent->SetInt( "collecting_player", pPlayer->GetUserID() );
  124. pEvent->SetInt( "soul_count", m_nAmount );
  125. gameeventmanager->FireEvent( pEvent, true );
  126. }
  127. // Strange Tracking
  128. static CSchemaItemDefHandle hItemDef( "Activated Halloween Pass");
  129. kill_eater_event_t eEventType = kKillEaterEvent_HalloweenSouls;
  130. EconEntity_NonEquippedItemKillTracking_NoPartnerBatched( pPlayer, hItemDef->GetDefinitionIndex(), eEventType, m_nAmount );
  131. // Play a spooky sound in their ears
  132. CSingleUserRecipientFilter filter( pPlayer );
  133. EmitSound_t params;
  134. params.m_nChannel = CHAN_STATIC;
  135. params.m_pSoundName = SOUND_PLAYER_COLLECT_SOULS;
  136. EmitSound( filter, pPlayer->entindex(), params );
  137. }
  138. if ( pOther == m_hTarget || ( !m_hTarget && pOther->IsPlayer() ) )
  139. {
  140. UTIL_Remove( this );
  141. }
  142. }
  143. #endif
  144. void CHalloweenSoulPack::FlyTowardsTargetEntity( void )
  145. {
  146. CBaseEntity* pEntity = m_hTarget.Get();
  147. float flT = ( gpGlobals->curtime - m_flCreationTime ) / m_flDuration;
  148. #ifdef CLIENT_DLL
  149. // Client doesn't need to do anything if there's no target
  150. if ( !pEntity )
  151. {
  152. return;
  153. }
  154. #else
  155. bool bIsAGhost = false;
  156. if ( pEntity && pEntity->IsPlayer() )
  157. {
  158. CTFPlayer* pTFPlayerTarget = assert_cast< CTFPlayer* >( pEntity );
  159. bIsAGhost = pTFPlayerTarget->m_Shared.InCond( TF_COND_HALLOWEEN_GHOST_MODE );
  160. }
  161. // If flT > 2.f something has gone terribly wrong, just give up.
  162. // Also give up if our entity is gone, dead or now a ghost
  163. if( flT > 2.f || pEntity == NULL || !pEntity->IsAlive() || bIsAGhost )
  164. {
  165. m_hTarget = NULL;
  166. SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
  167. SetContextThink( &CBaseEntity::SUB_Remove, gpGlobals->curtime + TF_SOULS_TIMEOUT, "RemoveThink" );
  168. return;
  169. }
  170. #endif
  171. // Clamp
  172. const float flBiasAmt = 0.2f;
  173. flT = clamp( Bias( flT, flBiasAmt ), 0.f, 1.f );
  174. // We want to fly through the front of their chest so they get a good show
  175. QAngle eyeAngles = pEntity->EyeAngles();
  176. Vector vecBehindChest;
  177. AngleVectors( eyeAngles, &vecBehindChest );
  178. vecBehindChest *= -2000;
  179. Vector vecNextCuvePos = pEntity->WorldSpaceCenter() + vecBehindChest;
  180. Vector vecOutput;
  181. Catmull_Rom_Spline( m_vecPreCurvePos, m_vecStartCurvePos, pEntity->WorldSpaceCenter(), vecNextCuvePos, flT, vecOutput );
  182. SetAbsOrigin( vecOutput );
  183. SetContextThink( &CHalloweenSoulPack::FlyThink, gpGlobals->curtime, "HalloweenSoulPackThink" );
  184. }
  185. void CHalloweenSoulPack::InitSplineData( void )
  186. {
  187. m_flCreationTime = gpGlobals->curtime;
  188. #ifdef GAME_DLL
  189. m_vecStartCurvePos = GetAbsOrigin();
  190. m_vecPreCurvePos = m_vecStartCurvePos + RandomVector( -2000, 2000 );
  191. m_vecPreCurvePos.SetZ( Min( m_vecPreCurvePos.GetZ(), 0.f ) );
  192. m_flDuration = RandomFloat( 1.f, 3.f );
  193. #endif
  194. SetContextThink( &CHalloweenSoulPack::FlyThink, gpGlobals->curtime, "HalloweenSoulPackThink" );
  195. }