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.

922 lines
27 KiB

  1. //===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "cbase.h"
  7. #include "team_control_point.h"
  8. #include "player.h"
  9. #include "teamplay_gamerules.h"
  10. #include "teamplayroundbased_gamerules.h"
  11. #include "team.h"
  12. #include "team_control_point_master.h"
  13. #include "mp_shareddefs.h"
  14. #include "engine/IEngineSound.h"
  15. #include "soundenvelope.h"
  16. // NOTE: This has to be the last file included!
  17. #include "tier0/memdbgon.h"
  18. BEGIN_DATADESC(CTeamControlPoint)
  19. DEFINE_KEYFIELD( m_iszPrintName, FIELD_STRING, "point_printname" ),
  20. DEFINE_KEYFIELD( m_iCPGroup, FIELD_INTEGER, "point_group" ),
  21. DEFINE_KEYFIELD( m_iDefaultOwner, FIELD_INTEGER, "point_default_owner" ),
  22. DEFINE_KEYFIELD( m_iPointIndex, FIELD_INTEGER, "point_index" ),
  23. DEFINE_KEYFIELD( m_iWarnOnCap, FIELD_INTEGER, "point_warn_on_cap" ),
  24. DEFINE_KEYFIELD( m_iszWarnSound, FIELD_STRING, "point_warn_sound" ),
  25. DEFINE_KEYFIELD( m_iszCaptureStartSound, FIELD_STRING, "point_capture_start_sound" ),
  26. DEFINE_KEYFIELD( m_iszCaptureEndSound, FIELD_STRING, "point_capture_end_sound" ),
  27. DEFINE_KEYFIELD( m_iszCaptureInProgress, FIELD_STRING, "point_capture_progress_sound" ),
  28. DEFINE_KEYFIELD( m_iszCaptureInterrupted, FIELD_STRING, "point_capture_interrupted_sound" ),
  29. DEFINE_KEYFIELD( m_bRandomOwnerOnRestart, FIELD_BOOLEAN, "random_owner_on_restart" ),
  30. // DEFINE_FIELD( m_iTeam, FIELD_INTEGER ),
  31. // DEFINE_FIELD( m_iIndex, FIELD_INTEGER ),
  32. // DEFINE_FIELD( m_TeamData, CUtlVector < perteamdata_t > ),
  33. // DEFINE_FIELD( m_bPointVisible, FIELD_INTEGER ),
  34. // DEFINE_FIELD( m_bActive, FIELD_BOOLEAN ),
  35. // DEFINE_FIELD( m_iszName, FIELD_STRING ),
  36. // DEFINE_FIELD( m_bStartDisabled, FIELD_BOOLEAN ),
  37. // DEFINE_FIELD( m_flLastContestedAt, FIELD_FLOAT ),
  38. // DEFINE_FIELD( m_pCaptureInProgressSound, CSoundPatch ),
  39. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetOwner", InputSetOwner ),
  40. DEFINE_INPUTFUNC( FIELD_VOID, "ShowModel", InputShowModel ),
  41. DEFINE_INPUTFUNC( FIELD_VOID, "HideModel", InputHideModel ),
  42. DEFINE_INPUTFUNC( FIELD_VOID, "RoundActivate", InputRoundActivate ),
  43. DEFINE_OUTPUT( m_OnCapTeam1, "OnCapTeam1" ), // these are fired whenever the point changes modes
  44. DEFINE_OUTPUT( m_OnCapTeam2, "OnCapTeam2" ),
  45. DEFINE_OUTPUT( m_OnCapReset, "OnCapReset" ),
  46. DEFINE_OUTPUT( m_OnOwnerChangedToTeam1, "OnOwnerChangedToTeam1" ), // these are fired when a team does the work to change the owner
  47. DEFINE_OUTPUT( m_OnOwnerChangedToTeam2, "OnOwnerChangedToTeam2" ),
  48. DEFINE_OUTPUT( m_OnRoundStartOwnedByTeam1, "OnRoundStartOwnedByTeam1" ), // these are fired when a round is starting
  49. DEFINE_OUTPUT( m_OnRoundStartOwnedByTeam2, "OnRoundStartOwnedByTeam2" ),
  50. DEFINE_THINKFUNC( AnimThink ),
  51. END_DATADESC();
  52. LINK_ENTITY_TO_CLASS( team_control_point, CTeamControlPoint );
  53. //-----------------------------------------------------------------------------
  54. // Purpose:
  55. //-----------------------------------------------------------------------------
  56. CTeamControlPoint::CTeamControlPoint()
  57. {
  58. m_TeamData.SetSize( GetNumberOfTeams() );
  59. m_pCaptureInProgressSound = NULL;
  60. #ifdef TF_DLL
  61. UseClientSideAnimation();
  62. #endif
  63. }
  64. //-----------------------------------------------------------------------------
  65. // Purpose:
  66. //-----------------------------------------------------------------------------
  67. void CTeamControlPoint::Spawn( void )
  68. {
  69. // Validate our default team
  70. if ( m_iDefaultOwner < 0 || m_iDefaultOwner >= GetNumberOfTeams() )
  71. {
  72. Warning( "team_control_point '%s' has bad point_default_owner.\n", GetDebugName() );
  73. m_iDefaultOwner = TEAM_UNASSIGNED;
  74. }
  75. #ifdef TF_DLL
  76. if ( m_iszCaptureStartSound == NULL_STRING )
  77. {
  78. m_iszCaptureStartSound = AllocPooledString( "Hologram.Start" );
  79. }
  80. if ( m_iszCaptureEndSound == NULL_STRING )
  81. {
  82. m_iszCaptureEndSound = AllocPooledString( "Hologram.Stop" );
  83. }
  84. if ( m_iszCaptureInProgress == NULL_STRING )
  85. {
  86. m_iszCaptureInProgress = AllocPooledString( "Hologram.Move" );
  87. }
  88. if ( m_iszCaptureInterrupted == NULL_STRING )
  89. {
  90. m_iszCaptureInterrupted = AllocPooledString( "Hologram.Interrupted" );
  91. }
  92. #endif
  93. Precache();
  94. InternalSetOwner( m_iDefaultOwner, false ); //init the owner of this point
  95. SetActive( !m_bStartDisabled );
  96. BaseClass::Spawn();
  97. SetPlaybackRate( 1.0 );
  98. SetThink( &CTeamControlPoint::AnimThink );
  99. SetNextThink( gpGlobals->curtime + 0.1f );
  100. if ( FBitSet( m_spawnflags, SF_CAP_POINT_HIDE_MODEL ) )
  101. {
  102. AddEffects( EF_NODRAW );
  103. }
  104. if ( FBitSet( m_spawnflags, SF_CAP_POINT_HIDE_SHADOW ) )
  105. {
  106. AddEffects( EF_NOSHADOW );
  107. }
  108. m_flLastContestedAt = -1;
  109. m_pCaptureInProgressSound = NULL;
  110. }
  111. //-----------------------------------------------------------------------------
  112. // Purpose:
  113. //-----------------------------------------------------------------------------
  114. bool CTeamControlPoint::KeyValue( const char *szKeyName, const char *szValue )
  115. {
  116. if ( !Q_strncmp( szKeyName, "team_capsound_", 14 ) )
  117. {
  118. int iTeam = atoi(szKeyName+14);
  119. Assert( iTeam >= 0 && iTeam < m_TeamData.Count() );
  120. m_TeamData[iTeam].iszCapSound = AllocPooledString(szValue);
  121. }
  122. else if ( !Q_strncmp( szKeyName, "team_model_", 11 ) )
  123. {
  124. int iTeam = atoi(szKeyName+11);
  125. Assert( iTeam >= 0 && iTeam < m_TeamData.Count() );
  126. m_TeamData[iTeam].iszModel = AllocPooledString(szValue);
  127. }
  128. else if ( !Q_strncmp( szKeyName, "team_timedpoints_", 17 ) )
  129. {
  130. int iTeam = atoi(szKeyName+17);
  131. Assert( iTeam >= 0 && iTeam < m_TeamData.Count() );
  132. m_TeamData[iTeam].iTimedPoints = atoi(szValue);
  133. }
  134. else if ( !Q_strncmp( szKeyName, "team_bodygroup_", 15 ) )
  135. {
  136. int iTeam = atoi(szKeyName+15);
  137. Assert( iTeam >= 0 && iTeam < m_TeamData.Count() );
  138. m_TeamData[iTeam].iModelBodygroup = atoi(szValue);
  139. }
  140. else if ( !Q_strncmp( szKeyName, "team_icon_", 10 ) )
  141. {
  142. int iTeam = atoi(szKeyName+10);
  143. Assert( iTeam >= 0 && iTeam < m_TeamData.Count() );
  144. m_TeamData[iTeam].iszIcon = AllocPooledString(szValue);
  145. }
  146. else if ( !Q_strncmp( szKeyName, "team_overlay_", 13 ) )
  147. {
  148. int iTeam = atoi(szKeyName+13);
  149. Assert( iTeam >= 0 && iTeam < m_TeamData.Count() );
  150. m_TeamData[iTeam].iszOverlay = AllocPooledString(szValue);
  151. }
  152. else if ( !Q_strncmp( szKeyName, "team_previouspoint_", 19 ) )
  153. {
  154. int iTeam;
  155. int iPoint = 0;
  156. sscanf( szKeyName+19, "%d_%d", &iTeam, &iPoint );
  157. Assert( iTeam >= 0 && iTeam < m_TeamData.Count() );
  158. Assert( iPoint >= 0 && iPoint < MAX_PREVIOUS_POINTS );
  159. m_TeamData[iTeam].iszPreviousPoint[iPoint] = AllocPooledString(szValue);
  160. }
  161. else
  162. {
  163. return BaseClass::KeyValue( szKeyName, szValue );
  164. }
  165. return true;
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Purpose:
  169. //-----------------------------------------------------------------------------
  170. void CTeamControlPoint::Precache( void )
  171. {
  172. for ( int i = 0; i < m_TeamData.Count(); i++ )
  173. {
  174. // Skip over spectator
  175. if ( i == TEAM_SPECTATOR )
  176. continue;
  177. if ( m_TeamData[i].iszCapSound != NULL_STRING )
  178. {
  179. PrecacheScriptSound( STRING(m_TeamData[i].iszCapSound) );
  180. }
  181. if ( m_TeamData[i].iszModel != NULL_STRING )
  182. {
  183. PrecacheModel( STRING(m_TeamData[i].iszModel) );
  184. }
  185. if ( m_TeamData[i].iszIcon != NULL_STRING )
  186. {
  187. PrecacheMaterial( STRING( m_TeamData[i].iszIcon ) );
  188. m_TeamData[i].iIcon = GetMaterialIndex( STRING( m_TeamData[i].iszIcon ) );
  189. Assert( m_TeamData[i].iIcon != 0 );
  190. }
  191. if ( !m_TeamData[i].iIcon )
  192. {
  193. Warning( "Invalid hud icon material for team %d in control point '%s' ( point index %d )\n", i, GetDebugName(), GetPointIndex() );
  194. }
  195. if ( m_TeamData[i].iszOverlay != NULL_STRING )
  196. {
  197. PrecacheMaterial( STRING( m_TeamData[i].iszOverlay ) );
  198. m_TeamData[i].iOverlay = GetMaterialIndex( STRING( m_TeamData[i].iszOverlay ) );
  199. Assert( m_TeamData[i].iOverlay != 0 );
  200. if ( !m_TeamData[i].iOverlay )
  201. {
  202. Warning( "Invalid hud overlay material for team %d in control point '%s' ( point index %d )\n", i, GetDebugName(), GetPointIndex() );
  203. }
  204. }
  205. }
  206. PrecacheScriptSound( STRING( m_iszCaptureStartSound ) );
  207. PrecacheScriptSound( STRING( m_iszCaptureEndSound ) );
  208. PrecacheScriptSound( STRING( m_iszCaptureInProgress ) );
  209. PrecacheScriptSound( STRING( m_iszCaptureInterrupted ) );
  210. if ( m_iszWarnSound != NULL_STRING )
  211. {
  212. PrecacheScriptSound( STRING( m_iszWarnSound ) );
  213. }
  214. #ifdef TF_DLL
  215. PrecacheScriptSound( "Announcer.ControlPointContested" );
  216. #endif
  217. }
  218. //------------------------------------------------------------------------------
  219. // Purpose:
  220. //------------------------------------------------------------------------------
  221. void CTeamControlPoint::AnimThink( void )
  222. {
  223. StudioFrameAdvance();
  224. DispatchAnimEvents(this);
  225. SetNextThink( gpGlobals->curtime + 0.1f );
  226. }
  227. //-----------------------------------------------------------------------------
  228. // Purpose: Used by ControlMaster to this point to its default owner
  229. //-----------------------------------------------------------------------------
  230. void CTeamControlPoint::InputReset( inputdata_t &input )
  231. {
  232. m_flLastContestedAt = -1;
  233. InternalSetOwner( m_iDefaultOwner, false );
  234. ObjectiveResource()->SetOwningTeam( GetPointIndex(), m_iTeam );
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Purpose:
  238. //-----------------------------------------------------------------------------
  239. void CTeamControlPoint::HandleScoring( int iTeam )
  240. {
  241. if ( TeamplayRoundBasedRules() && !TeamplayRoundBasedRules()->ShouldScorePerRound() )
  242. {
  243. GetGlobalTeam( iTeam )->AddScore( 1 );
  244. TeamplayRoundBasedRules()->HandleTeamScoreModify( iTeam, 1 );
  245. CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL;
  246. if ( pMaster && !pMaster->WouldNewCPOwnerWinGame( this, iTeam ) )
  247. {
  248. CTeamRecipientFilter filter( iTeam );
  249. EmitSound( filter, entindex(), "Hud.EndRoundScored" );
  250. }
  251. }
  252. }
  253. //-----------------------------------------------------------------------------
  254. // Purpose: Used by Area caps to set the owner
  255. //-----------------------------------------------------------------------------
  256. void CTeamControlPoint::InputSetOwner( inputdata_t &input )
  257. {
  258. int iCapTeam = input.value.Int();
  259. Assert( iCapTeam >= 0 && iCapTeam < GetNumberOfTeams() );
  260. Assert( input.pCaller );
  261. if ( GetOwner() == iCapTeam )
  262. return;
  263. if ( TeamplayGameRules()->PointsMayBeCaptured() )
  264. {
  265. // must be done before setting the owner
  266. HandleScoring( iCapTeam );
  267. if ( input.pCaller->IsPlayer() )
  268. {
  269. int iCappingPlayer = input.pCaller->entindex();
  270. InternalSetOwner( iCapTeam, true, 1, &iCappingPlayer );
  271. }
  272. else
  273. {
  274. InternalSetOwner( iCapTeam, false );
  275. }
  276. ObjectiveResource()->SetOwningTeam( GetPointIndex(), m_iTeam );
  277. }
  278. }
  279. //-----------------------------------------------------------------------------
  280. // Purpose:
  281. //-----------------------------------------------------------------------------
  282. void CTeamControlPoint::InputShowModel( inputdata_t &input )
  283. {
  284. RemoveEffects( EF_NODRAW );
  285. }
  286. //-----------------------------------------------------------------------------
  287. // Purpose:
  288. //-----------------------------------------------------------------------------
  289. void CTeamControlPoint::InputHideModel( inputdata_t &input )
  290. {
  291. AddEffects( EF_NODRAW );
  292. }
  293. //-----------------------------------------------------------------------------
  294. // Purpose:
  295. //-----------------------------------------------------------------------------
  296. int CTeamControlPoint::GetCurrentHudIconIndex( void )
  297. {
  298. return m_TeamData[GetOwner()].iIcon;
  299. }
  300. //-----------------------------------------------------------------------------
  301. // Purpose:
  302. //-----------------------------------------------------------------------------
  303. int CTeamControlPoint::GetHudIconIndexForTeam( int iGameTeam )
  304. {
  305. return m_TeamData[iGameTeam].iIcon;
  306. }
  307. //-----------------------------------------------------------------------------
  308. // Purpose:
  309. //-----------------------------------------------------------------------------
  310. int CTeamControlPoint::GetHudOverlayIndexForTeam( int iGameTeam )
  311. {
  312. return m_TeamData[iGameTeam].iOverlay;
  313. }
  314. //-----------------------------------------------------------------------------
  315. // Purpose:
  316. //-----------------------------------------------------------------------------
  317. int CTeamControlPoint::GetPreviousPointForTeam( int iGameTeam, int iPrevPoint )
  318. {
  319. Assert( iPrevPoint >= 0 && iPrevPoint < MAX_PREVIOUS_POINTS );
  320. int iRetVal = -1;
  321. CBaseEntity *pEntity = gEntList.FindEntityByName( NULL, STRING(m_TeamData[iGameTeam].iszPreviousPoint[iPrevPoint]) );
  322. if ( pEntity )
  323. {
  324. CTeamControlPoint *pPoint = dynamic_cast<CTeamControlPoint*>( pEntity );
  325. if ( pPoint )
  326. {
  327. iRetVal = pPoint->GetPointIndex();
  328. }
  329. }
  330. return iRetVal;
  331. }
  332. //-----------------------------------------------------------------------------
  333. // Purpose:
  334. //-----------------------------------------------------------------------------
  335. void CTeamControlPoint::ForceOwner( int iTeam )
  336. {
  337. InternalSetOwner( iTeam, false, 0, 0 );
  338. ObjectiveResource()->SetOwningTeam( GetPointIndex(), m_iTeam );
  339. }
  340. //-----------------------------------------------------------------------------
  341. // Purpose:
  342. //-----------------------------------------------------------------------------
  343. void CTeamControlPoint::SetOwner( int iCapTeam, bool bMakeSound, int iNumCappers, int *pCappingPlayers )
  344. {
  345. if ( TeamplayGameRules()->PointsMayBeCaptured() )
  346. {
  347. // must be done before setting the owner
  348. HandleScoring( iCapTeam );
  349. InternalSetOwner( iCapTeam, bMakeSound, iNumCappers, pCappingPlayers );
  350. ObjectiveResource()->SetOwningTeam( GetPointIndex(), m_iTeam );
  351. }
  352. }
  353. //-----------------------------------------------------------------------------
  354. // Purpose:
  355. //-----------------------------------------------------------------------------
  356. void CTeamControlPoint::CaptureStart( int iCapTeam, int iNumCappingPlayers, int *pCappingPlayers )
  357. {
  358. int iNumCappers = iNumCappingPlayers;
  359. IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_point_startcapture" );
  360. if ( event )
  361. {
  362. event->SetInt( "cp", m_iPointIndex );
  363. event->SetString( "cpname", STRING( m_iszPrintName ) );
  364. event->SetInt( "team", m_iTeam );
  365. event->SetInt( "capteam", iCapTeam );
  366. // safety check
  367. if ( iNumCappers > 8 )
  368. {
  369. iNumCappers = 8;
  370. }
  371. char cappers[9]; // pCappingPlayers should be max length 8
  372. int i;
  373. for( i = 0 ; i < iNumCappers ; i++ )
  374. {
  375. cappers[i] = (char)pCappingPlayers[i];
  376. }
  377. cappers[i] = '\0';
  378. // pCappingPlayers is a null terminated list of player indices
  379. event->SetString( "cappers", cappers );
  380. event->SetInt( "priority", 7 );
  381. gameeventmanager->FireEvent( event );
  382. }
  383. }
  384. //-----------------------------------------------------------------------------
  385. // Purpose:
  386. //-----------------------------------------------------------------------------
  387. void CTeamControlPoint::CaptureEnd( void )
  388. {
  389. StopLoopingSounds();
  390. if ( !FBitSet( m_spawnflags, SF_CAP_POINT_NO_CAP_SOUNDS ) )
  391. {
  392. EmitSound( STRING( m_iszCaptureEndSound ) );
  393. }
  394. }
  395. //-----------------------------------------------------------------------------
  396. // Purpose:
  397. //-----------------------------------------------------------------------------
  398. void CTeamControlPoint::CaptureInterrupted( bool bBlocked )
  399. {
  400. StopLoopingSounds();
  401. if ( FBitSet( m_spawnflags, SF_CAP_POINT_NO_CAP_SOUNDS ) )
  402. {
  403. return;
  404. }
  405. const char *pSoundName = NULL;
  406. if ( bBlocked == true )
  407. {
  408. pSoundName = STRING( m_iszCaptureInterrupted );
  409. }
  410. else
  411. {
  412. pSoundName = STRING( m_iszCaptureInProgress );
  413. EmitSound( STRING( m_iszCaptureStartSound ) );
  414. }
  415. if ( m_pCaptureInProgressSound == NULL && pSoundName != NULL )
  416. {
  417. CPASFilter filter( GetAbsOrigin() );
  418. CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController();
  419. m_pCaptureInProgressSound = controller.SoundCreate( filter, entindex(), pSoundName );
  420. controller.Play( m_pCaptureInProgressSound, 1.0, 100 );
  421. }
  422. }
  423. //-----------------------------------------------------------------------------
  424. // Purpose:
  425. //-----------------------------------------------------------------------------
  426. void CTeamControlPoint::StopLoopingSounds( void )
  427. {
  428. CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController();
  429. if ( m_pCaptureInProgressSound )
  430. {
  431. controller.SoundDestroy( m_pCaptureInProgressSound );
  432. m_pCaptureInProgressSound = NULL;
  433. }
  434. }
  435. //-----------------------------------------------------------------------------
  436. // Purpose: Sets the new owner of the point, plays the appropriate sound and shows the right model
  437. //-----------------------------------------------------------------------------
  438. void CTeamControlPoint::InternalSetOwner( int iCapTeam, bool bMakeSound, int iNumCappers, int *pCappingPlayers )
  439. {
  440. Assert( iCapTeam >= 0 && iCapTeam < GetNumberOfTeams() );
  441. int iOldTeam = m_iTeam;
  442. m_iTeam = iCapTeam;
  443. ChangeTeam( iCapTeam );
  444. if ( bMakeSound )
  445. {
  446. CBroadcastRecipientFilter filter;
  447. EmitSound( filter, entindex(), STRING( m_TeamData[m_iTeam].iszCapSound ) );
  448. }
  449. // Update visuals
  450. SetModel( STRING(m_TeamData[m_iTeam].iszModel) );
  451. SetBodygroup( 0, m_iTeam );
  452. m_nSkin = ( m_iTeam == TEAM_UNASSIGNED ) ? 2 : (m_iTeam - 2);
  453. ResetSequence( LookupSequence("idle") );
  454. // We add 1 to the index because we consider the default "no points capped" as 0.
  455. TeamplayGameRules()->SetLastCapPointChanged( m_iPointIndex+1 );
  456. // Determine the pose parameters for each team
  457. for ( int i = 0; i < m_TeamData.Count(); i++ )
  458. {
  459. // Skip spectator
  460. if ( i == TEAM_SPECTATOR )
  461. continue;
  462. if ( GetModelPtr() && GetModelPtr()->SequencesAvailable() )
  463. {
  464. m_TeamData[i].iTeamPoseParam = LookupPoseParameter( UTIL_VarArgs( "cappoint_%d_percentage", i ) );
  465. }
  466. else
  467. {
  468. m_TeamData[i].iTeamPoseParam = -1;
  469. }
  470. }
  471. UpdateCapPercentage();
  472. if ( m_iTeam == TEAM_UNASSIGNED )
  473. {
  474. m_OnCapReset.FireOutput( this, this );
  475. }
  476. else
  477. {
  478. // Remap team to get first game team = 1
  479. switch ( m_iTeam - FIRST_GAME_TEAM+1 )
  480. {
  481. case 1:
  482. m_OnCapTeam1.FireOutput( this, this );
  483. break;
  484. case 2:
  485. m_OnCapTeam2.FireOutput( this, this );
  486. break;
  487. default:
  488. Assert(0);
  489. break;
  490. }
  491. }
  492. // If we're playing a sound, this is a true cap by players.
  493. if ( bMakeSound )
  494. {
  495. if ( iOldTeam > LAST_SHARED_TEAM && iOldTeam != m_iTeam )
  496. {
  497. // Make the members of our old team say something
  498. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  499. {
  500. CBaseMultiplayerPlayer *pPlayer = ToBaseMultiplayerPlayer( UTIL_PlayerByIndex( i ) );
  501. if ( !pPlayer )
  502. continue;
  503. if ( pPlayer->GetTeamNumber() == iOldTeam )
  504. {
  505. pPlayer->SpeakConceptIfAllowed( MP_CONCEPT_LOST_CONTROL_POINT );
  506. }
  507. }
  508. }
  509. for( int i = 0; i < iNumCappers; i++ )
  510. {
  511. int playerIndex = pCappingPlayers[i];
  512. Assert( playerIndex > 0 && playerIndex <= gpGlobals->maxClients );
  513. PlayerCapped( ToBaseMultiplayerPlayer(UTIL_PlayerByIndex( playerIndex )) );
  514. }
  515. // Remap team to get first game team = 1
  516. switch ( m_iTeam - FIRST_GAME_TEAM+1 )
  517. {
  518. case 1:
  519. m_OnOwnerChangedToTeam1.FireOutput( this, this );
  520. break;
  521. case 2:
  522. m_OnOwnerChangedToTeam2.FireOutput( this, this );
  523. break;
  524. }
  525. if ( m_iTeam != TEAM_UNASSIGNED && iNumCappers )
  526. {
  527. SendCapString( m_iTeam, iNumCappers, pCappingPlayers );
  528. }
  529. }
  530. // Have control point master check the win conditions now!
  531. CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, GetControlPointMasterName() );
  532. while( pEnt )
  533. {
  534. CTeamControlPointMaster *pMaster = dynamic_cast<CTeamControlPointMaster *>( pEnt );
  535. if ( pMaster->IsActive() )
  536. {
  537. pMaster->CheckWinConditions();
  538. }
  539. pEnt = gEntList.FindEntityByClassname( pEnt, GetControlPointMasterName() );
  540. }
  541. }
  542. //-----------------------------------------------------------------------------
  543. // Purpose:
  544. //-----------------------------------------------------------------------------
  545. void CTeamControlPoint::SendCapString( int iCapTeam, int iNumCappingPlayers, int *pCappingPlayers )
  546. {
  547. if ( strlen( STRING(m_iszPrintName) ) <= 0 )
  548. return;
  549. int iNumCappers = iNumCappingPlayers;
  550. IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_point_captured" );
  551. if ( event )
  552. {
  553. event->SetInt( "cp", m_iPointIndex );
  554. event->SetString( "cpname", STRING( m_iszPrintName ) );
  555. event->SetInt( "team", iCapTeam );
  556. // safety check
  557. if ( iNumCappers > 8 )
  558. {
  559. iNumCappers = 8;
  560. }
  561. char cappers[9]; // pCappingPlayers should be max length 8
  562. int i;
  563. for( i = 0 ; i < iNumCappers ; i++ )
  564. {
  565. cappers[i] = (char)pCappingPlayers[i];
  566. }
  567. cappers[i] = '\0';
  568. // pCappingPlayers is a null terminated list of player indices
  569. event->SetString( "cappers", cappers );
  570. event->SetInt( "priority", 9 );
  571. gameeventmanager->FireEvent( event );
  572. }
  573. }
  574. //-----------------------------------------------------------------------------
  575. // Purpose:
  576. //-----------------------------------------------------------------------------
  577. void CTeamControlPoint::CaptureBlocked( CBaseMultiplayerPlayer *pPlayer )
  578. {
  579. if( strlen( STRING(m_iszPrintName) ) <= 0 )
  580. return;
  581. IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_capture_blocked" );
  582. if ( event )
  583. {
  584. event->SetInt( "cp", m_iPointIndex );
  585. event->SetString( "cpname", STRING(m_iszPrintName) );
  586. event->SetInt( "blocker", pPlayer->entindex() );
  587. event->SetInt( "priority", 9 );
  588. gameeventmanager->FireEvent( event );
  589. }
  590. PlayerBlocked( pPlayer );
  591. }
  592. //-----------------------------------------------------------------------------
  593. // Purpose:
  594. //-----------------------------------------------------------------------------
  595. int CTeamControlPoint::GetOwner( void ) const
  596. {
  597. return m_iTeam;
  598. }
  599. //-----------------------------------------------------------------------------
  600. // Purpose:
  601. //-----------------------------------------------------------------------------
  602. int CTeamControlPoint::GetDefaultOwner( void ) const
  603. {
  604. return m_iDefaultOwner;
  605. }
  606. //-----------------------------------------------------------------------------
  607. // Purpose:
  608. //-----------------------------------------------------------------------------
  609. int CTeamControlPoint::GetCPGroup( void )
  610. {
  611. return m_iCPGroup;
  612. }
  613. //-----------------------------------------------------------------------------
  614. // Purpose: Returns the time-based point value of this control point
  615. //-----------------------------------------------------------------------------
  616. int CTeamControlPoint::PointValue( void )
  617. {
  618. if ( GetOwner() != m_iDefaultOwner )
  619. return m_TeamData[ GetOwner() ].iTimedPoints;
  620. return 0;
  621. }
  622. //-----------------------------------------------------------------------------
  623. // Purpose:
  624. //-----------------------------------------------------------------------------
  625. void CTeamControlPoint::SetActive( bool active )
  626. {
  627. m_bActive = active;
  628. if( active )
  629. {
  630. RemoveEffects( EF_NODRAW );
  631. }
  632. else
  633. {
  634. AddEffects( EF_NODRAW );
  635. }
  636. }
  637. //-----------------------------------------------------------------------------
  638. // Purpose:
  639. //-----------------------------------------------------------------------------
  640. void CTeamControlPoint::SetCappersRequiredForTeam( int iGameTeam, int iCappers )
  641. {
  642. m_TeamData[iGameTeam].iPlayersRequired = iCappers;
  643. }
  644. //-----------------------------------------------------------------------------
  645. // Purpose:
  646. //-----------------------------------------------------------------------------
  647. float CTeamControlPoint::LastContestedAt( void )
  648. {
  649. return m_flLastContestedAt;
  650. }
  651. //-----------------------------------------------------------------------------
  652. // Purpose:
  653. //-----------------------------------------------------------------------------
  654. void CTeamControlPoint::SetLastContestedAt( float flTime )
  655. {
  656. m_flLastContestedAt = flTime;
  657. }
  658. //-----------------------------------------------------------------------------
  659. // Purpose:
  660. //-----------------------------------------------------------------------------
  661. void CTeamControlPoint::UpdateCapPercentage( void )
  662. {
  663. for ( int i = LAST_SHARED_TEAM+1; i < m_TeamData.Count(); i++ )
  664. {
  665. // Skip spectator
  666. if ( i == TEAM_SPECTATOR )
  667. continue;
  668. float flPerc = GetTeamCapPercentage(i);
  669. if ( m_TeamData[i].iTeamPoseParam != -1 )
  670. {
  671. SetPoseParameter( m_TeamData[i].iTeamPoseParam, flPerc );
  672. }
  673. }
  674. }
  675. //-----------------------------------------------------------------------------
  676. // Purpose:
  677. //-----------------------------------------------------------------------------
  678. float CTeamControlPoint::GetTeamCapPercentage( int iTeam )
  679. {
  680. int iCappingTeam = ObjectiveResource()->GetCappingTeam( GetPointIndex() );
  681. if ( iCappingTeam == TEAM_UNASSIGNED )
  682. {
  683. // No-one's capping this point.
  684. if ( iTeam == m_iTeam )
  685. return 1.0;
  686. return 0.0;
  687. }
  688. float flCapPerc = ObjectiveResource()->GetCPCapPercentage( GetPointIndex() );
  689. if ( iTeam == iCappingTeam )
  690. return (1.0 - flCapPerc);
  691. if ( iTeam == m_iTeam )
  692. return flCapPerc;
  693. return 0.0;
  694. }
  695. //-----------------------------------------------------------------------------
  696. // Purpose:
  697. //-----------------------------------------------------------------------------
  698. int CTeamControlPoint::DrawDebugTextOverlays( void )
  699. {
  700. int text_offset = BaseClass::DrawDebugTextOverlays();
  701. if (m_debugOverlays & OVERLAY_TEXT_BIT)
  702. {
  703. char tempstr[1024];
  704. Q_snprintf(tempstr, sizeof(tempstr), "INDEX: (%d)", GetPointIndex() );
  705. EntityText(text_offset,tempstr,0);
  706. text_offset++;
  707. Q_snprintf( tempstr, sizeof(tempstr), "Red Previous Points: ");
  708. for ( int i = 0; i < MAX_PREVIOUS_POINTS; i++ )
  709. {
  710. if ( m_TeamData[2].iszPreviousPoint[i] != NULL_STRING )
  711. {
  712. Q_strncat( tempstr, STRING(m_TeamData[2].iszPreviousPoint[i]), 1024, COPY_ALL_CHARACTERS );
  713. Q_strncat( tempstr, ", ", 1024, COPY_ALL_CHARACTERS );
  714. }
  715. }
  716. EntityText(text_offset,tempstr,0);
  717. text_offset++;
  718. Q_snprintf( tempstr, sizeof(tempstr), "Blue Previous Points: " );
  719. for ( int i = 0; i < MAX_PREVIOUS_POINTS; i++ )
  720. {
  721. if ( m_TeamData[3].iszPreviousPoint[i] != NULL_STRING )
  722. {
  723. Q_strncat( tempstr, STRING(m_TeamData[3].iszPreviousPoint[i]), 1024, COPY_ALL_CHARACTERS );
  724. Q_strncat( tempstr, ", ", 1024, COPY_ALL_CHARACTERS );
  725. }
  726. }
  727. EntityText(text_offset,tempstr,0);
  728. text_offset++;
  729. for ( int i = 0; i < MAX_CONTROL_POINT_TEAMS; i++ )
  730. {
  731. if ( ObjectiveResource()->GetBaseControlPointForTeam(i) == GetPointIndex() )
  732. {
  733. Q_snprintf(tempstr, sizeof(tempstr), "Base Control Point for Team %d", i );
  734. EntityText(text_offset,tempstr,0);
  735. text_offset++;
  736. }
  737. }
  738. }
  739. return text_offset;
  740. }
  741. //-----------------------------------------------------------------------------
  742. // Purpose: The specified player took part in capping this point.
  743. //-----------------------------------------------------------------------------
  744. void CTeamControlPoint::PlayerCapped( CBaseMultiplayerPlayer *pPlayer )
  745. {
  746. if ( pPlayer )
  747. {
  748. pPlayer->SpeakConceptIfAllowed( MP_CONCEPT_CAPTURED_POINT );
  749. }
  750. }
  751. //-----------------------------------------------------------------------------
  752. // Purpose: The specified player blocked the enemy team from capping this point.
  753. //-----------------------------------------------------------------------------
  754. void CTeamControlPoint::PlayerBlocked( CBaseMultiplayerPlayer *pPlayer )
  755. {
  756. if ( pPlayer )
  757. {
  758. pPlayer->SpeakConceptIfAllowed( MP_CONCEPT_CAPTURE_BLOCKED );
  759. }
  760. }
  761. //-----------------------------------------------------------------------------
  762. // Purpose:
  763. //-----------------------------------------------------------------------------
  764. void CTeamControlPoint::InputRoundActivate( inputdata_t &inputdata )
  765. {
  766. switch ( m_iTeam - FIRST_GAME_TEAM+1 )
  767. {
  768. case 1:
  769. m_OnRoundStartOwnedByTeam1.FireOutput( this, this );
  770. break;
  771. case 2:
  772. m_OnRoundStartOwnedByTeam2.FireOutput( this, this );
  773. break;
  774. }
  775. }