Counter Strike : Global Offensive Source Code
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.

1157 lines
31 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "cbase.h"
  7. #include "trigger_area_capture.h"
  8. #include "player.h"
  9. #include "teamplay_gamerules.h"
  10. #include "team.h"
  11. #include "team_objectiveresource.h"
  12. #include "team_control_point_master.h"
  13. #include "teamplayroundbased_gamerules.h"
  14. // NOTE: This has to be the last file included!
  15. #include "tier0/memdbgon.h"
  16. extern ConVar mp_capstyle;
  17. extern ConVar mp_blockstyle;
  18. extern ConVar mp_capdeteriorate_time;
  19. BEGIN_DATADESC(CTriggerAreaCapture)
  20. // Touch functions
  21. DEFINE_FUNCTION( AreaTouch ),
  22. // Think functions
  23. DEFINE_THINKFUNC( CaptureThink ),
  24. // Keyfields
  25. DEFINE_KEYFIELD( m_iszCapPointName, FIELD_STRING, "area_cap_point" ),
  26. DEFINE_KEYFIELD( m_flCapTime, FIELD_FLOAT, "area_time_to_cap" ),
  27. // DEFINE_FIELD( m_iCapMode, FIELD_INTEGER ),
  28. // DEFINE_FIELD( m_bCapturing, FIELD_BOOLEAN ),
  29. // DEFINE_FIELD( m_nCapturingTeam, FIELD_INTEGER ),
  30. // DEFINE_FIELD( m_nOwningTeam, FIELD_INTEGER ),
  31. // DEFINE_FIELD( m_nTeamInZone, FIELD_INTEGER ),
  32. // DEFINE_FIELD( m_fTimeRemaining, FIELD_FLOAT ),
  33. // DEFINE_FIELD( m_flLastReductionTime, FIELD_FLOAT ),
  34. // DEFINE_FIELD( m_bBlocked, FIELD_BOOLEAN ),
  35. // DEFINE_FIELD( m_TeamData, CUtlVector < perteamdata_t > ),
  36. // DEFINE_FIELD( m_Blockers, CUtlVector < blockers_t > ),
  37. // DEFINE_FIELD( m_bActive, FIELD_BOOLEAN ),
  38. // DEFINE_FIELD( m_iAreaIndex, FIELD_INTEGER ),
  39. // DEFINE_FIELD( m_hPoint, CHandle < CTeamControlPoint > ),
  40. // DEFINE_FIELD( m_bRequiresObject, FIELD_BOOLEAN ),
  41. // DEFINE_FIELD( m_iCapAttemptNumber, FIELD_INTEGER ),
  42. // Inputs
  43. DEFINE_INPUTFUNC( FIELD_VOID, "RoundSpawn", InputRoundSpawn ),
  44. DEFINE_INPUTFUNC( FIELD_STRING, "SetTeamCanCap", InputSetTeamCanCap ),
  45. DEFINE_INPUTFUNC( FIELD_STRING, "SetControlPoint", InputSetControlPoint ),
  46. DEFINE_INPUTFUNC( FIELD_VOID, "CaptureCurrentCP", InputCaptureCurrentCP ),
  47. // Outputs
  48. DEFINE_OUTPUT( m_OnStartTeam1, "OnStartTeam1" ),
  49. DEFINE_OUTPUT( m_OnStartTeam2, "OnStartTeam2" ),
  50. DEFINE_OUTPUT( m_OnBreakTeam1, "OnBreakTeam1" ),
  51. DEFINE_OUTPUT( m_OnBreakTeam2, "OnBreakTeam2" ),
  52. DEFINE_OUTPUT( m_OnCapTeam1, "OnCapTeam1" ),
  53. DEFINE_OUTPUT( m_OnCapTeam2, "OnCapTeam2" ),
  54. DEFINE_OUTPUT( m_StartOutput, "OnStartCap" ),
  55. DEFINE_OUTPUT( m_BreakOutput, "OnBreakCap" ),
  56. DEFINE_OUTPUT( m_CapOutput, "OnEndCap" ),
  57. DEFINE_OUTPUT( m_OnNumCappersChanged, "OnNumCappersChanged" ),
  58. END_DATADESC();
  59. LINK_ENTITY_TO_CLASS( trigger_capture_area, CTriggerAreaCapture );
  60. //-----------------------------------------------------------------------------
  61. // Purpose:
  62. //-----------------------------------------------------------------------------
  63. CTriggerAreaCapture::CTriggerAreaCapture()
  64. {
  65. m_TeamData.SetSize( GetNumberOfTeams() );
  66. }
  67. //-----------------------------------------------------------------------------
  68. // Purpose:
  69. //-----------------------------------------------------------------------------
  70. void CTriggerAreaCapture::Spawn( void )
  71. {
  72. BaseClass::Spawn();
  73. AddSpawnFlags( SF_TRIGGER_ALLOW_CLIENTS );
  74. InitTrigger();
  75. Precache();
  76. m_iAreaIndex = -1;
  77. SetTouch ( &CTriggerAreaCapture::AreaTouch );
  78. SetThink( &CTriggerAreaCapture::CaptureThink );
  79. SetNextThink( gpGlobals->curtime + AREA_THINK_TIME );
  80. for ( int i = 0; i < m_TeamData.Count(); i++ )
  81. {
  82. if ( m_TeamData[i].iNumRequiredToCap < 1 )
  83. {
  84. m_TeamData[i].iNumRequiredToCap = 1;
  85. }
  86. }
  87. }
  88. //-----------------------------------------------------------------------------
  89. // Purpose:
  90. //-----------------------------------------------------------------------------
  91. bool CTriggerAreaCapture::KeyValue( const char *szKeyName, const char *szValue )
  92. {
  93. if ( !Q_strncmp( szKeyName, "team_numcap_", 12 ) )
  94. {
  95. int iTeam = atoi(szKeyName+12);
  96. Assert( iTeam >= 0 && iTeam < m_TeamData.Count() );
  97. m_TeamData[iTeam].iNumRequiredToCap = atoi(szValue);
  98. }
  99. else if ( !Q_strncmp( szKeyName, "team_cancap_", 12 ) )
  100. {
  101. int iTeam = atoi(szKeyName+12);
  102. Assert( iTeam >= 0 && iTeam < m_TeamData.Count() );
  103. m_TeamData[iTeam].bCanCap = (atoi(szValue) != 0);
  104. }
  105. else if ( !Q_strncmp( szKeyName, "team_spawn_", 11 ) )
  106. {
  107. int iTeam = atoi(szKeyName+11);
  108. Assert( iTeam >= 0 && iTeam < m_TeamData.Count() );
  109. m_TeamData[iTeam].iSpawnAdjust = atoi(szValue);
  110. }
  111. else
  112. {
  113. return BaseClass::KeyValue( szKeyName, szValue );
  114. }
  115. return true;
  116. }
  117. //-----------------------------------------------------------------------------
  118. // Purpose:
  119. //-----------------------------------------------------------------------------
  120. void CTriggerAreaCapture::Precache( void )
  121. {
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Purpose:
  125. //-----------------------------------------------------------------------------
  126. void CTriggerAreaCapture::SetAreaIndex( int index )
  127. {
  128. m_iAreaIndex = index;
  129. }
  130. //-----------------------------------------------------------------------------
  131. // Purpose:
  132. //-----------------------------------------------------------------------------
  133. bool CTriggerAreaCapture::IsActive( void )
  134. {
  135. return !m_bDisabled;
  136. }
  137. //-----------------------------------------------------------------------------
  138. // Purpose:
  139. //-----------------------------------------------------------------------------
  140. void CTriggerAreaCapture::StartTouch(CBaseEntity *pOther)
  141. {
  142. BaseClass::StartTouch( pOther );
  143. if ( PassesTriggerFilters(pOther) && m_hPoint )
  144. {
  145. IGameEvent *event = gameeventmanager->CreateEvent( "controlpoint_starttouch" );
  146. if ( event )
  147. {
  148. event->SetInt( "player", pOther->entindex() );
  149. event->SetInt( "area", m_hPoint->GetPointIndex() );
  150. gameeventmanager->FireEvent( event );
  151. }
  152. // Call capture think immediately to make it update our area's player counts.
  153. // If we don't do this, the player can receive the above event telling him he's
  154. // in a zone, but the objective resource still thinks he's not.
  155. CaptureThink();
  156. if ( m_bCapturing )
  157. {
  158. CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL;
  159. if ( pMaster )
  160. {
  161. float flRate = pMaster->GetPartialCapturePointRate();
  162. if ( flRate > 0.0f )
  163. {
  164. CBaseMultiplayerPlayer *pPlayer = ToBaseMultiplayerPlayer(pOther);
  165. if ( pPlayer )
  166. {
  167. pPlayer->StartScoringEscortPoints( flRate );
  168. }
  169. }
  170. }
  171. }
  172. }
  173. }
  174. //-----------------------------------------------------------------------------
  175. // Purpose:
  176. //-----------------------------------------------------------------------------
  177. void CTriggerAreaCapture::EndTouch(CBaseEntity *pOther)
  178. {
  179. if ( PassesTriggerFilters(pOther) && m_hPoint )
  180. {
  181. IGameEvent *event = gameeventmanager->CreateEvent( "controlpoint_endtouch" );
  182. if ( event )
  183. {
  184. event->SetInt( "player", pOther->entindex() );
  185. event->SetInt( "area", m_hPoint->GetPointIndex() );
  186. gameeventmanager->FireEvent( event );
  187. }
  188. // incase we leave but the area keeps capturing
  189. CBaseMultiplayerPlayer *pPlayer = ToBaseMultiplayerPlayer(pOther);
  190. if ( pPlayer )
  191. {
  192. pPlayer->StopScoringEscortPoints();
  193. }
  194. }
  195. BaseClass::EndTouch( pOther );
  196. }
  197. //-----------------------------------------------------------------------------
  198. // Purpose:
  199. //-----------------------------------------------------------------------------
  200. void CTriggerAreaCapture::AreaTouch( CBaseEntity *pOther )
  201. {
  202. if ( !IsActive() )
  203. return;
  204. if ( !PassesTriggerFilters(pOther) )
  205. return;
  206. // Don't cap areas unless the round is running
  207. if ( !TeamplayGameRules()->PointsMayBeCaptured() )
  208. return;
  209. Assert( m_iAreaIndex != -1 );
  210. // dont touch for non-alive or non-players
  211. if( !pOther->IsPlayer() || !pOther->IsAlive() )
  212. return;
  213. // make sure this point is in the round being played (if we're playing one)
  214. CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL;
  215. if ( pMaster && m_hPoint )
  216. {
  217. if ( !pMaster->PointCanBeCapped( m_hPoint ) )
  218. {
  219. return;
  220. }
  221. }
  222. if ( m_hPoint )
  223. {
  224. m_nOwningTeam = m_hPoint->GetOwner();
  225. }
  226. CBaseMultiplayerPlayer *pPlayer = ToBaseMultiplayerPlayer(pOther);
  227. Assert( pPlayer );
  228. if ( pPlayer->GetTeamNumber() != m_nOwningTeam )
  229. {
  230. if ( m_TeamData[ pPlayer->GetTeamNumber() ].bCanCap )
  231. {
  232. DisplayCapHintTo( pPlayer );
  233. }
  234. }
  235. }
  236. ConVar mp_simulatemultiplecappers( "mp_simulatemultiplecappers", "1", FCVAR_CHEAT );
  237. #define MAX_CAPTURE_TEAMS 8
  238. //-----------------------------------------------------------------------------
  239. // Purpose:
  240. //-----------------------------------------------------------------------------
  241. void CTriggerAreaCapture::CaptureThink( void )
  242. {
  243. SetNextThink( gpGlobals->curtime + AREA_THINK_TIME );
  244. // make sure this point is in the round being played (if we're playing one)
  245. CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL;
  246. if ( pMaster && m_hPoint )
  247. {
  248. if ( !pMaster->PointCanBeCapped( m_hPoint ) )
  249. {
  250. return;
  251. }
  252. }
  253. if ( !TeamplayGameRules()->PointsMayBeCaptured() )
  254. {
  255. // Points aren't allowed to be captured. If we were
  256. // being captured, we need to clean up and reset.
  257. if ( m_bCapturing )
  258. {
  259. BreakCapture( false );
  260. UpdateNumPlayers();
  261. }
  262. return;
  263. }
  264. // go through our list of players
  265. Assert( GetNumberOfTeams() <= MAX_CAPTURE_TEAMS );
  266. int iNumPlayers[MAX_CAPTURE_TEAMS];
  267. int iNumBlockablePlayers[MAX_CAPTURE_TEAMS]; // Players in the zone who can't cap, but can block / pause caps
  268. CBaseMultiplayerPlayer *pFirstPlayerTouching[MAX_CAPTURE_TEAMS];
  269. for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ )
  270. {
  271. iNumPlayers[i] = 0;
  272. iNumBlockablePlayers[i] = 0;
  273. pFirstPlayerTouching[i] = NULL;
  274. }
  275. // Loop through the entities we're touching, and find players
  276. for ( int i = 0; i < m_hTouchingEntities.Count(); i++ )
  277. {
  278. CBaseEntity *ent = m_hTouchingEntities[i];
  279. if ( ent && ent->IsPlayer() )
  280. {
  281. CBaseMultiplayerPlayer *pPlayer = ToBaseMultiplayerPlayer(ent);
  282. if ( pPlayer->IsAlive() )
  283. {
  284. int iTeam = pPlayer->GetTeamNumber();
  285. // If a team's not allowed to cap a point, don't count players in it at all
  286. if ( !TeamplayGameRules()->TeamMayCapturePoint( iTeam, m_hPoint->GetPointIndex() ) )
  287. continue;
  288. if ( !TeamplayGameRules()->PlayerMayCapturePoint( pPlayer, m_hPoint->GetPointIndex() ) )
  289. {
  290. if ( TeamplayGameRules()->PlayerMayBlockPoint( pPlayer, m_hPoint->GetPointIndex() ) )
  291. {
  292. if ( iNumPlayers[iTeam] == 0 && iNumBlockablePlayers[iTeam] == 0 )
  293. {
  294. pFirstPlayerTouching[iTeam] = pPlayer;
  295. }
  296. iNumBlockablePlayers[iTeam] += TeamplayGameRules()->GetCaptureValueForPlayer( pPlayer );
  297. }
  298. continue;
  299. }
  300. if ( iTeam >= FIRST_GAME_TEAM )
  301. {
  302. if ( iNumPlayers[iTeam] == 0 && iNumBlockablePlayers[iTeam] == 0 )
  303. {
  304. pFirstPlayerTouching[iTeam] = pPlayer;
  305. }
  306. iNumPlayers[iTeam] += TeamplayGameRules()->GetCaptureValueForPlayer( pPlayer );
  307. }
  308. }
  309. }
  310. }
  311. int iTeamsInZone = 0;
  312. bool bUpdatePlayers = false;
  313. m_nTeamInZone = TEAM_UNASSIGNED;
  314. for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ )
  315. {
  316. iNumPlayers[i] *= mp_simulatemultiplecappers.GetInt();
  317. if ( m_TeamData[i].iNumTouching != iNumPlayers[i] )
  318. {
  319. m_TeamData[i].iNumTouching = iNumPlayers[i];
  320. bUpdatePlayers = true;
  321. }
  322. m_TeamData[i].iBlockedTouching = m_TeamData[i].iNumTouching;
  323. if ( m_TeamData[i].iNumTouching )
  324. {
  325. iTeamsInZone++;
  326. m_nTeamInZone = i;
  327. }
  328. }
  329. if ( iTeamsInZone > 1 )
  330. {
  331. m_nTeamInZone = TEAM_UNASSIGNED;
  332. }
  333. else
  334. {
  335. // If we've got non-cappable, yet blockable players here for the team that's defending, they
  336. // need to block the cap. This catches cases like the TF invulnerability, which needs to block
  337. // caps, but isn't allowed to contribute to a cap.
  338. for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ )
  339. {
  340. if ( !iNumBlockablePlayers[i] || m_nTeamInZone == i )
  341. continue;
  342. iTeamsInZone++;
  343. }
  344. }
  345. UpdateTeamInZone();
  346. // If the cap is being blocked, reset the number of players so the client
  347. // knows to stop the capture as well.
  348. if ( mp_blockstyle.GetInt() == 1 )
  349. {
  350. if ( m_bCapturing && iTeamsInZone > 1 )
  351. {
  352. for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ )
  353. {
  354. iNumPlayers[i] = 0;
  355. if ( m_TeamData[i].iNumTouching != iNumPlayers[i] )
  356. {
  357. m_TeamData[i].iNumTouching = iNumPlayers[i];
  358. bUpdatePlayers = true;
  359. }
  360. }
  361. }
  362. }
  363. if ( bUpdatePlayers )
  364. {
  365. UpdateNumPlayers();
  366. }
  367. // When a player blocks, tell them the cap index and attempt number
  368. // only give successive blocks to them if the attempt number is different
  369. if ( m_bCapturing )
  370. {
  371. if ( m_hPoint )
  372. {
  373. m_hPoint->SetLastContestedAt( gpGlobals->curtime );
  374. }
  375. // Calculate the amount of modification to the cap time
  376. float flTimeDelta = gpGlobals->curtime - m_flLastReductionTime;
  377. float flReduction = flTimeDelta;
  378. if ( mp_capstyle.GetInt() == 1 )
  379. {
  380. // Diminishing returns for successive players.
  381. for ( int i = 1; i < m_TeamData[m_nTeamInZone].iNumTouching; i++ )
  382. {
  383. flReduction += (flTimeDelta / (float)(i+1));
  384. }
  385. }
  386. m_flLastReductionTime = gpGlobals->curtime;
  387. //if more than one team is in the zone
  388. if( iTeamsInZone > 1 )
  389. {
  390. if ( !m_bBlocked )
  391. {
  392. m_bBlocked = true;
  393. UpdateBlocked();
  394. }
  395. // See if anyone gets credit for the block
  396. float flPercentToGo = m_fTimeRemaining / m_flCapTime;
  397. if ( mp_capstyle.GetInt() == 1 )
  398. {
  399. flPercentToGo = m_fTimeRemaining / ((m_flCapTime * 2) * m_TeamData[m_nCapturingTeam].iNumRequiredToCap);
  400. }
  401. if ( flPercentToGo <= 0.5 && m_hPoint )
  402. {
  403. // find the first player that is not on the capturing team
  404. // they have just broken a cap and should be rewarded
  405. // tell the player the capture attempt number, for checking later
  406. CBaseMultiplayerPlayer *pBlockingPlayer = NULL;
  407. for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ )
  408. {
  409. if ( m_nCapturingTeam == i )
  410. continue;
  411. if ( pFirstPlayerTouching[i] )
  412. {
  413. pBlockingPlayer = pFirstPlayerTouching[i];
  414. break;
  415. }
  416. }
  417. Assert( pBlockingPlayer );
  418. if ( pBlockingPlayer )
  419. {
  420. bool bRepeatBlocker = false;
  421. for ( int i = m_Blockers.Count()-1; i >= 0; i-- )
  422. {
  423. if ( m_Blockers[i].hPlayer != pBlockingPlayer )
  424. continue;
  425. // If this guy's was a blocker, but not valid now, remove him from the list
  426. if ( m_Blockers[i].iCapAttemptNumber != m_iCapAttemptNumber || !IsTouching(m_Blockers[i].hPlayer) )
  427. {
  428. m_Blockers.Remove(i);
  429. continue;
  430. }
  431. bRepeatBlocker = true;
  432. break;
  433. }
  434. if ( !bRepeatBlocker )
  435. {
  436. m_hPoint->CaptureBlocked( pBlockingPlayer );
  437. // Add this guy to our blocker list
  438. int iNew = m_Blockers.AddToTail();
  439. m_Blockers[iNew].hPlayer = pBlockingPlayer;
  440. m_Blockers[iNew].iCapAttemptNumber = m_iCapAttemptNumber;
  441. }
  442. }
  443. }
  444. if ( mp_blockstyle.GetInt() == 0 )
  445. {
  446. BreakCapture( false );
  447. }
  448. return;
  449. }
  450. if ( m_bBlocked )
  451. {
  452. m_bBlocked = false;
  453. UpdateBlocked();
  454. }
  455. float flTotalTimeToCap = m_flCapTime;
  456. if ( mp_capstyle.GetInt() == 1 )
  457. {
  458. flTotalTimeToCap = ((m_flCapTime * 2) * m_TeamData[m_nCapturingTeam].iNumRequiredToCap);
  459. }
  460. // Now remove the reduction amount after we've determined there's only 1 team in the area
  461. if ( m_nCapturingTeam == m_nTeamInZone )
  462. {
  463. SetCapTimeRemaining( m_fTimeRemaining - flReduction );
  464. }
  465. else if ( m_nOwningTeam == TEAM_UNASSIGNED && m_nTeamInZone != TEAM_UNASSIGNED )
  466. {
  467. SetCapTimeRemaining( m_fTimeRemaining + flReduction );
  468. }
  469. else
  470. {
  471. // Caps deteriorate over time
  472. if ( TeamplayRoundBasedRules() && m_hPoint && TeamplayRoundBasedRules()->TeamMayCapturePoint(m_nCapturingTeam,m_hPoint->GetPointIndex()) )
  473. {
  474. float flDecrease = (flTotalTimeToCap / mp_capdeteriorate_time.GetFloat()) * flTimeDelta;
  475. if ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->InOvertime() )
  476. {
  477. flDecrease *= 6;
  478. }
  479. SetCapTimeRemaining( m_fTimeRemaining + flDecrease );
  480. }
  481. else
  482. {
  483. SetCapTimeRemaining( flTotalTimeToCap );
  484. }
  485. }
  486. /*
  487. //if no-one is in the area
  488. if( iTeamsInZone == 0 )
  489. {
  490. BreakCapture( true );
  491. return;
  492. }
  493. //if they've lost the number of players needed to cap
  494. int iTeamMembersHere = m_TeamData[m_nCapturingTeam].iNumTouching + iNumBlockablePlayers[m_nCapturingTeam];
  495. if ( (iTeamMembersHere == 0 ) || (mp_capstyle.GetInt() == 0 && iTeamMembersHere < m_TeamData[m_nCapturingTeam].iNumRequiredToCap) )
  496. {
  497. BreakCapture( true );
  498. return;
  499. }
  500. */
  501. // if the cap is done
  502. if ( m_fTimeRemaining <= 0 )
  503. {
  504. EndCapture( m_nCapturingTeam );
  505. return; //we're done
  506. }
  507. else
  508. {
  509. if ( m_fTimeRemaining >= flTotalTimeToCap )
  510. {
  511. BreakCapture( false );
  512. return;
  513. }
  514. }
  515. }
  516. else
  517. {
  518. // If there are any teams in the zone that aren't the owner, try to start capping
  519. if ( iTeamsInZone > 0 )
  520. {
  521. for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ )
  522. {
  523. if ( !m_TeamData[i].bCanCap || m_nOwningTeam == i )
  524. continue;
  525. if ( m_TeamData[i].iNumTouching == 0 )
  526. continue;
  527. if ( mp_capstyle.GetInt() == 0 && m_TeamData[i].iNumTouching < m_TeamData[i].iNumRequiredToCap )
  528. continue;
  529. StartCapture( i, CAPTURE_NORMAL );
  530. break;
  531. }
  532. }
  533. }
  534. }
  535. //-----------------------------------------------------------------------------
  536. // Purpose:
  537. //-----------------------------------------------------------------------------
  538. void CTriggerAreaCapture::SetCapTimeRemaining( float flTime )
  539. {
  540. m_fTimeRemaining = flTime;
  541. float flCapPercentage = 0;
  542. if ( m_nCapturingTeam )
  543. {
  544. flCapPercentage = m_fTimeRemaining / m_flCapTime;
  545. if ( mp_capstyle.GetInt() == 1 )
  546. {
  547. flCapPercentage = m_fTimeRemaining / ((m_flCapTime * 2) * m_TeamData[m_nCapturingTeam].iNumRequiredToCap);
  548. }
  549. }
  550. ObjectiveResource()->SetCPCapPercentage( m_hPoint->GetPointIndex(), flCapPercentage );
  551. if ( m_hPoint )
  552. {
  553. m_hPoint->UpdateCapPercentage();
  554. }
  555. }
  556. //-----------------------------------------------------------------------------
  557. // Purpose:
  558. //-----------------------------------------------------------------------------
  559. void CTriggerAreaCapture::SetOwner( int team )
  560. {
  561. //break any current capturing
  562. BreakCapture( false );
  563. HandleRespawnTimeAdjustments( m_nOwningTeam, team );
  564. //set the owner to the passed value
  565. m_nOwningTeam = team;
  566. UpdateOwningTeam();
  567. }
  568. //-----------------------------------------------------------------------------
  569. // Purpose:
  570. //-----------------------------------------------------------------------------
  571. void CTriggerAreaCapture::ForceOwner( int team )
  572. {
  573. SetOwner( team );
  574. if ( m_hPoint )
  575. {
  576. m_hPoint->ForceOwner( team );
  577. }
  578. }
  579. //-----------------------------------------------------------------------------
  580. // Purpose:
  581. //-----------------------------------------------------------------------------
  582. void CTriggerAreaCapture::HandleRespawnTimeAdjustments( int oldTeam, int newTeam )
  583. {
  584. if ( oldTeam > LAST_SHARED_TEAM )
  585. {
  586. // reverse the adjust made when the old team captured this point (if we made one)
  587. if ( m_TeamData[oldTeam].iSpawnAdjust != 0 )
  588. {
  589. TeamplayRoundBasedRules()->AddTeamRespawnWaveTime( oldTeam, -m_TeamData[oldTeam].iSpawnAdjust );
  590. }
  591. }
  592. if ( newTeam > LAST_SHARED_TEAM )
  593. {
  594. if ( m_TeamData[newTeam].iSpawnAdjust != 0 )
  595. {
  596. TeamplayRoundBasedRules()->AddTeamRespawnWaveTime( newTeam, m_TeamData[newTeam].iSpawnAdjust );
  597. }
  598. }
  599. }
  600. //-----------------------------------------------------------------------------
  601. // Purpose:
  602. //-----------------------------------------------------------------------------
  603. void CTriggerAreaCapture::StartCapture( int team, int capmode )
  604. {
  605. // Remap team to get first game team = 1
  606. switch ( team - FIRST_GAME_TEAM+1 )
  607. {
  608. case 1:
  609. m_OnStartTeam1.FireOutput( this, this );
  610. break;
  611. case 2:
  612. m_OnStartTeam2.FireOutput( this, this );
  613. break;
  614. default:
  615. Assert(0);
  616. break;
  617. }
  618. m_StartOutput.FireOutput(this,this);
  619. m_nCapturingTeam = team;
  620. UpdateNumPlayers();
  621. if ( mp_capstyle.GetInt() == 1 )
  622. {
  623. SetCapTimeRemaining( ((m_flCapTime * 2) * m_TeamData[team].iNumRequiredToCap) );
  624. }
  625. else
  626. {
  627. SetCapTimeRemaining( m_flCapTime );
  628. }
  629. m_bCapturing = true;
  630. m_bBlocked = false;
  631. m_iCapMode = capmode;
  632. m_flLastReductionTime = gpGlobals->curtime;
  633. UpdateCappingTeam( m_nCapturingTeam );
  634. UpdateBlocked();
  635. if( m_hPoint )
  636. {
  637. int numcappers = 0;
  638. int cappingplayers[MAX_AREA_CAPPERS];
  639. GetNumCappingPlayers( m_nCapturingTeam, numcappers, cappingplayers );
  640. m_hPoint->CaptureStart( m_nCapturingTeam, numcappers, cappingplayers );
  641. }
  642. // tell all touching players to start racking up capture points
  643. CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL;
  644. if ( pMaster )
  645. {
  646. float flRate = pMaster->GetPartialCapturePointRate();
  647. if ( flRate > 0.0f )
  648. {
  649. // for each player touch
  650. CTeam *pTeam = GetGlobalTeam( m_nCapturingTeam );
  651. if ( pTeam )
  652. {
  653. for ( int i=0;i<pTeam->GetNumPlayers();i++ )
  654. {
  655. CBaseMultiplayerPlayer *pPlayer = ToBaseMultiplayerPlayer( pTeam->GetPlayer(i) );
  656. if ( pPlayer && IsTouching( pPlayer ) )
  657. {
  658. pPlayer->StartScoringEscortPoints( flRate );
  659. }
  660. }
  661. }
  662. }
  663. }
  664. }
  665. //-----------------------------------------------------------------------------
  666. // Purpose:
  667. //-----------------------------------------------------------------------------
  668. void CTriggerAreaCapture::GetNumCappingPlayers( int team, int &numcappers, int *cappingplayers )
  669. {
  670. numcappers = 0;
  671. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  672. {
  673. CBaseEntity *ent = UTIL_PlayerByIndex( i );
  674. if ( ent )
  675. {
  676. CBaseMultiplayerPlayer *player = ToBaseMultiplayerPlayer(ent);
  677. if ( IsTouching( player ) && ( player->GetTeamNumber() == team ) ) // need to make sure disguised spies aren't included in the list of capping players
  678. {
  679. if ( numcappers < MAX_AREA_CAPPERS-1 )
  680. {
  681. cappingplayers[numcappers] = i;
  682. numcappers++;
  683. }
  684. }
  685. }
  686. }
  687. if ( numcappers < MAX_AREA_CAPPERS )
  688. {
  689. cappingplayers[numcappers] = 0; //null terminate :)
  690. }
  691. }
  692. //-----------------------------------------------------------------------------
  693. // Purpose:
  694. //-----------------------------------------------------------------------------
  695. void CTriggerAreaCapture::EndCapture( int team )
  696. {
  697. IncrementCapAttemptNumber();
  698. // Remap team to get first game team = 1
  699. switch ( team - FIRST_GAME_TEAM+1 )
  700. {
  701. case 1:
  702. m_OnCapTeam1.FireOutput( this, this );
  703. break;
  704. case 2:
  705. m_OnCapTeam2.FireOutput( this, this );
  706. break;
  707. default:
  708. Assert(0);
  709. break;
  710. }
  711. m_CapOutput.FireOutput(this,this);
  712. int numcappers = 0;
  713. int cappingplayers[MAX_AREA_CAPPERS];
  714. GetNumCappingPlayers( team, numcappers, cappingplayers );
  715. // Handle this before we assign the new team as the owner of this area
  716. HandleRespawnTimeAdjustments( m_nOwningTeam, team );
  717. m_nOwningTeam = team;
  718. m_bCapturing = false;
  719. m_nCapturingTeam = TEAM_UNASSIGNED;
  720. SetCapTimeRemaining( 0 );
  721. //there may have been more than one capper, but only report this one.
  722. //he hasn't gotten points yet, and his name will go in the cap string if its needed
  723. //first capper gets name sent and points given by flag.
  724. //other cappers get points manually above, no name in message
  725. //send the player in the cap string
  726. if( m_hPoint )
  727. {
  728. OnEndCapture( m_nOwningTeam );
  729. UpdateOwningTeam();
  730. m_hPoint->SetOwner( m_nOwningTeam, true, numcappers, cappingplayers );
  731. m_hPoint->CaptureEnd();
  732. }
  733. m_OnNumCappersChanged.Set( 0, this, this );
  734. // tell all touching players to stop racking up capture points
  735. CTeam *pTeam = GetGlobalTeam( m_nCapturingTeam );
  736. if ( pTeam )
  737. {
  738. for ( int i=0;i<pTeam->GetNumPlayers();i++ )
  739. {
  740. CBaseMultiplayerPlayer *pPlayer = ToBaseMultiplayerPlayer( pTeam->GetPlayer(i) );
  741. if ( pPlayer && IsTouching( pPlayer ) )
  742. {
  743. pPlayer->StopScoringEscortPoints();
  744. }
  745. }
  746. }
  747. }
  748. //-----------------------------------------------------------------------------
  749. // Purpose:
  750. //-----------------------------------------------------------------------------
  751. void CTriggerAreaCapture::BreakCapture( bool bNotEnoughPlayers )
  752. {
  753. if( m_bCapturing )
  754. {
  755. // Remap team to get first game team = 1
  756. switch ( m_nCapturingTeam - FIRST_GAME_TEAM+1 )
  757. {
  758. case 1:
  759. m_OnBreakTeam1.FireOutput( this, this );
  760. break;
  761. case 2:
  762. m_OnBreakTeam2.FireOutput( this, this );
  763. break;
  764. default:
  765. Assert(0);
  766. break;
  767. }
  768. m_BreakOutput.FireOutput(this,this);
  769. m_bCapturing = false;
  770. m_nCapturingTeam = TEAM_UNASSIGNED;
  771. UpdateCappingTeam( TEAM_UNASSIGNED );
  772. if ( bNotEnoughPlayers )
  773. {
  774. IncrementCapAttemptNumber();
  775. }
  776. SetCapTimeRemaining( 0 );
  777. if( m_hPoint )
  778. {
  779. m_hPoint->CaptureEnd();
  780. }
  781. m_OnNumCappersChanged.Set( 0, this, this );
  782. // tell all touching players to stop racking up capture points
  783. CTeam *pTeam = GetGlobalTeam( m_nCapturingTeam );
  784. if ( pTeam )
  785. {
  786. for ( int i=0;i<pTeam->GetNumPlayers();i++ )
  787. {
  788. CBaseMultiplayerPlayer *pPlayer = ToBaseMultiplayerPlayer( pTeam->GetPlayer(i) );
  789. if ( pPlayer && IsTouching( pPlayer ) )
  790. {
  791. pPlayer->StopScoringEscortPoints();
  792. }
  793. }
  794. }
  795. }
  796. }
  797. //-----------------------------------------------------------------------------
  798. // Purpose:
  799. //-----------------------------------------------------------------------------
  800. void CTriggerAreaCapture::IncrementCapAttemptNumber( void )
  801. {
  802. m_iCapAttemptNumber++;
  803. m_Blockers.Purge();
  804. }
  805. //-----------------------------------------------------------------------------
  806. // Purpose:
  807. //-----------------------------------------------------------------------------
  808. void CTriggerAreaCapture::InputRoundSpawn( inputdata_t &inputdata )
  809. {
  810. // find the flag we're linked to
  811. if( !m_hPoint )
  812. {
  813. m_hPoint = dynamic_cast<CTeamControlPoint*>( gEntList.FindEntityByName(NULL, STRING(m_iszCapPointName) ) );
  814. if ( m_hPoint )
  815. {
  816. m_nOwningTeam = m_hPoint->GetOwner();
  817. for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ )
  818. {
  819. m_hPoint->SetCappersRequiredForTeam( i, m_TeamData[i].iNumRequiredToCap );
  820. ObjectiveResource()->SetCPRequiredCappers( m_hPoint->GetPointIndex(), i, m_TeamData[i].iNumRequiredToCap );
  821. ObjectiveResource()->SetTeamCanCap( m_hPoint->GetPointIndex(), i, m_TeamData[i].bCanCap );
  822. if ( mp_capstyle.GetInt() == 1 )
  823. {
  824. ObjectiveResource()->SetCPCapTime( m_hPoint->GetPointIndex(), i, (m_flCapTime * 2) * m_TeamData[i].iNumRequiredToCap );
  825. }
  826. else
  827. {
  828. ObjectiveResource()->SetCPCapTime( m_hPoint->GetPointIndex(), i, m_flCapTime );
  829. }
  830. }
  831. }
  832. }
  833. }
  834. //-----------------------------------------------------------------------------
  835. // Purpose:
  836. //-----------------------------------------------------------------------------
  837. void CTriggerAreaCapture::InputSetTeamCanCap( inputdata_t &inputdata )
  838. {
  839. // Get the interaction name & target
  840. char parseString[255];
  841. Q_strncpy(parseString, inputdata.value.String(), sizeof(parseString));
  842. char *pszParam = strtok(parseString," ");
  843. if ( pszParam && pszParam[0] )
  844. {
  845. int iTeam = atoi( pszParam );
  846. pszParam = strtok(NULL," ");
  847. if ( pszParam && pszParam[0] )
  848. {
  849. bool bCanCap = (atoi(pszParam) != 0);
  850. if ( iTeam >= 0 && iTeam < GetNumberOfTeams() )
  851. {
  852. m_TeamData[iTeam].bCanCap = bCanCap;
  853. if ( m_hPoint )
  854. {
  855. ObjectiveResource()->SetTeamCanCap( m_hPoint->GetPointIndex(), iTeam, m_TeamData[iTeam].bCanCap );
  856. }
  857. return;
  858. }
  859. }
  860. }
  861. Warning("%s(%s) received SetTeamCanCap input with invalid format. Format should be: <team number> <can cap (0/1)>.\n", GetClassname(), GetDebugName() );
  862. }
  863. void CTriggerAreaCapture::InputCaptureCurrentCP( inputdata_t &inputdata )
  864. {
  865. if ( m_bCapturing )
  866. {
  867. EndCapture( m_nCapturingTeam );
  868. }
  869. }
  870. void CTriggerAreaCapture::InputSetControlPoint( inputdata_t &inputdata )
  871. {
  872. BreakCapture( false ); // clear the capping for the previous point, forces us to recalc on the new one
  873. char parseString[255];
  874. Q_strncpy(parseString, inputdata.value.String(), sizeof(parseString));
  875. m_iszCapPointName = MAKE_STRING( parseString );
  876. m_hPoint = NULL; // force a reset of this
  877. InputRoundSpawn( inputdata );
  878. // force everyone touching to re-touch so the hud gets set up properly
  879. for ( int i = 0; i < m_hTouchingEntities.Count(); i++ )
  880. {
  881. CBaseEntity *ent = m_hTouchingEntities[i];
  882. if ( ent && ent->IsPlayer() )
  883. {
  884. EndTouch( ent );
  885. StartTouch( ent );
  886. }
  887. }
  888. }
  889. //-----------------------------------------------------------------------------
  890. // Purpose: Check if this player's death causes a block
  891. // return FALSE if the player is not in this area
  892. // return TRUE otherwise ( eg player is in area, but his death does not cause break )
  893. //-----------------------------------------------------------------------------
  894. bool CTriggerAreaCapture::CheckIfDeathCausesBlock( CBaseMultiplayerPlayer *pVictim, CBaseMultiplayerPlayer *pKiller )
  895. {
  896. if ( !pVictim || !pKiller )
  897. return false;
  898. // make sure this player is in this area
  899. if ( !IsTouching( pVictim ) )
  900. return false;
  901. // Teamkills shouldn't give a block reward
  902. if ( pVictim->GetTeamNumber() == pKiller->GetTeamNumber() )
  903. return true;
  904. // return if the area is not being capped
  905. if ( !m_bCapturing )
  906. return true;
  907. int iTeam = pVictim->GetTeamNumber();
  908. // return if this player's team is not capping the area
  909. if ( iTeam != m_nCapturingTeam )
  910. return true;
  911. // break early incase we kill multiple people in the same frame
  912. bool bBreakCap = false;
  913. if ( mp_capstyle.GetInt() == 1 )
  914. {
  915. bBreakCap = (m_TeamData[m_nCapturingTeam].iBlockedTouching - 1) <= 0;
  916. }
  917. else
  918. {
  919. bBreakCap = ( m_TeamData[m_nCapturingTeam].iBlockedTouching - 1 < m_TeamData[m_nCapturingTeam].iNumRequiredToCap );
  920. }
  921. if ( bBreakCap )
  922. {
  923. m_hPoint->CaptureBlocked( pKiller );
  924. //BreakCapture( true );
  925. }
  926. return true;
  927. }
  928. //-----------------------------------------------------------------------------
  929. // Purpose:
  930. //-----------------------------------------------------------------------------
  931. void CTriggerAreaCapture::UpdateNumPlayers( void )
  932. {
  933. if( !m_hPoint )
  934. return;
  935. int index = m_hPoint->GetPointIndex();
  936. for ( int i = 0; i < m_TeamData.Count(); i++ )
  937. {
  938. if ( i >= FIRST_GAME_TEAM && i == m_nCapturingTeam )
  939. {
  940. m_OnNumCappersChanged.Set( m_TeamData[i].iNumTouching, this, this );
  941. }
  942. ObjectiveResource()->SetNumPlayers( index, i, m_TeamData[i].iNumTouching );
  943. }
  944. }
  945. //-----------------------------------------------------------------------------
  946. // Purpose:
  947. //-----------------------------------------------------------------------------
  948. void CTriggerAreaCapture::UpdateOwningTeam( void )
  949. {
  950. if ( m_hPoint )
  951. {
  952. ObjectiveResource()->SetOwningTeam( m_hPoint->GetPointIndex(), m_nOwningTeam );
  953. }
  954. }
  955. //-----------------------------------------------------------------------------
  956. // Purpose:
  957. //-----------------------------------------------------------------------------
  958. void CTriggerAreaCapture::UpdateCappingTeam( int iTeam )
  959. {
  960. if ( m_hPoint )
  961. {
  962. ObjectiveResource()->SetCappingTeam( m_hPoint->GetPointIndex(), iTeam );
  963. }
  964. }
  965. //-----------------------------------------------------------------------------
  966. // Purpose:
  967. //-----------------------------------------------------------------------------
  968. void CTriggerAreaCapture::UpdateTeamInZone( void )
  969. {
  970. if ( m_hPoint )
  971. {
  972. ObjectiveResource()->SetTeamInZone( m_hPoint->GetPointIndex(), m_nTeamInZone );
  973. }
  974. }
  975. //-----------------------------------------------------------------------------
  976. // Purpose:
  977. //-----------------------------------------------------------------------------
  978. void CTriggerAreaCapture::UpdateBlocked( void )
  979. {
  980. if ( m_hPoint )
  981. {
  982. ObjectiveResource()->SetCapBlocked( m_hPoint->GetPointIndex(), m_bBlocked );
  983. m_hPoint->CaptureInterrupted( m_bBlocked );
  984. }
  985. }