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.

646 lines
19 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Team management class. Contains all the details for a specific team
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "team.h"
  9. #include "player.h"
  10. #include "team_spawnpoint.h"
  11. #include "usermessages.h"
  12. #if defined ( CSTRIKE15 )
  13. #include "cs_bot.h"
  14. #endif
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. CUtlVector< CTeam * > g_Teams;
  18. extern ConVar mp_radar_showall;
  19. //-----------------------------------------------------------------------------
  20. // Purpose: SendProxy that converts the Team's player UtlVector to entindexes
  21. //-----------------------------------------------------------------------------
  22. void SendProxy_PlayerList( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
  23. {
  24. CTeam *pTeam = (CTeam*)pData;
  25. // If this assertion fails, then SendProxyArrayLength_PlayerArray must have failed.
  26. Assert( iElement < pTeam->m_aPlayers.Count() );
  27. CBasePlayer *pPlayer = pTeam->m_aPlayers[iElement];
  28. pOut->m_Int = pPlayer->entindex();
  29. }
  30. int SendProxyArrayLength_PlayerArray( const void *pStruct, int objectID )
  31. {
  32. CTeam *pTeam = (CTeam*)pStruct;
  33. return pTeam->m_aPlayers.Count();
  34. }
  35. // Datatable
  36. IMPLEMENT_SERVERCLASS_ST_NOBASE(CTeam, DT_Team)
  37. SendPropInt( SENDINFO(m_iTeamNum), 5 ),
  38. SendPropInt( SENDINFO(m_bSurrendered), 0 ),
  39. SendPropInt( SENDINFO(m_scoreTotal), 0 ),
  40. SendPropInt( SENDINFO(m_scoreFirstHalf), 0 ),
  41. SendPropInt( SENDINFO(m_scoreSecondHalf), 0 ),
  42. SendPropInt( SENDINFO(m_scoreOvertime), 0 ),
  43. SendPropInt( SENDINFO(m_iClanID), 32, SPROP_UNSIGNED ),
  44. SendPropString( SENDINFO( m_szTeamname ) ),
  45. SendPropString( SENDINFO( m_szClanTeamname ) ),
  46. SendPropString( SENDINFO( m_szTeamFlagImage ) ),
  47. SendPropString( SENDINFO( m_szTeamLogoImage ) ),
  48. SendPropString( SENDINFO( m_szTeamMatchStat ) ),
  49. SendPropInt( SENDINFO( m_nGGLeaderEntIndex_CT ), 0 ),
  50. SendPropInt( SENDINFO( m_nGGLeaderEntIndex_T ), 0 ),
  51. SendPropInt( SENDINFO(m_numMapVictories), 4, SPROP_UNSIGNED ),
  52. SendPropArray2(
  53. SendProxyArrayLength_PlayerArray,
  54. SendPropInt("player_array_element", 0, 4, 10, SPROP_UNSIGNED, SendProxy_PlayerList),
  55. MAX_PLAYERS,
  56. 0,
  57. "player_array"
  58. )
  59. END_SEND_TABLE()
  60. LINK_ENTITY_TO_CLASS( team_manager, CTeam );
  61. //-----------------------------------------------------------------------------
  62. // Purpose: Get a pointer to the specified team manager
  63. //-----------------------------------------------------------------------------
  64. CTeam *GetGlobalTeam( int iIndex )
  65. {
  66. if ( iIndex < 0 || iIndex >= GetNumberOfTeams() )
  67. return NULL;
  68. return g_Teams[ iIndex ];
  69. }
  70. //-----------------------------------------------------------------------------
  71. // Purpose: Get the number of team managers
  72. //-----------------------------------------------------------------------------
  73. int GetNumberOfTeams( void )
  74. {
  75. return g_Teams.Count();
  76. }
  77. const char* GetTeamName( int iTeam )
  78. {
  79. CTeam *pTeam = GetGlobalTeam( iTeam );
  80. if ( pTeam )
  81. {
  82. return pTeam->GetName();
  83. }
  84. else
  85. {
  86. return "UNKNOWN TEAM";
  87. }
  88. }
  89. int CTeam::m_nStaticGGLeader_CT = -1;
  90. int CTeam::m_nStaticGGLeader_T = -1;
  91. //-----------------------------------------------------------------------------
  92. // Purpose: Needed because this is an entity, but should never be used
  93. //-----------------------------------------------------------------------------
  94. CTeam::CTeam( void )
  95. {
  96. memset( m_szTeamname.GetForModify(), 0, sizeof(m_szTeamname) );
  97. memset( m_szClanTeamname.GetForModify(), 0, sizeof(m_szClanTeamname) );
  98. memset( m_szTeamFlagImage.GetForModify(), 0, sizeof(m_szTeamFlagImage) );
  99. memset( m_szTeamLogoImage.GetForModify(), 0, sizeof(m_szTeamLogoImage) );
  100. memset( m_szTeamMatchStat.GetForModify(), 0, sizeof( m_szTeamMatchStat ) );
  101. m_numMapVictories.GetForModify() = 0;
  102. ResetTeamLeaders();
  103. }
  104. //-----------------------------------------------------------------------------
  105. // Purpose:
  106. //-----------------------------------------------------------------------------
  107. CTeam::~CTeam( void )
  108. {
  109. m_aSpawnPoints.Purge();
  110. m_aPlayers.Purge();
  111. }
  112. void CTeam::ResetTeamLeaders()
  113. {
  114. m_flLastPlayerSortTime = 0;
  115. m_nGGLeaderEntIndex_CT = -1;
  116. m_nGGLeaderEntIndex_T = -1;
  117. m_bGGHasLeader_CT = false;
  118. m_bGGHasLeader_T = false;
  119. }
  120. //-----------------------------------------------------------------------------
  121. // Purpose: Called every frame
  122. //-----------------------------------------------------------------------------
  123. void CTeam::Think( void )
  124. {
  125. if ( m_flLastPlayerSortTime + 0.025f < gpGlobals->curtime )
  126. {
  127. DetermineGGLeaderAndSort();
  128. }
  129. }
  130. void CTeam::DetermineGGLeaderAndSort( void )
  131. {
  132. CUtlVector< CCSPlayer* > playerList_CT;
  133. CUtlVector< CCSPlayer* > playerList_T;
  134. int iNumPlayers = GetNumPlayers();
  135. // m_aPlayers.Sort( PlayerSortFunction );
  136. for ( int i = 0; i < iNumPlayers; i++ )
  137. {
  138. CCSPlayer *player = static_cast< CCSPlayer* >( GetPlayer( i ) );
  139. if ( player )
  140. {
  141. if ( player->GetTeamNumber() == TEAM_CT )
  142. {
  143. if ( player->GetPlayerGunGameWeaponIndex() > 0 )
  144. m_bGGHasLeader_CT = true;
  145. playerList_CT.AddToTail( player );
  146. }
  147. else if ( player->GetTeamNumber() == TEAM_TERRORIST )
  148. {
  149. if ( player->GetPlayerGunGameWeaponIndex() > 0 )
  150. m_bGGHasLeader_T = true;
  151. playerList_T.AddToTail( player );
  152. }
  153. }
  154. }
  155. m_nStaticGGLeader_CT = m_nGGLeaderEntIndex_CT;
  156. m_nStaticGGLeader_T = m_nGGLeaderEntIndex_T;
  157. playerList_CT.Sort( TeamGGSortFunction );
  158. playerList_T.Sort( TeamGGSortFunction );
  159. if ( playerList_CT.Count() > 0 && m_bGGHasLeader_CT )
  160. m_nGGLeaderEntIndex_CT = playerList_CT[0]->entindex();
  161. if ( playerList_T.Count() > 0 && m_bGGHasLeader_T )
  162. m_nGGLeaderEntIndex_T = playerList_T[0]->entindex();
  163. // send an event down so the client gets it asap
  164. if ( m_nLastGGLeader_CT != m_nGGLeaderEntIndex_CT || m_nLastGGLeader_T != m_nGGLeaderEntIndex_T )
  165. {
  166. int nLeaderIndex = m_nGGLeaderEntIndex_CT;
  167. if ( m_nLastGGLeader_T != m_nGGLeaderEntIndex_T )
  168. nLeaderIndex = m_nGGLeaderEntIndex_T;
  169. for ( int i = 1; i <= iNumPlayers; i++ )
  170. {
  171. CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) );
  172. if ( pPlayer && pPlayer->entindex() == nLeaderIndex )
  173. {
  174. //if we made it this far, we are the current leader
  175. IGameEvent *event = gameeventmanager->CreateEvent( "gg_team_leader" );
  176. if ( event )
  177. {
  178. event->SetInt( "playerid", pPlayer->GetUserID() );
  179. gameeventmanager->FireEvent( event );
  180. }
  181. break;
  182. }
  183. }
  184. }
  185. m_nLastGGLeader_CT = m_nGGLeaderEntIndex_CT;
  186. m_nLastGGLeader_T = m_nGGLeaderEntIndex_T;
  187. }
  188. int CTeam::GetGGLeader( int nTeam )
  189. {
  190. if ( nTeam == TEAM_CT )
  191. return m_nGGLeaderEntIndex_CT;
  192. else if ( nTeam == TEAM_TERRORIST )
  193. return m_nGGLeaderEntIndex_T;
  194. return -1;
  195. }
  196. //-----------------------------------------------------------------------------
  197. // Purpose: Used for sorting players in valve containers
  198. //-----------------------------------------------------------------------------
  199. int CTeam::TeamGGSortFunction( CCSPlayer* const *entry1, CCSPlayer* const *entry2 )
  200. {
  201. // bail out early if either player is an empty slot, i.e. has a player index of -1
  202. if ( entry1 == NULL )
  203. return 1;
  204. if ( entry2 == NULL )
  205. return -1;
  206. if ( (*entry1)->entindex() == -1 )
  207. return 1;
  208. if ( (*entry2)->entindex() == -1 )
  209. return -1;
  210. // Higher GG Progressive weapon ranks higher. In case of ties for that, we rank according to player index so
  211. // we don't overly shuffle the ordering
  212. if ( (*entry1)->GetPlayerGunGameWeaponIndex() > (*entry2)->GetPlayerGunGameWeaponIndex() )
  213. return -1;
  214. else if ( (*entry1)->GetPlayerGunGameWeaponIndex() < (*entry2)->GetPlayerGunGameWeaponIndex() )
  215. return 1;
  216. else
  217. {
  218. int nLeader = m_nStaticGGLeader_CT;
  219. if ( (*entry1)->GetTeamNumber() == TEAM_TERRORIST )
  220. nLeader = m_nStaticGGLeader_T;
  221. // Current GG leader always sorts in front in the case of a tie
  222. if ( (*entry1)->entindex() == nLeader )
  223. return -1;
  224. else if ( (*entry2)->entindex() == nLeader )
  225. return 1;
  226. //else
  227. // return entry1->entindex() - entry2->entindex();
  228. }
  229. return 0;
  230. }
  231. //-----------------------------------------------------------------------------
  232. // Purpose: Teams are always transmitted to clients
  233. //-----------------------------------------------------------------------------
  234. int CTeam::UpdateTransmitState()
  235. {
  236. return SetTransmitState( FL_EDICT_ALWAYS );
  237. }
  238. //-----------------------------------------------------------------------------
  239. // Visibility/scanners
  240. //-----------------------------------------------------------------------------
  241. int CTeam::ShouldTransmitToPlayer( CBasePlayer* pRecipient, CBaseEntity* pEntity )
  242. {
  243. // Always transmit the observer target to players and to spectators
  244. if ( pRecipient && (pRecipient->IsObserver() && pRecipient->GetObserverTarget() == pEntity) )
  245. return FL_EDICT_ALWAYS;
  246. // Spec that isn't a coach
  247. if ( pRecipient->IsSpectator() )
  248. return FL_EDICT_ALWAYS;
  249. // Same team
  250. if ( pRecipient->GetAssociatedTeamNumber() == pEntity->GetTeamNumber() )
  251. return FL_EDICT_ALWAYS;
  252. // radar_show is 'all' or set to the target's team.
  253. if ( mp_radar_showall.GetInt() &&
  254. (
  255. ( mp_radar_showall.GetInt() == 1 ) ||
  256. ( mp_radar_showall.GetInt() == pRecipient->GetTeamNumber() )
  257. ) )
  258. return FL_EDICT_ALWAYS;
  259. return FL_EDICT_PVSCHECK;
  260. }
  261. //-----------------------------------------------------------------------------
  262. // Initialization
  263. //-----------------------------------------------------------------------------
  264. void CTeam::Init( const char *pName, int iNumber )
  265. {
  266. InitializeSpawnpoints();
  267. InitializePlayers();
  268. ResetTeamLeaders();
  269. m_bSurrendered = 0;
  270. m_scoreTotal = 0;
  271. m_scoreFirstHalf = 0;
  272. m_scoreSecondHalf = 0;
  273. m_scoreOvertime = 0;
  274. Q_strncpy( m_szTeamname.GetForModify(), pName, MAX_TEAM_NAME_LENGTH );
  275. m_iTeamNum = iNumber;
  276. }
  277. //-----------------------------------------------------------------------------
  278. // DATA HANDLING
  279. //-----------------------------------------------------------------------------
  280. int CTeam::GetTeamNumber( void ) const
  281. {
  282. return m_iTeamNum;
  283. }
  284. //-----------------------------------------------------------------------------
  285. // Purpose: Set the team's name
  286. //-----------------------------------------------------------------------------
  287. void CTeam::SetName( const char *pName )
  288. {
  289. Q_strncpy( m_szTeamname.GetForModify(), pName, MAX_TEAM_NAME_LENGTH );
  290. }
  291. //-----------------------------------------------------------------------------
  292. // Purpose: Get the team's name
  293. //-----------------------------------------------------------------------------
  294. const char *CTeam::GetName( void )
  295. {
  296. return m_szTeamname;
  297. }
  298. //-----------------------------------------------------------------------------
  299. // Purpose: Set the team's name
  300. //-----------------------------------------------------------------------------
  301. void CTeam::SetClanName( const char *pName )
  302. {
  303. Q_strncpy( m_szClanTeamname.GetForModify(), pName, MAX_TEAM_NAME_LENGTH );
  304. }
  305. //-----------------------------------------------------------------------------
  306. // Purpose: Get the team's name
  307. //-----------------------------------------------------------------------------
  308. const char *CTeam::GetClanName( void )
  309. {
  310. return m_szClanTeamname;
  311. }
  312. void CTeam::SetClanID( uint32 iClanID )
  313. {
  314. m_iClanID = iClanID;
  315. }
  316. uint32 CTeam::GetClanID( void )
  317. {
  318. return m_iClanID;
  319. }
  320. //-----------------------------------------------------------------------------
  321. // Purpose: Set the team's name
  322. //-----------------------------------------------------------------------------
  323. void CTeam::SetFlagImageString( const char *pName )
  324. {
  325. Q_strncpy( m_szTeamFlagImage.GetForModify(), pName, MAX_TEAM_FLAG_ICON_LENGTH );
  326. }
  327. //-----------------------------------------------------------------------------
  328. // Purpose: Get the team's name
  329. //-----------------------------------------------------------------------------
  330. const char *CTeam::GetFlagImageString( void )
  331. {
  332. return m_szTeamFlagImage;
  333. }
  334. //-----------------------------------------------------------------------------
  335. // Purpose: Set the team's name
  336. //-----------------------------------------------------------------------------
  337. void CTeam::SetLogoImageString( const char *pName )
  338. {
  339. Q_strncpy( m_szTeamLogoImage.GetForModify(), pName, MAX_TEAM_FLAG_ICON_LENGTH );
  340. }
  341. void CTeam::SetNumMapVictories( int numMapVictories )
  342. {
  343. if ( numMapVictories != m_numMapVictories )
  344. {
  345. m_numMapVictories = numMapVictories;
  346. }
  347. }
  348. //-----------------------------------------------------------------------------
  349. // Purpose: Get the team's name
  350. //-----------------------------------------------------------------------------
  351. const char *CTeam::GetLogoImageString( void )
  352. {
  353. return m_szTeamLogoImage;
  354. }
  355. //-----------------------------------------------------------------------------
  356. // Purpose: Update the player's client data
  357. //-----------------------------------------------------------------------------
  358. void CTeam::UpdateClientData( CBasePlayer *pPlayer )
  359. {
  360. }
  361. //------------------------------------------------------------------------------------------------------------------
  362. // SPAWNPOINTS
  363. //-----------------------------------------------------------------------------
  364. // Purpose:
  365. //-----------------------------------------------------------------------------
  366. void CTeam::InitializeSpawnpoints( void )
  367. {
  368. m_iLastSpawn = 0;
  369. }
  370. //-----------------------------------------------------------------------------
  371. // Purpose:
  372. //-----------------------------------------------------------------------------
  373. void CTeam::AddSpawnpoint( CTeamSpawnPoint *pSpawnpoint )
  374. {
  375. m_aSpawnPoints.AddToTail( pSpawnpoint );
  376. }
  377. //-----------------------------------------------------------------------------
  378. // Purpose:
  379. //-----------------------------------------------------------------------------
  380. void CTeam::RemoveSpawnpoint( CTeamSpawnPoint *pSpawnpoint )
  381. {
  382. for (int i = 0; i < m_aSpawnPoints.Count(); i++ )
  383. {
  384. if ( m_aSpawnPoints[i] == pSpawnpoint )
  385. {
  386. m_aSpawnPoints.Remove( i );
  387. return;
  388. }
  389. }
  390. }
  391. //-----------------------------------------------------------------------------
  392. // Purpose: Spawn the player at one of this team's spawnpoints. Return true if successful.
  393. //-----------------------------------------------------------------------------
  394. CBaseEntity *CTeam::SpawnPlayer( CBasePlayer *pPlayer )
  395. {
  396. if ( m_aSpawnPoints.Count() == 0 )
  397. return NULL;
  398. // Randomize the start spot
  399. int iSpawn = m_iLastSpawn + random->RandomInt( 1,3 );
  400. if ( iSpawn >= m_aSpawnPoints.Count() )
  401. iSpawn -= m_aSpawnPoints.Count();
  402. int iStartingSpawn = iSpawn;
  403. // Now loop through the spawnpoints and pick one
  404. int loopCount = 0;
  405. do
  406. {
  407. if ( iSpawn >= m_aSpawnPoints.Count() )
  408. {
  409. ++loopCount;
  410. iSpawn = 0;
  411. }
  412. // check if pSpot is valid, and that the player is on the right team
  413. if ( (loopCount > 3) || m_aSpawnPoints[iSpawn]->IsValid( pPlayer ) )
  414. {
  415. // DevMsg( 1, "player: spawning at (%s)\n", STRING(m_aSpawnPoints[iSpawn]->m_iName) );
  416. m_aSpawnPoints[iSpawn]->m_OnPlayerSpawn.FireOutput( pPlayer, m_aSpawnPoints[iSpawn] );
  417. m_iLastSpawn = iSpawn;
  418. return m_aSpawnPoints[iSpawn];
  419. }
  420. iSpawn++;
  421. } while ( iSpawn != iStartingSpawn ); // loop if we're not back to the start
  422. return NULL;
  423. }
  424. //------------------------------------------------------------------------------------------------------------------
  425. // PLAYERS
  426. //-----------------------------------------------------------------------------
  427. // Purpose:
  428. //-----------------------------------------------------------------------------
  429. void CTeam::InitializePlayers( void )
  430. {
  431. }
  432. //-----------------------------------------------------------------------------
  433. // Purpose: Add the specified player to this team. Remove them from their current team, if any.
  434. //-----------------------------------------------------------------------------
  435. void CTeam::AddPlayer( CBasePlayer *pPlayer )
  436. {
  437. m_aPlayers.AddToTail( pPlayer );
  438. NetworkStateChanged();
  439. }
  440. //-----------------------------------------------------------------------------
  441. // Purpose: Remove this player from the team
  442. //-----------------------------------------------------------------------------
  443. void CTeam::RemovePlayer( CBasePlayer *pPlayer )
  444. {
  445. m_aPlayers.FindAndRemove( pPlayer );
  446. NetworkStateChanged();
  447. }
  448. //-----------------------------------------------------------------------------
  449. // Purpose: Return the number of players in this team.
  450. //-----------------------------------------------------------------------------
  451. int CTeam::GetNumPlayers( void )
  452. {
  453. return m_aPlayers.Count();
  454. }
  455. //-----------------------------------------------------------------------------
  456. // Purpose: Get a specific player
  457. //-----------------------------------------------------------------------------
  458. CBasePlayer *CTeam::GetPlayer( int iIndex )
  459. {
  460. Assert( iIndex >= 0 && iIndex < m_aPlayers.Count() );
  461. return m_aPlayers[ iIndex ];
  462. }
  463. //------------------------------------------------------------------------------------------------------------------
  464. // SCORING
  465. //-----------------------------------------------------------------------------
  466. //-----------------------------------------------------------------------------
  467. // Purpose:
  468. //-----------------------------------------------------------------------------
  469. void CTeam::ResetScores( void )
  470. {
  471. m_bSurrendered = 0;
  472. m_scoreTotal = 0;
  473. m_scoreFirstHalf = 0;
  474. m_scoreSecondHalf = 0;
  475. m_scoreOvertime = 0;
  476. }
  477. //-----------------------------------------------------------------------------
  478. // Purpose:
  479. //-----------------------------------------------------------------------------
  480. void CTeam::AwardAchievement( int iAchievement )
  481. {
  482. Assert( iAchievement >= 0 && iAchievement < 255 ); // must fit in short
  483. CRecipientFilter filter;
  484. int iNumPlayers = GetNumPlayers();
  485. for ( int i=0;i<iNumPlayers;i++ )
  486. {
  487. if ( GetPlayer(i) )
  488. {
  489. filter.AddRecipient( GetPlayer(i) );
  490. }
  491. }
  492. CCSUsrMsg_AchievementEvent msg;
  493. msg.set_achievement( iAchievement );
  494. SendUserMessage( filter, CS_UM_AchievementEvent, msg );
  495. }
  496. int CTeam::GetAliveMembers( void )
  497. {
  498. int iAlive = 0;
  499. int iNumPlayers = GetNumPlayers();
  500. for ( int i=0;i<iNumPlayers;i++ )
  501. {
  502. if ( GetPlayer(i) && GetPlayer(i)->IsAlive() )
  503. {
  504. iAlive++;
  505. }
  506. }
  507. return iAlive;
  508. }
  509. #if defined ( CSTRIKE15 )
  510. int CTeam::GetBotMembers( CUtlVector< CCSBot* > *pOutVecBots /*= NULL*/ )
  511. {
  512. int iBots = 0;
  513. for ( int i = 0; i < GetNumPlayers(); i++ )
  514. {
  515. if ( GetPlayer( i ) && GetPlayer( i )->IsBot() )
  516. {
  517. if ( pOutVecBots )
  518. {
  519. CCSBot* pBot = dynamic_cast< CCSBot* > ( GetPlayer( i ) );
  520. if ( pBot )
  521. {
  522. pOutVecBots->AddToTail( pBot );
  523. }
  524. }
  525. iBots++;
  526. }
  527. }
  528. return iBots;
  529. }
  530. int CTeam::GetHumanMembers( CUtlVector< class CCSPlayer* > *pOutVecPlayers /*= NULL */ )
  531. {
  532. int iPlayers = 0;
  533. for ( int i = 0; i < GetNumPlayers(); i++ )
  534. {
  535. if ( GetPlayer( i ) && !GetPlayer( i )->IsBot() )
  536. {
  537. if ( pOutVecPlayers )
  538. {
  539. CCSPlayer* pPlayer = dynamic_cast< CCSPlayer * > ( GetPlayer( i ) );
  540. if ( pPlayer )
  541. {
  542. pOutVecPlayers->AddToTail( pPlayer );
  543. }
  544. }
  545. iPlayers++;
  546. }
  547. }
  548. return iPlayers;
  549. }
  550. #endif