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.

760 lines
23 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: CTF HealthKit.
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "entity_halloween_pickup.h"
  8. #ifdef GAME_DLL
  9. #include "items.h"
  10. #include "tf_gamerules.h"
  11. #include "tf_player.h"
  12. #include "tf_team.h"
  13. #include "engine/IEngineSound.h"
  14. #include "entity_halloween_pickup.h"
  15. #include "tf_fx.h"
  16. #include "tf_logic_halloween_2014.h"
  17. #endif // GAME_DLL
  18. #ifdef CLIENT_DLL
  19. #include "c_tf_player.h"
  20. #endif
  21. #include "tf_shareddefs.h"
  22. #include "tf_duckleaderboard.h"
  23. #define TF_HALLOWEEN_PICKUP_RETURN_DELAY 10
  24. #ifdef GAME_DLL
  25. IMPLEMENT_AUTO_LIST( IHalloweenGiftSpawnAutoList );
  26. #endif // GAME_DLL
  27. //=============================================================================
  28. //
  29. // CTF Halloween Pickup defines.
  30. IMPLEMENT_NETWORKCLASS_ALIASED( HalloweenPickup, DT_CHalloweenPickup )
  31. BEGIN_NETWORK_TABLE( CHalloweenPickup, DT_CHalloweenPickup )
  32. END_NETWORK_TABLE()
  33. BEGIN_DATADESC( CHalloweenPickup )
  34. DEFINE_KEYFIELD( m_iszSound, FIELD_STRING, "pickup_sound" ),
  35. DEFINE_KEYFIELD( m_iszParticle, FIELD_STRING, "pickup_particle" ),
  36. #ifdef GAME_DLL
  37. DEFINE_OUTPUT( m_OnRedPickup, "OnRedPickup" ),
  38. DEFINE_OUTPUT( m_OnBluePickup, "OnBluePickup" ),
  39. #endif
  40. END_DATADESC();
  41. LINK_ENTITY_TO_CLASS( tf_halloween_pickup, CHalloweenPickup );
  42. // ************************************************************************************
  43. BEGIN_DATADESC( CBonusDuckPickup )
  44. // DEFINE_KEYFIELD( m_iszSound, FIELD_STRING, "pickup_sound" ),
  45. // DEFINE_KEYFIELD( m_iszParticle, FIELD_STRING, "pickup_particle" ),
  46. END_DATADESC();
  47. IMPLEMENT_NETWORKCLASS_ALIASED( BonusDuckPickup, DT_CBonusDuckPickup )
  48. BEGIN_NETWORK_TABLE( CBonusDuckPickup, DT_CBonusDuckPickup )
  49. #ifdef GAME_DLL
  50. SendPropBool( SENDINFO( m_bSpecial ) ),
  51. #else
  52. RecvPropBool( RECVINFO( m_bSpecial ) ),
  53. #endif
  54. END_NETWORK_TABLE()
  55. LINK_ENTITY_TO_CLASS( tf_bonus_duck_pickup, CBonusDuckPickup );
  56. // ************************************************************************************
  57. #ifdef GAME_DLL
  58. LINK_ENTITY_TO_CLASS( tf_halloween_gift_spawn_location, CHalloweenGiftSpawnLocation );
  59. #endif
  60. // ************************************************************************************
  61. IMPLEMENT_NETWORKCLASS_ALIASED( HalloweenGiftPickup, DT_CHalloweenGiftPickup )
  62. BEGIN_NETWORK_TABLE( CHalloweenGiftPickup, DT_CHalloweenGiftPickup )
  63. #ifdef CLIENT_DLL
  64. RecvPropEHandle( RECVINFO( m_hTargetPlayer ) ),
  65. #else
  66. SendPropEHandle( SENDINFO( m_hTargetPlayer ) ),
  67. #endif
  68. END_NETWORK_TABLE()
  69. BEGIN_DATADESC( CHalloweenGiftPickup )
  70. END_DATADESC();
  71. LINK_ENTITY_TO_CLASS( tf_halloween_gift_pickup, CHalloweenGiftPickup );
  72. // ************************************************************************************
  73. // ************************************************************************************
  74. ConVar tf_halloween_gift_lifetime( "tf_halloween_gift_lifetime", "240", FCVAR_CHEAT | FCVAR_REPLICATED );
  75. #ifdef STAGING_ONLY
  76. ConVar tf_halloween_gift_soul_value( "tf_halloween_gift_soul_value", "10", FCVAR_CHEAT | FCVAR_REPLICATED );
  77. #endif
  78. //=============================================================================
  79. //
  80. // CTF Halloween Pickup functions.
  81. //
  82. //-----------------------------------------------------------------------------
  83. // Purpose:
  84. //-----------------------------------------------------------------------------
  85. CHalloweenPickup::CHalloweenPickup()
  86. {
  87. #ifdef GAME_DLL
  88. ChangeTeam( TEAM_UNASSIGNED );
  89. #endif
  90. m_iszSound = MAKE_STRING( "Halloween.Quack" );
  91. m_iszParticle = MAKE_STRING( "halloween_explosion" );
  92. }
  93. //-----------------------------------------------------------------------------
  94. // Purpose:
  95. //-----------------------------------------------------------------------------
  96. CHalloweenPickup::~CHalloweenPickup()
  97. {
  98. }
  99. //-----------------------------------------------------------------------------
  100. // Purpose: Precache function for the pickup
  101. //-----------------------------------------------------------------------------
  102. void CHalloweenPickup::Precache( void )
  103. {
  104. // We deliberately allow late precaches here
  105. bool bAllowPrecache = CBaseEntity::IsPrecacheAllowed();
  106. CBaseEntity::SetAllowPrecache( true );
  107. PrecacheScriptSound( TF_HALLOWEEN_PICKUP_DEFAULT_SOUND );
  108. if ( m_iszSound != NULL_STRING )
  109. {
  110. PrecacheScriptSound( STRING( m_iszSound ) );
  111. }
  112. if ( m_iszParticle != NULL_STRING )
  113. {
  114. PrecacheParticleSystem( STRING( m_iszParticle ) );
  115. }
  116. BaseClass::Precache();
  117. CBaseEntity::SetAllowPrecache( bAllowPrecache );
  118. }
  119. #ifdef GAME_DLL
  120. //-----------------------------------------------------------------------------
  121. // Purpose:
  122. //-----------------------------------------------------------------------------
  123. int CHalloweenPickup::UpdateTransmitState()
  124. {
  125. return SetTransmitState( FL_EDICT_ALWAYS );
  126. }
  127. //-----------------------------------------------------------------------------
  128. // Purpose:
  129. //-----------------------------------------------------------------------------
  130. int CHalloweenPickup::ShouldTransmit( const CCheckTransmitInfo *pInfo )
  131. {
  132. return FL_EDICT_ALWAYS;
  133. }
  134. //-----------------------------------------------------------------------------
  135. // Purpose: MyTouch function for the pickup
  136. //-----------------------------------------------------------------------------
  137. bool CHalloweenPickup::MyTouch( CBasePlayer *pPlayer )
  138. {
  139. bool bSuccess = false;
  140. if ( ValidTouch( pPlayer ) )
  141. {
  142. bSuccess = true;
  143. switch( pPlayer->GetTeamNumber() )
  144. {
  145. case TF_TEAM_BLUE:
  146. m_OnBluePickup.FireOutput( this, this );
  147. break;
  148. case TF_TEAM_RED:
  149. m_OnRedPickup.FireOutput( this, this );
  150. break;
  151. }
  152. Vector vecOrigin = GetAbsOrigin() + Vector( 0, 0, 32 );
  153. CPVSFilter filter( vecOrigin );
  154. if ( m_iszSound != NULL_STRING )
  155. {
  156. EmitSound( filter, entindex(), STRING( m_iszSound ) );
  157. }
  158. else
  159. {
  160. EmitSound( filter, entindex(), TF_HALLOWEEN_PICKUP_DEFAULT_SOUND );
  161. }
  162. if ( m_iszParticle != NULL_STRING )
  163. {
  164. TE_TFParticleEffect( filter, 0.0, STRING( m_iszParticle ), vecOrigin, vec3_angle );
  165. }
  166. // Increment score directly during 2014 halloween
  167. if ( CTFMinigameLogic::GetMinigameLogic() && CTFMinigameLogic::GetMinigameLogic()->GetActiveMinigame() )
  168. {
  169. inputdata_t inputdata;
  170. inputdata.pActivator = NULL;
  171. inputdata.pCaller = NULL;
  172. inputdata.value.SetInt( 1 );
  173. inputdata.nOutputID = 0;
  174. if ( pPlayer->GetTeamNumber() == TF_TEAM_RED )
  175. {
  176. CTFMinigameLogic::GetMinigameLogic()->GetActiveMinigame()->InputScoreTeamRed( inputdata );
  177. }
  178. else
  179. {
  180. CTFMinigameLogic::GetMinigameLogic()->GetActiveMinigame()->InputScoreTeamBlue( inputdata );
  181. }
  182. }
  183. if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ) )
  184. {
  185. CTFPlayer *pTFPlayer = ToTFPlayer( pPlayer );
  186. if ( pTFPlayer )
  187. {
  188. pTFPlayer->AwardAchievement( ACHIEVEMENT_TF_HALLOWEEN_DOOMSDAY_COLLECT_DUCKS );
  189. IGameEvent *pEvent = gameeventmanager->CreateEvent( "halloween_duck_collected" );
  190. if ( pEvent )
  191. {
  192. pEvent->SetInt( "collector", pTFPlayer->GetUserID() );
  193. gameeventmanager->FireEvent( pEvent, true );
  194. }
  195. }
  196. }
  197. }
  198. return bSuccess;
  199. }
  200. //-----------------------------------------------------------------------------
  201. // Purpose:
  202. //-----------------------------------------------------------------------------
  203. bool CHalloweenPickup::ValidTouch( CBasePlayer *pPlayer )
  204. {
  205. CTFPlayer *pTFPlayer = ToTFPlayer( pPlayer );
  206. if ( pTFPlayer && pTFPlayer->m_Shared.InCond( TF_COND_HALLOWEEN_GHOST_MODE ) )
  207. return false;
  208. return BaseClass::ValidTouch( pPlayer );
  209. }
  210. //-----------------------------------------------------------------------------
  211. // Purpose:
  212. //-----------------------------------------------------------------------------
  213. float CHalloweenPickup::GetRespawnDelay( void )
  214. {
  215. return TF_HALLOWEEN_PICKUP_RETURN_DELAY;
  216. }
  217. //-----------------------------------------------------------------------------
  218. // Purpose: Do everything that our base does, but don't change our origin
  219. //-----------------------------------------------------------------------------
  220. CBaseEntity* CHalloweenPickup::Respawn( void )
  221. {
  222. SetTouch( NULL );
  223. AddEffects( EF_NODRAW );
  224. VPhysicsDestroyObject();
  225. SetMoveType( MOVETYPE_NONE );
  226. SetSolid( SOLID_BBOX );
  227. AddSolidFlags( FSOLID_TRIGGER );
  228. m_bRespawning = true;
  229. //UTIL_SetOrigin( this, g_pGameRules->VecItemRespawnSpot( this ) );// blip to whereever you should respawn.
  230. SetAbsAngles( g_pGameRules->VecItemRespawnAngles( this ) );// set the angles.
  231. #if !defined( TF_DLL )
  232. UTIL_DropToFloor( this, MASK_SOLID );
  233. #endif
  234. RemoveAllDecals(); //remove any decals
  235. SetThink ( &CItem::Materialize );
  236. SetNextThink( gpGlobals->curtime + GetRespawnDelay() );
  237. return this;
  238. }
  239. //-----------------------------------------------------------------------------
  240. // Purpose:
  241. //-----------------------------------------------------------------------------
  242. bool CHalloweenPickup::ItemCanBeTouchedByPlayer( CBasePlayer *pPlayer )
  243. {
  244. if ( m_flThrowerTouchTime > 0.f && gpGlobals->curtime < m_flThrowerTouchTime )
  245. {
  246. return false;
  247. }
  248. return BaseClass::ItemCanBeTouchedByPlayer( pPlayer );
  249. }
  250. #endif // GAME_DLL
  251. // ***********************************************************************************************
  252. ConVar tf_duck_allow_team_pickup( "tf_duck_allow_team_pickup", "1", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY );
  253. CBonusDuckPickup::CBonusDuckPickup()
  254. {
  255. #ifdef GAME_DLL
  256. ChangeTeam( TEAM_UNASSIGNED );
  257. m_iCreatorId = -1;
  258. m_iVictimId = -1;
  259. m_iAssisterId = -1;
  260. m_iFlags = 0;
  261. #else
  262. pGlowEffect = NULL;
  263. #endif
  264. m_bSpecial = false;
  265. m_iszSound = MAKE_STRING( BONUS_DUCK_CREATED_SOUND );
  266. m_iszParticle = MAKE_STRING( "duck_pickup" );
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Purpose:
  270. //-----------------------------------------------------------------------------
  271. CBonusDuckPickup::~CBonusDuckPickup()
  272. {
  273. #ifdef GAME_DLL
  274. m_flLifeTime = 0;
  275. #else
  276. if ( pGlowEffect )
  277. {
  278. ParticleProp()->StopEmission( pGlowEffect );
  279. pGlowEffect = NULL;
  280. }
  281. #endif
  282. }
  283. //-----------------------------------------------------------------------------
  284. void CBonusDuckPickup::Precache( void )
  285. {
  286. // We deliberately allow late precaches here
  287. bool bAllowPrecache = CBaseEntity::IsPrecacheAllowed();
  288. CBaseEntity::SetAllowPrecache( true );
  289. PrecacheParticleSystem( BONUS_DUCK_GLOW );
  290. PrecacheParticleSystem( BONUS_DUCK_TRAIL_RED );
  291. PrecacheParticleSystem( BONUS_DUCK_TRAIL_BLUE );
  292. PrecacheParticleSystem( BONUS_DUCK_TRAIL_SPECIAL_RED );
  293. PrecacheParticleSystem( BONUS_DUCK_TRAIL_SPECIAL_BLUE );
  294. PrecacheScriptSound( BONUS_DUCK_CREATED_SOUND );
  295. BaseClass::Precache();
  296. CBaseEntity::SetAllowPrecache( bAllowPrecache );
  297. }
  298. #ifdef GAME_DLL
  299. //-----------------------------------------------------------------------------
  300. // Purpose:
  301. //-----------------------------------------------------------------------------
  302. bool CBonusDuckPickup::ValidTouch( CBasePlayer *pPlayer )
  303. {
  304. // Is the item enabled?
  305. if ( IsDisabled() )
  306. return false;
  307. // Only touch a live player.
  308. if ( !pPlayer || !pPlayer->IsPlayer() || !pPlayer->IsAlive() )
  309. return false;
  310. if ( ( GetTeamNumber() >= FIRST_GAME_TEAM ) && ( pPlayer->GetTeamNumber() == GetTeamNumber() ) )
  311. return false;
  312. CTFPlayer *pTFPlayer = ToTFPlayer( pPlayer );
  313. if ( pTFPlayer && pTFPlayer->m_Shared.InCond( TF_COND_HALLOWEEN_GHOST_MODE ) )
  314. return false;
  315. return true;
  316. }
  317. //-----------------------------------------------------------------------------
  318. #define DUCK_BLINK_TIME 3.0f
  319. void CBonusDuckPickup::Spawn( void )
  320. {
  321. BaseClass::Spawn();
  322. //SetCycle( RandomFloat(0, 60.0f) );
  323. //align to the ground so we're not standing on end
  324. QAngle angle = vec3_angle;
  325. // rotate randomly in yaw
  326. angle[1] = random->RandomFloat( 0, 360 );
  327. SetAbsAngles( angle );
  328. float flLifeTime = GetLifeTime();
  329. m_flKillTime = gpGlobals->curtime + flLifeTime;
  330. m_nBlinkCount = 0;
  331. SetContextThink( &CBonusDuckPickup::BlinkThink, gpGlobals->curtime + flLifeTime - DUCK_BLINK_TIME, "BonusDuckBlinkThink" );
  332. SetContextThink( &CBonusDuckPickup::UpdateCollisionBounds, gpGlobals->curtime + 2.0f, "UpdateCollisionBoundsThink" );
  333. }
  334. //-----------------------------------------------------------------------------
  335. bool CBonusDuckPickup::MyTouch( CBasePlayer *pPlayer )
  336. {
  337. bool bSuccess = false;
  338. if ( tf_duck_allow_team_pickup.GetBool() || ValidTouch( pPlayer ) )
  339. {
  340. bSuccess = true;
  341. Vector vecOrigin = GetAbsOrigin();
  342. CPVSFilter pvsFilter( vecOrigin );
  343. if ( m_iszSound != NULL_STRING )
  344. {
  345. EmitSound( pvsFilter, entindex(), STRING( m_iszSound ) );
  346. }
  347. else
  348. {
  349. EmitSound( pvsFilter, entindex(), TF_HALLOWEEN_PICKUP_DEFAULT_SOUND );
  350. }
  351. if ( m_iszParticle != NULL_STRING )
  352. {
  353. TE_TFParticleEffect( pvsFilter, 0.0, STRING( m_iszParticle ), vecOrigin, vec3_angle );
  354. }
  355. if ( m_bSpecial )
  356. {
  357. CSingleUserRecipientFilter userfilter( pPlayer );
  358. UserMessageBegin( userfilter, "BonusDucks" );
  359. WRITE_BYTE( pPlayer->entindex() );
  360. WRITE_BYTE( true );
  361. MessageEnd();
  362. }
  363. // Notify User that they picked up a EOTL duck if the holiday is active
  364. if ( pPlayer && TFGameRules() && TFGameRules()->IsHolidayActive( kHoliday_EOTL ) && !TFGameRules()->HaveCheatsBeenEnabledDuringLevel() )
  365. {
  366. int iFlags = m_iFlags;
  367. if ( m_bSpecial )
  368. {
  369. iFlags |= DUCK_FLAG_BONUS;
  370. }
  371. // Send Message to Toucher and Creator if Creator is same team as toucher
  372. // Tell your team you picked up a duck
  373. // IsCreated, ID of Creator, ID of Victim, Count, IsGolden
  374. // Message to Toucher
  375. {
  376. CSingleUserRecipientFilter userfilter( pPlayer );
  377. UserMessageBegin( userfilter, "EOTLDuckEvent" );
  378. WRITE_BYTE( false );
  379. WRITE_BYTE( m_iCreatorId );
  380. WRITE_BYTE( m_iVictimId );
  381. WRITE_BYTE( pPlayer->entindex() );
  382. WRITE_BYTE( GetTeamNumber() );
  383. WRITE_BYTE( 1 );
  384. WRITE_BYTE( iFlags );
  385. MessageEnd();
  386. }
  387. // Notify Creator
  388. if ( m_iCreatorId != pPlayer->entindex() )
  389. {
  390. CBasePlayer *pCreator = UTIL_PlayerByIndex( m_iCreatorId );
  391. if ( pCreator && pCreator->InSameTeam( pPlayer ) )
  392. {
  393. CSingleUserRecipientFilter userfilter( pCreator );
  394. UserMessageBegin( userfilter, "EOTLDuckEvent" );
  395. WRITE_BYTE( false );
  396. WRITE_BYTE( m_iCreatorId );
  397. WRITE_BYTE( m_iVictimId );
  398. WRITE_BYTE( pPlayer->entindex() );
  399. WRITE_BYTE( GetTeamNumber() );
  400. WRITE_BYTE( 1 );
  401. WRITE_BYTE( iFlags );
  402. MessageEnd();
  403. }
  404. }
  405. // Notify Assister someone picked up their duck as well
  406. if ( m_iAssisterId != -1 && m_iAssisterId != pPlayer->entindex() )
  407. {
  408. CBasePlayer *pAssister = UTIL_PlayerByIndex( m_iAssisterId );
  409. if ( pAssister && pAssister->InSameTeam( pPlayer ) )
  410. {
  411. CSingleUserRecipientFilter userfilter( pAssister );
  412. UserMessageBegin( userfilter, "EOTLDuckEvent" );
  413. WRITE_BYTE( false );
  414. WRITE_BYTE( m_iAssisterId );
  415. WRITE_BYTE( m_iVictimId );
  416. WRITE_BYTE( pPlayer->entindex() );
  417. WRITE_BYTE( GetTeamNumber() );
  418. WRITE_BYTE( 1 );
  419. WRITE_BYTE( iFlags );
  420. MessageEnd();
  421. }
  422. }
  423. }
  424. }
  425. return bSuccess;
  426. }
  427. //-----------------------------------------------------------------------------
  428. void CBonusDuckPickup::DropSingleInstance( Vector &vecLaunchVel, CBaseCombatCharacter *pThrower, float flThrowerTouchDelay, float flResetTime /*= 0.1f*/ )
  429. {
  430. // Remove ourselves after some time
  431. SetContextThink( &CBonusDuckPickup::NotifyFadeOut, gpGlobals->curtime + GetLifeTime(), "CBonusDuckPreRemoveThink" );
  432. BaseClass::DropSingleInstance( vecLaunchVel, pThrower, flThrowerTouchDelay, flResetTime );
  433. }
  434. //-----------------------------------------------------------------------------
  435. void CBonusDuckPickup::NotifyFadeOut( void )
  436. {
  437. //// Notify User that they picked up a EOTL duck if the holiday is active
  438. //if ( TFGameRules() && TFGameRules()->IsHolidayActive( kHoliday_EOTL ) )
  439. //{
  440. // int iFlags = 0;
  441. // if ( m_bSpecial )
  442. // {
  443. // iFlags |= DUCK_FLAG_BONUS;
  444. // }
  445. // // Tell your team you picked up a duck
  446. // // IsCreated, ID of Creator, ID of Victim, Count, IsGolden
  447. // CTeamRecipientFilter userfilter( GetTeamNumber(), true );
  448. // UserMessageBegin( userfilter, "EOTLDuckEvent" );
  449. // WRITE_BYTE( false );
  450. // WRITE_BYTE( m_iCreatorId );
  451. // WRITE_BYTE( m_iVictimId );
  452. // WRITE_BYTE( 0 );
  453. // WRITE_BYTE( GetTeamNumber() );
  454. // WRITE_BYTE( 1 );
  455. // WRITE_BYTE( iFlags );
  456. // MessageEnd();
  457. //}
  458. }
  459. //-----------------------------------------------------------------------------
  460. void CBonusDuckPickup::UpdateCollisionBounds()
  461. {
  462. CollisionProp()->SetCollisionBounds( Vector( -50, -50, -50 ), Vector( 50, 50, 50 ) );
  463. }
  464. //-----------------------------------------------------------------------------
  465. void CBonusDuckPickup::BlinkThink()
  466. {
  467. float flTimeToKill = m_flKillTime - gpGlobals->curtime;
  468. float flNextBlink = RemapValClamped( flTimeToKill, DUCK_BLINK_TIME, 0.f, 0.3f, 0.05f );
  469. SetContextThink( &CBonusDuckPickup::BlinkThink, gpGlobals->curtime + flNextBlink, "BonusDuckBlinkThink" );
  470. SetRenderMode( kRenderTransAlpha );
  471. ++m_nBlinkCount;
  472. if ( m_nBlinkCount % 2 == 0 )
  473. {
  474. SetRenderColorA( 50 );
  475. }
  476. else
  477. {
  478. SetRenderColorA( 255 );
  479. }
  480. }
  481. #else
  482. //-----------------------------------------------------------------------------
  483. // Purpose:
  484. //-----------------------------------------------------------------------------
  485. void CBonusDuckPickup::OnDataChanged( DataUpdateType_t updateType )
  486. {
  487. BaseClass::OnDataChanged( updateType );
  488. if ( updateType == DATA_UPDATE_CREATED )
  489. {
  490. if ( !IsDormant() )
  491. {
  492. if ( pGlowEffect )
  493. {
  494. ParticleProp()->StopEmission( pGlowEffect );
  495. pGlowEffect = NULL;
  496. }
  497. if ( m_bSpecial )
  498. {
  499. pGlowEffect = ParticleProp()->Create( BONUS_DUCK_GLOW, PATTACH_ABSORIGIN_FOLLOW, 0, Vector( 0, 0, 10 ) );
  500. // these are fire and forget
  501. ParticleProp()->Create( ( GetTeamNumber() == TF_TEAM_RED ) ? BONUS_DUCK_TRAIL_SPECIAL_RED : BONUS_DUCK_TRAIL_SPECIAL_BLUE, PATTACH_ABSORIGIN_FOLLOW );
  502. }
  503. else
  504. {
  505. // these are fire and forget
  506. ParticleProp()->Create( ( GetTeamNumber() == TF_TEAM_RED ) ? BONUS_DUCK_TRAIL_RED : BONUS_DUCK_TRAIL_BLUE, PATTACH_ABSORIGIN_FOLLOW );
  507. }
  508. CPVSFilter filter( GetAbsOrigin() );
  509. EmitSound( filter, entindex(), BONUS_DUCK_CREATED_SOUND );
  510. }
  511. }
  512. }
  513. #endif // GAME_DLL
  514. //-----------------------------------------------------------------------------
  515. // Purpose: Halloween Gift Spawn
  516. //-----------------------------------------------------------------------------
  517. #ifdef GAME_DLL
  518. CHalloweenGiftSpawnLocation::CHalloweenGiftSpawnLocation()
  519. {
  520. }
  521. #endif
  522. //-----------------------------------------------------------------------------
  523. CHalloweenGiftPickup::CHalloweenGiftPickup()
  524. {
  525. m_hTargetPlayer = NULL;
  526. #ifdef CLIENT_DLL
  527. m_pPreviousTargetPlayer = NULL;
  528. #endif
  529. }
  530. //-----------------------------------------------------------------------------
  531. void CHalloweenGiftPickup::Precache( void )
  532. {
  533. BaseClass::Precache();
  534. PrecacheScriptSound( "sf15.Merasmus.Gargoyle.Spawn" );
  535. PrecacheScriptSound( "sf15.Merasmus.Gargoyle.Gone" );
  536. PrecacheScriptSound( "sf15.Merasmus.Gargoyle.Got" );
  537. }
  538. //------------------------------------------------------------------------
  539. void CHalloweenGiftPickup::Spawn( void )
  540. {
  541. BaseClass::Spawn();
  542. #ifdef GAME_DLL
  543. // Set a timer
  544. SetContextThink( &CHalloweenGiftPickup::DespawnGift, gpGlobals->curtime + tf_halloween_gift_lifetime.GetInt(), "DespawnGift" );
  545. AddSpawnFlags( SF_NORESPAWN );
  546. #endif // CLIENT_DLL
  547. }
  548. #ifdef GAME_DLL
  549. //------------------------------------------------------------------------
  550. // Despawn (and notify client) and then remove
  551. //------------------------------------------------------------------------
  552. void CHalloweenGiftPickup::DespawnGift()
  553. {
  554. SetTargetPlayer( NULL );
  555. SetContextThink( &CHalloweenGiftPickup::RemoveGift, gpGlobals->curtime + 1.0, "RemoveGift" );
  556. }
  557. //------------------------------------------------------------------------
  558. void CHalloweenGiftPickup::RemoveGift()
  559. {
  560. UTIL_Remove( this );
  561. }
  562. //------------------------------------------------------------------------
  563. void CHalloweenGiftPickup::SetTargetPlayer( CTFPlayer *pTarget )
  564. {
  565. m_hTargetPlayer = pTarget;
  566. }
  567. //------------------------------------------------------------------------
  568. bool CHalloweenGiftPickup::ValidTouch( CBasePlayer *pPlayer )
  569. {
  570. CTFPlayer *pTFPlayer = ToTFPlayer( pPlayer );
  571. if ( pTFPlayer && pTFPlayer != m_hTargetPlayer.Get() )
  572. return false;
  573. return true;
  574. }
  575. //------------------------------------------------------------------------
  576. bool CHalloweenGiftPickup::MyTouch( CBasePlayer *pPlayer )
  577. {
  578. CTFPlayer *pTFPlayer = ToTFPlayer( pPlayer );
  579. if ( pTFPlayer && pTFPlayer != m_hTargetPlayer.Get() )
  580. return false;
  581. // TODO: Give contract points
  582. // Visual effects
  583. Vector vecOrigin = GetAbsOrigin();
  584. CPVSFilter filter( vecOrigin );
  585. TE_TFParticleEffect( filter, 0.0, "duck_collect_green", vecOrigin, vec3_angle );
  586. // Sound effects
  587. CSingleUserRecipientFilter touchingFilter( pPlayer );
  588. EmitSound( touchingFilter, entindex(), "Halloween.PumpkinPickup" );
  589. EmitSound( touchingFilter, entindex(), "sf15.Merasmus.Gargoyle.Got" );
  590. // Give souls to the collecting player
  591. #ifdef STAGING_ONLY
  592. for( int i=0; i<tf_halloween_gift_soul_value.GetInt(); ++i )
  593. #else
  594. for( int i=0; i<10; ++i )
  595. #endif // STAGING_ONLY
  596. {
  597. TFGameRules()->DropHalloweenSoulPack( 1, vecOrigin, pPlayer, TEAM_SPECTATOR );
  598. }
  599. // Achievement
  600. if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_MANN_MANOR ) )
  601. {
  602. pTFPlayer->AwardAchievement( ACHIEVEMENT_TF_HALLOWEEN_COLLECT_GOODY_BAG );
  603. }
  604. return true;
  605. }
  606. #endif // GAME_DLL
  607. #ifdef CLIENT_DLL
  608. //-----------------------------------------------------------------------------
  609. void CHalloweenGiftPickup::OnDataChanged( DataUpdateType_t updateType )
  610. {
  611. BaseClass::OnDataChanged( updateType );
  612. if ( updateType == DATA_UPDATE_DATATABLE_CHANGED )
  613. {
  614. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  615. if ( pLocalPlayer )
  616. {
  617. // Gift Added
  618. if ( m_hTargetPlayer.Get() != NULL && m_pPreviousTargetPlayer == NULL && m_hTargetPlayer.Get() == pLocalPlayer )
  619. {
  620. // Notification
  621. CEconNotification *pNotification = new CEconNotification();
  622. pNotification->SetText( "#TF_HalloweenItem_SoulAppeared" );
  623. pNotification->SetLifetime( 5.0f );
  624. pNotification->SetSoundFilename( "ui/halloween_loot_spawn.wav" );
  625. NotificationQueue_Add( pNotification );
  626. pLocalPlayer->EmitSound( "sf15.Merasmus.Gargoyle.Spawn" );
  627. }
  628. // Gift Despawned
  629. if ( m_hTargetPlayer.Get() == NULL && m_pPreviousTargetPlayer != NULL && m_pPreviousTargetPlayer == pLocalPlayer )
  630. {
  631. // Notification
  632. CEconNotification *pNotification = new CEconNotification();
  633. pNotification->SetText( "#TF_HalloweenItem_SoulDisappeared" );
  634. pNotification->SetLifetime( 5.0f );
  635. pNotification->SetSoundFilename( "ui/halloween_loot_found.wav" );
  636. NotificationQueue_Add( pNotification );
  637. pLocalPlayer->EmitSound( "sf15.Merasmus.Gargoyle.Gone" );
  638. }
  639. m_pPreviousTargetPlayer = m_hTargetPlayer.Get();
  640. }
  641. }
  642. }
  643. //------------------------------------------------------------------------
  644. bool CHalloweenGiftPickup::ShouldDraw()
  645. {
  646. CTFPlayer *pOwner = m_hTargetPlayer.Get();
  647. if ( pOwner != C_TFPlayer::GetLocalTFPlayer() )
  648. return false;
  649. return BaseClass::ShouldDraw();
  650. }
  651. #endif