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.

755 lines
20 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: CTF Flag Capture Zone.
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "func_capture_zone.h"
  8. #include "tf_player.h"
  9. #include "tf_item.h"
  10. #include "tf_team.h"
  11. #include "tf_gamerules.h"
  12. #include "entity_capture_flag.h"
  13. #include "tf_logic_player_destruction.h"
  14. //=============================================================================
  15. //
  16. // CTF Flag Capture Zone tables.
  17. //
  18. BEGIN_DATADESC( CCaptureZone )
  19. // Keyfields.
  20. DEFINE_KEYFIELD( m_nCapturePoint, FIELD_INTEGER, "CapturePoint" ),
  21. DEFINE_KEYFIELD( m_flCaptureDelay, FIELD_FLOAT, "capture_delay" ),
  22. DEFINE_KEYFIELD( m_flCaptureDelayOffset, FIELD_FLOAT, "capture_delay_offset" ),
  23. DEFINE_KEYFIELD( m_bShouldBlock, FIELD_BOOLEAN, "shouldBlock" ),
  24. // Functions.
  25. DEFINE_FUNCTION( CCaptureZoneShim::Touch ),
  26. // Inputs.
  27. DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
  28. DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
  29. // Outputs.
  30. DEFINE_OUTPUT( m_outputOnCapture, "OnCapture" ),
  31. DEFINE_OUTPUT( m_OnCapTeam1, "OnCapTeam1" ),
  32. DEFINE_OUTPUT( m_OnCapTeam2, "OnCapTeam2" ),
  33. DEFINE_OUTPUT( m_OnCapTeam1_PD, "OnCapTeam1_PD" ),
  34. DEFINE_OUTPUT( m_OnCapTeam2_PD, "OnCapTeam2_PD" ),
  35. END_DATADESC()
  36. LINK_ENTITY_TO_CLASS( func_capturezone, CCaptureZone );
  37. IMPLEMENT_SERVERCLASS_ST( CCaptureZone, DT_CaptureZone )
  38. SendPropBool( SENDINFO( m_bDisabled ) ),
  39. END_SEND_TABLE()
  40. IMPLEMENT_AUTO_LIST( ICaptureZoneAutoList );
  41. //=============================================================================
  42. //
  43. // CTF Flag Capture Zone functions.
  44. //
  45. //-----------------------------------------------------------------------------
  46. // Purpose:
  47. //-----------------------------------------------------------------------------
  48. CCaptureZone::CCaptureZone()
  49. {
  50. m_bShouldBlock = true;
  51. m_flCaptureDelay = 1.1f;
  52. m_flCaptureDelayOffset = 0.025f;
  53. }
  54. //-----------------------------------------------------------------------------
  55. // Purpose:
  56. //-----------------------------------------------------------------------------
  57. void CCaptureZone::Spawn()
  58. {
  59. InitTrigger();
  60. SetTouch( &CCaptureZoneShim::Touch );
  61. if ( m_bDisabled )
  62. {
  63. SetDisabled( true );
  64. }
  65. m_flNextTouchingEnemyZoneWarning = -1;
  66. AddSpawnFlags( SF_TRIGGER_ALLOW_ALL ); // so we can keep track of who is touching us
  67. }
  68. //-----------------------------------------------------------------------------
  69. // Purpose:
  70. //-----------------------------------------------------------------------------
  71. void CCaptureZone::Activate( void )
  72. {
  73. BaseClass::Activate();
  74. if ( TFGameRules() && ( TFGameRules()->GetGameType() == TF_GAMETYPE_PD ) )
  75. {
  76. SetThink( &CCaptureZone::PlayerDestructionThink );
  77. SetNextThink( gpGlobals->curtime + 0.1 );
  78. }
  79. else
  80. {
  81. SetThink( NULL );
  82. }
  83. }
  84. //-----------------------------------------------------------------------------
  85. // Purpose:
  86. //-----------------------------------------------------------------------------
  87. void CCaptureZone::PlayerDestructionThink( void )
  88. {
  89. SetNextThink( gpGlobals->curtime + 0.1 );
  90. if ( !IsDisabled() )
  91. {
  92. bool bRedInZone = false;
  93. bool bBlueInZone = false;
  94. // nothing to do while no-one is touching us
  95. if ( m_hTouchingEntities.Count() == 0 )
  96. return;
  97. // loop through the touching players to figure out the teams involved
  98. for ( int i = 0; i < m_hTouchingEntities.Count(); i++ )
  99. {
  100. CBaseEntity *pEnt = m_hTouchingEntities[i];
  101. if ( pEnt && pEnt->IsPlayer() )
  102. {
  103. CTFPlayer *pTFPlayer = ToTFPlayer( pEnt );
  104. if ( pTFPlayer && pTFPlayer->IsAlive() )
  105. {
  106. if ( pTFPlayer->GetTeamNumber() == TF_TEAM_RED )
  107. {
  108. bRedInZone = true;
  109. }
  110. else if ( pTFPlayer->GetTeamNumber() == TF_TEAM_BLUE )
  111. {
  112. bBlueInZone = true;
  113. }
  114. }
  115. }
  116. }
  117. // safety check, but this should have already been caught by the ( m_hTouchingEntities.Count() == 0 ) check above
  118. if ( !bRedInZone && !bBlueInZone )
  119. return;
  120. if ( m_bShouldBlock )
  121. {
  122. // both teams are touching the zone and they block each other
  123. if ( bRedInZone && bBlueInZone )
  124. return;
  125. }
  126. CUtlVector< CTFPlayer* > playerVector;
  127. CollectPlayers( &playerVector, TF_TEAM_RED );
  128. CollectPlayers( &playerVector, TF_TEAM_BLUE, false, APPEND_PLAYERS );
  129. float flCaptureDelay = m_flCaptureDelay - ( m_flCaptureDelayOffset * playerVector.Count() );
  130. // let's see if anyone has any player destruction points to capture
  131. for ( int i = 0; i < m_hTouchingEntities.Count(); i++ )
  132. {
  133. CBaseEntity *pEnt = m_hTouchingEntities[i];
  134. if ( pEnt && pEnt->IsPlayer() )
  135. {
  136. CTFPlayer *pTFPlayer = ToTFPlayer( pEnt );
  137. if ( pTFPlayer && pTFPlayer->IsAlive() )
  138. {
  139. // does this capture point have a team number assigned?
  140. if ( ( GetTeamNumber() != TEAM_UNASSIGNED ) && ( pTFPlayer->GetTeamNumber() != GetTeamNumber() ) )
  141. continue;
  142. if ( pTFPlayer->HasTheFlag() && pTFPlayer->CanScorePointForPD() )
  143. {
  144. CCaptureFlag *pFlag = dynamic_cast< CCaptureFlag* >( pTFPlayer->GetItem() );
  145. int nPoints = pFlag->GetPointValue();
  146. if ( nPoints > 0 )
  147. {
  148. // decrease the number of points
  149. pFlag->AddPointValue( -1 );
  150. // fire the output
  151. switch ( pTFPlayer->GetTeamNumber() )
  152. {
  153. case TF_TEAM_RED:
  154. m_OnCapTeam1_PD.FireOutput( this, this );
  155. break;
  156. case TF_TEAM_BLUE:
  157. m_OnCapTeam2_PD.FireOutput( this, this );
  158. break;
  159. default:
  160. break;
  161. }
  162. IGameEvent *event = gameeventmanager->CreateEvent( "special_score" );
  163. if ( event )
  164. {
  165. event->SetInt( "player", pTFPlayer->entindex() );
  166. gameeventmanager->FireEvent( event );
  167. }
  168. }
  169. // remove this flag if this was the last point
  170. if ( pFlag->GetPointValue() == 0 )
  171. {
  172. UTIL_Remove( pFlag );
  173. }
  174. if ( CTFPlayerDestructionLogic::GetPlayerDestructionLogic() )
  175. {
  176. CTFPlayerDestructionLogic::GetPlayerDestructionLogic()->CalcTeamLeader( pTFPlayer->GetTeamNumber() );
  177. }
  178. pTFPlayer->SetNextScorePointForPD( gpGlobals->curtime + flCaptureDelay );
  179. }
  180. }
  181. }
  182. }
  183. }
  184. }
  185. //-----------------------------------------------------------------------------
  186. // Purpose:
  187. //-----------------------------------------------------------------------------
  188. void CCaptureZone::ShimTouch( CBaseEntity *pOther )
  189. {
  190. // Is the zone enabled?
  191. if ( IsDisabled() )
  192. return;
  193. // Get the TF player.
  194. CTFPlayer *pPlayer = ToTFPlayer( pOther );
  195. if ( pPlayer )
  196. {
  197. // Check to see if the player has the capture flag.
  198. if ( pPlayer->HasItem() && ( pPlayer->GetItem()->GetItemID() == TF_ITEM_CAPTURE_FLAG ) )
  199. {
  200. CCaptureFlag *pFlag = dynamic_cast<CCaptureFlag*>( pPlayer->GetItem() );
  201. if ( pFlag )
  202. {
  203. // we have a special think that will handle the player destruction flags
  204. if ( pFlag->GetType() == TF_FLAGTYPE_PLAYER_DESTRUCTION )
  205. return;
  206. if ( !pFlag->IsCaptured() )
  207. {
  208. // does this capture point have a team number assigned?
  209. if ( GetTeamNumber() != TEAM_UNASSIGNED )
  210. {
  211. // Check to see if the capture zone team matches the player's team.
  212. if ( pPlayer->GetTeamNumber() != TEAM_UNASSIGNED && pPlayer->GetTeamNumber() != GetTeamNumber() )
  213. {
  214. if ( pFlag->GetType() == TF_FLAGTYPE_CTF )
  215. {
  216. // Do this at most once every 5 seconds
  217. if ( m_flNextTouchingEnemyZoneWarning < gpGlobals->curtime )
  218. {
  219. CSingleUserRecipientFilter filter( pPlayer );
  220. TFGameRules()->SendHudNotification( filter, HUD_NOTIFY_TOUCHING_ENEMY_CTF_CAP );
  221. m_flNextTouchingEnemyZoneWarning = gpGlobals->curtime + 5;
  222. }
  223. }
  224. // else if ( pFlag->GetGameType() == TF_FLAGTYPE_INVADE )
  225. // {
  226. // }
  227. return;
  228. }
  229. }
  230. }
  231. // in MvM, the "flag" is the bomb and is captured when the carrying bot deploys it
  232. if ( TFGameRules()->FlagsMayBeCapped() && !TFGameRules()->IsMannVsMachineMode() )
  233. {
  234. Capture( pOther );
  235. }
  236. }
  237. }
  238. }
  239. }
  240. void CCaptureZone::Capture( CBaseEntity *pOther )
  241. {
  242. CTFPlayer *pPlayer = ToTFPlayer( pOther );
  243. if ( pPlayer )
  244. {
  245. // Check to see if the player has the capture flag and flag is allowed to be captured.
  246. if ( pPlayer->HasItem() && ( pPlayer->GetItem()->GetItemID() == TF_ITEM_CAPTURE_FLAG ) && TFGameRules()->CanFlagBeCaptured( pOther ) )
  247. {
  248. CCaptureFlag *pFlag = dynamic_cast< CCaptureFlag* >( pPlayer->GetItem() );
  249. if ( !pFlag )
  250. return;
  251. // we have a special think that will handle the player destruction flags
  252. if ( pFlag->GetType() == TF_FLAGTYPE_PLAYER_DESTRUCTION )
  253. return;
  254. if ( !pFlag->IsCaptured() )
  255. {
  256. pFlag->Capture( pPlayer, m_nCapturePoint );
  257. // Outputs
  258. m_outputOnCapture.FireOutput( this, this );
  259. switch ( pPlayer->GetTeamNumber() )
  260. {
  261. case TF_TEAM_RED:
  262. m_OnCapTeam1.FireOutput( this, this );
  263. break;
  264. case TF_TEAM_BLUE:
  265. m_OnCapTeam2.FireOutput( this, this );
  266. break;
  267. default:
  268. break;
  269. }
  270. IGameEvent *event = gameeventmanager->CreateEvent( "ctf_flag_captured" );
  271. if ( event )
  272. {
  273. int iCappingTeam = pPlayer->GetTeamNumber();
  274. int iCappingTeamScore = 0;
  275. CTFTeam* pCappingTeam = pPlayer->GetTFTeam();
  276. if ( pCappingTeam )
  277. {
  278. iCappingTeamScore = pCappingTeam->GetFlagCaptures();
  279. }
  280. event->SetInt( "capping_team", iCappingTeam );
  281. event->SetInt( "capping_team_score", iCappingTeamScore );
  282. event->SetInt( "capper", pPlayer->GetUserID() );
  283. event->SetInt( "priority", 9 ); // HLTV priority
  284. gameeventmanager->FireEvent( event );
  285. }
  286. if ( TFGameRules() )
  287. {
  288. if ( TFGameRules()->IsHolidayActive( kHoliday_EOTL ) )
  289. {
  290. TFGameRules()->DropBonusDuck( pPlayer->GetAbsOrigin(), pPlayer, NULL, NULL, false, true );
  291. }
  292. else if ( TFGameRules()->IsHolidayActive( kHoliday_Halloween ) )
  293. {
  294. TFGameRules()->DropHalloweenSoulPackToTeam( 5, GetAbsOrigin(), pPlayer->GetTeamNumber(), TEAM_SPECTATOR );
  295. }
  296. }
  297. }
  298. }
  299. else if ( !TFGameRules()->CanFlagBeCaptured( pOther ) && TFGameRules()->IsPowerupMode() )
  300. {
  301. ClientPrint( pPlayer, HUD_PRINTCENTER, "Cannot capture - your flag is not at base!" );
  302. }
  303. }
  304. }
  305. //-----------------------------------------------------------------------------
  306. // Purpose: The timer is always transmitted to clients
  307. //-----------------------------------------------------------------------------
  308. int CCaptureZone::UpdateTransmitState()
  309. {
  310. // ALWAYS transmit to all clients.
  311. return SetTransmitState( FL_EDICT_ALWAYS );
  312. }
  313. //-----------------------------------------------------------------------------
  314. // Purpose:
  315. //-----------------------------------------------------------------------------
  316. bool CCaptureZone::IsDisabled( void )
  317. {
  318. return m_bDisabled;
  319. }
  320. //-----------------------------------------------------------------------------
  321. // Purpose:
  322. //-----------------------------------------------------------------------------
  323. void CCaptureZone::InputEnable( inputdata_t &inputdata )
  324. {
  325. SetDisabled( false );
  326. }
  327. //-----------------------------------------------------------------------------
  328. // Purpose:
  329. //-----------------------------------------------------------------------------
  330. void CCaptureZone::InputDisable( inputdata_t &inputdata )
  331. {
  332. SetDisabled( true );
  333. }
  334. //-----------------------------------------------------------------------------
  335. // Purpose:
  336. //-----------------------------------------------------------------------------
  337. void CCaptureZone::SetDisabled( bool bDisabled )
  338. {
  339. m_bDisabled.Set( bDisabled );
  340. if ( bDisabled )
  341. {
  342. BaseClass::Disable();
  343. SetTouch( NULL );
  344. }
  345. else
  346. {
  347. BaseClass::Enable();
  348. SetTouch( &CCaptureZoneShim::Touch );
  349. }
  350. }
  351. //=============================================================================
  352. //
  353. // Flag Detection Zone tables.
  354. //
  355. BEGIN_DATADESC( CFlagDetectionZone )
  356. DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "StartDisabled" ),
  357. DEFINE_KEYFIELD( m_bShouldAlarm, FIELD_BOOLEAN, "alarm" ),
  358. // Inputs.
  359. DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
  360. DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
  361. DEFINE_INPUTFUNC( FIELD_VOID, "Test", InputTest ),
  362. // Outputs.
  363. DEFINE_OUTPUT( m_outputOnStartTouchFlag, "OnStartTouchFlag" ),
  364. DEFINE_OUTPUT( m_outputOnEndTouchFlag, "OnEndTouchFlag" ),
  365. DEFINE_OUTPUT( m_outputOnDroppedFlag, "OnDroppedFlag" ),
  366. DEFINE_OUTPUT( m_outputOnPickedUpFlag, "OnPickedUpFlag" ),
  367. END_DATADESC()
  368. LINK_ENTITY_TO_CLASS( func_flagdetectionzone, CFlagDetectionZone );
  369. IMPLEMENT_AUTO_LIST( IFlagDetectionZoneAutoList );
  370. //=============================================================================
  371. //
  372. // Flag Detection Zone functions.
  373. //
  374. CFlagDetectionZone::CFlagDetectionZone()
  375. {
  376. m_bShouldAlarm = false;
  377. }
  378. void CFlagDetectionZone::Spawn()
  379. {
  380. InitTrigger();
  381. if ( m_bDisabled )
  382. {
  383. SetDisabled( true );
  384. }
  385. }
  386. void CFlagDetectionZone::StartTouch( CBaseEntity *pOther )
  387. {
  388. // Is the zone enabled?
  389. if ( IsDisabled() )
  390. return;
  391. if ( pOther->IsPlayer() )
  392. {
  393. EHANDLE hOther;
  394. hOther = pOther;
  395. if ( m_hTouchingPlayers.Find( hOther ) == m_hTouchingPlayers.InvalidIndex() )
  396. {
  397. m_hTouchingPlayers.AddToTail( hOther );
  398. }
  399. }
  400. if ( EntityIsFlagCarrier( pOther ) )
  401. {
  402. EHANDLE hOther;
  403. hOther = pOther;
  404. bool bAdded = false;
  405. if ( m_hTouchingEntities.Find( hOther ) == m_hTouchingEntities.InvalidIndex() )
  406. {
  407. m_hTouchingEntities.AddToTail( hOther );
  408. bAdded = true;
  409. }
  410. m_OnStartTouch.FireOutput( pOther, this );
  411. if ( bAdded && ( m_hTouchingEntities.Count() == 1 ) )
  412. {
  413. // First entity to touch us that passes our filters
  414. m_outputOnStartTouchFlag.FireOutput( pOther, this );
  415. m_OnStartTouchAll.FireOutput( pOther, this );
  416. }
  417. IGameEvent *event = gameeventmanager->CreateEvent( "flag_carried_in_detection_zone" );
  418. if ( event )
  419. {
  420. gameeventmanager->FireEvent( event );
  421. }
  422. }
  423. }
  424. void CFlagDetectionZone::EndTouch( CBaseEntity *pOther )
  425. {
  426. // Is the zone enabled?
  427. if ( IsDisabled() )
  428. return;
  429. if ( pOther->IsPlayer() )
  430. {
  431. EHANDLE hOther;
  432. hOther = pOther;
  433. m_hTouchingPlayers.FindAndRemove( hOther );
  434. }
  435. if ( IsTouching( pOther ) )
  436. {
  437. EHANDLE hOther;
  438. hOther = pOther;
  439. m_hTouchingEntities.FindAndRemove( hOther );
  440. m_OnEndTouch.FireOutput(pOther, this);
  441. // If there are no more entities touching this trigger, fire the lost all touches
  442. // Loop through the touching entities backwards. Clean out old ones, and look for existing
  443. bool bFoundOtherTouchee = false;
  444. int iSize = m_hTouchingEntities.Count();
  445. for ( int i = iSize-1; i >= 0; i-- )
  446. {
  447. EHANDLE hOther;
  448. hOther = m_hTouchingEntities[i];
  449. if ( !hOther )
  450. {
  451. m_hTouchingEntities.Remove( i );
  452. }
  453. else if ( hOther->IsPlayer() && !hOther->IsAlive() )
  454. {
  455. #ifdef STAGING_ONLY
  456. AssertMsg( false, "Dead player [%s] is still touching this trigger at [%f %f %f]", hOther->GetEntityName().ToCStr(), XYZ( hOther->GetAbsOrigin() ) );
  457. Warning( "Dead player [%s] is still touching this trigger at [%f %f %f]", hOther->GetEntityName().ToCStr(), XYZ( hOther->GetAbsOrigin() ) );
  458. #endif
  459. m_hTouchingEntities.Remove( i );
  460. }
  461. else
  462. {
  463. bFoundOtherTouchee = true;
  464. }
  465. }
  466. //FIXME: Without this, triggers fire their EndTouch outputs when they are disabled!
  467. // Didn't find one?
  468. if ( !bFoundOtherTouchee /*&& !m_bDisabled*/ )
  469. {
  470. m_outputOnEndTouchFlag.FireOutput( this, this );
  471. m_OnEndTouchAll.FireOutput( pOther, this);
  472. }
  473. }
  474. }
  475. void CFlagDetectionZone::InputEnable( inputdata_t &inputdata )
  476. {
  477. SetDisabled( false );
  478. }
  479. void CFlagDetectionZone::InputDisable( inputdata_t &inputdata )
  480. {
  481. SetDisabled( true );
  482. }
  483. void CFlagDetectionZone::InputTest( inputdata_t &inputdata )
  484. {
  485. // Loop through the touching entities backwards. Clean out old ones, and look for existing
  486. int iSize = m_hTouchingEntities.Count();
  487. for ( int i = iSize-1; i >= 0; i-- )
  488. {
  489. EHANDLE hOther;
  490. hOther = m_hTouchingEntities[i];
  491. if ( !hOther )
  492. {
  493. m_hTouchingEntities.Remove( i );
  494. }
  495. else if ( hOther->IsPlayer() && !hOther->IsAlive() )
  496. {
  497. #ifdef STAGING_ONLY
  498. AssertMsg( false, "Dead player [%s] is still touching this trigger at [%f %f %f]", hOther->GetEntityName().ToCStr(), XYZ( hOther->GetAbsOrigin() ) );
  499. Warning( "Dead player [%s] is still touching this trigger at [%f %f %f]", hOther->GetEntityName().ToCStr(), XYZ( hOther->GetAbsOrigin() ) );
  500. #endif
  501. m_hTouchingEntities.Remove( i );
  502. }
  503. }
  504. if ( m_hTouchingEntities.Count() )
  505. {
  506. m_OnStartTouch.FireOutput( m_hTouchingEntities[ 0 ], this );
  507. m_outputOnStartTouchFlag.FireOutput( this, this );
  508. }
  509. else
  510. {
  511. m_outputOnEndTouchFlag.FireOutput( this, this );
  512. m_OnEndTouchAll.FireOutput( this, this );
  513. }
  514. }
  515. void CFlagDetectionZone::SetDisabled( bool bDisabled )
  516. {
  517. m_bDisabled = bDisabled;
  518. if ( bDisabled )
  519. {
  520. BaseClass::Disable();
  521. SetTouch( NULL );
  522. }
  523. else
  524. {
  525. BaseClass::Enable();
  526. }
  527. }
  528. void CFlagDetectionZone::FlagDropped( CBasePlayer *pPlayer )
  529. {
  530. EHANDLE hOther;
  531. hOther = pPlayer;
  532. if ( m_hTouchingEntities.Find( hOther ) != m_hTouchingEntities.InvalidIndex() )
  533. {
  534. m_outputOnDroppedFlag.FireOutput( pPlayer, this );
  535. EndTouch( pPlayer );
  536. // Still touching as a non-carrierz
  537. m_hTouchingPlayers.AddToTail( hOther );
  538. }
  539. }
  540. void CFlagDetectionZone::FlagPickedUp( CBasePlayer *pPlayer )
  541. {
  542. EHANDLE hOther;
  543. hOther = pPlayer;
  544. if ( m_hTouchingPlayers.Find( hOther ) != m_hTouchingPlayers.InvalidIndex() )
  545. {
  546. m_outputOnPickedUpFlag.FireOutput( pPlayer, this );
  547. StartTouch( pPlayer );
  548. }
  549. }
  550. bool CFlagDetectionZone::EntityIsFlagCarrier( CBaseEntity *pEntity )
  551. {
  552. // Get the TF player.
  553. CTFPlayer *pPlayer = ToTFPlayer( pEntity );
  554. if ( pPlayer )
  555. {
  556. // Check to see if the player has the capture flag.
  557. if ( pPlayer->HasItem() && ( pPlayer->GetItem()->GetItemID() == TF_ITEM_CAPTURE_FLAG ) )
  558. {
  559. CCaptureFlag *pFlag = dynamic_cast<CCaptureFlag*>( pPlayer->GetItem() );
  560. if ( pFlag && !pFlag->IsCaptured() )
  561. {
  562. return true;
  563. }
  564. }
  565. }
  566. return false;
  567. }
  568. void CFlagDetectionZone::FlagCaptured( CBasePlayer *pPlayer )
  569. {
  570. if ( !pPlayer )
  571. return;
  572. if ( FStrEq( "sd_doomsday", STRING( gpGlobals->mapname ) ) )
  573. {
  574. EHANDLE hOther;
  575. hOther = pPlayer;
  576. if ( m_hTouchingPlayers.Find( hOther ) != m_hTouchingPlayers.InvalidIndex() )
  577. {
  578. int nWinningTeam = pPlayer->GetTeamNumber();
  579. CUtlVector< EHANDLE > winningPlayers;
  580. for ( int i = 0 ; i < m_hTouchingPlayers.Count() ; i++ )
  581. {
  582. EHANDLE hTemp = m_hTouchingPlayers[i];
  583. if ( hTemp && ( hTemp->GetTeamNumber() == nWinningTeam ) )
  584. {
  585. winningPlayers.AddToHead( hTemp );
  586. }
  587. }
  588. // ACHIEVEMENT_TF_MAPS_DOOMSDAY_RIDE_THE_ELEVATOR
  589. if ( winningPlayers.Count() >= 5 )
  590. {
  591. // loop through and award the achievement
  592. for ( int i = 0 ; i < winningPlayers.Count() ; i++ )
  593. {
  594. EHANDLE hTemp = winningPlayers[i];
  595. if ( hTemp )
  596. {
  597. CTFPlayer *pTFPlayer = ToTFPlayer( hTemp );
  598. if ( pTFPlayer )
  599. {
  600. pTFPlayer->AwardAchievement( ACHIEVEMENT_TF_MAPS_DOOMSDAY_RIDE_THE_ELEVATOR );
  601. }
  602. }
  603. }
  604. }
  605. }
  606. }
  607. }
  608. //-----------------------------------------------------------------------------
  609. // Purpose: Handles if the specified entity is dropped in a detection zone
  610. //-----------------------------------------------------------------------------
  611. void HandleFlagDroppedInDetectionZone( CBasePlayer *pPlayer )
  612. {
  613. for ( int i=0; i<IFlagDetectionZoneAutoList::AutoList().Count(); ++i )
  614. {
  615. CFlagDetectionZone *pZone = static_cast<CFlagDetectionZone *>( IFlagDetectionZoneAutoList::AutoList()[i] );
  616. if ( !pZone->IsDisabled() )
  617. {
  618. pZone->FlagDropped( pPlayer );
  619. }
  620. }
  621. }
  622. //-----------------------------------------------------------------------------
  623. // Purpose: Handles if the specified entity is picked up in a detection zone
  624. //-----------------------------------------------------------------------------
  625. void HandleFlagPickedUpInDetectionZone( CBasePlayer *pPlayer )
  626. {
  627. for ( int i=0; i<IFlagDetectionZoneAutoList::AutoList().Count(); ++i )
  628. {
  629. CFlagDetectionZone *pZone = static_cast<CFlagDetectionZone *>( IFlagDetectionZoneAutoList::AutoList()[i] );
  630. if ( !pZone->IsDisabled() )
  631. {
  632. pZone->FlagPickedUp( pPlayer );
  633. }
  634. }
  635. }
  636. //-----------------------------------------------------------------------------
  637. // Purpose: Handles if the specified entity is captured in a detection zone
  638. //-----------------------------------------------------------------------------
  639. void HandleFlagCapturedInDetectionZone( CBasePlayer *pPlayer )
  640. {
  641. for ( int i=0; i<IFlagDetectionZoneAutoList::AutoList().Count(); ++i )
  642. {
  643. CFlagDetectionZone *pZone = static_cast<CFlagDetectionZone *>( IFlagDetectionZoneAutoList::AutoList()[i] );
  644. if ( !pZone->IsDisabled() )
  645. {
  646. pZone->FlagCaptured( pPlayer );
  647. }
  648. }
  649. }