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.

481 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. //=============================================================================
  4. #include "cbase.h"
  5. #include "tf_team.h"
  6. #include "entitylist.h"
  7. #include "util.h"
  8. #include "tf_obj.h"
  9. #include "tf_gamerules.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. //-----------------------------------------------------------------------------
  13. // Purpose: SendProxy that converts the UtlVector list of objects to entindexes, where it's reassembled on the client
  14. //-----------------------------------------------------------------------------
  15. void SendProxy_TeamObjectList( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
  16. {
  17. CTFTeam *pTeam = (CTFTeam*)pStruct;
  18. Assert( iElement < pTeam->GetNumObjects() );
  19. CBaseObject *pObject = pTeam->GetObject(iElement);
  20. EHANDLE hObject;
  21. hObject = pObject;
  22. SendProxy_EHandleToInt( pProp, pStruct, &hObject, pOut, iElement, objectID );
  23. }
  24. int SendProxyArrayLength_TeamObjects( const void *pStruct, int objectID )
  25. {
  26. CTFTeam *pTeam = (CTFTeam*)pStruct;
  27. int iObjects = pTeam->GetNumObjects();
  28. return iObjects;
  29. }
  30. //=============================================================================
  31. //
  32. // TF Team tables.
  33. //
  34. IMPLEMENT_SERVERCLASS_ST( CTFTeam, DT_TFTeam )
  35. SendPropInt( SENDINFO( m_nFlagCaptures ), 8 ),
  36. SendPropInt( SENDINFO( m_iRole ), 4, SPROP_UNSIGNED ),
  37. SendPropArray2(
  38. SendProxyArrayLength_TeamObjects,
  39. SendPropInt( "team_object_array_element", 0, SIZEOF_IGNORE, NUM_NETWORKED_EHANDLE_BITS, SPROP_UNSIGNED, SendProxy_TeamObjectList ),
  40. MAX_PLAYERS * MAX_OBJECTS_PER_PLAYER,
  41. 0,
  42. "team_object_array"
  43. ),
  44. SendPropEHandle( SENDINFO( m_hLeader ) ),
  45. END_SEND_TABLE()
  46. LINK_ENTITY_TO_CLASS( tf_team, CTFTeam );
  47. //=============================================================================
  48. //
  49. // TF Team Manager Functions.
  50. //
  51. CTFTeamManager s_TFTeamManager;
  52. CTFTeamManager *TFTeamMgr()
  53. {
  54. return &s_TFTeamManager;
  55. }
  56. //-----------------------------------------------------------------------------
  57. // Purpose:
  58. //-----------------------------------------------------------------------------
  59. CTFTeamManager::CTFTeamManager()
  60. {
  61. m_UndefinedTeamColor.r = 255;
  62. m_UndefinedTeamColor.g = 255;
  63. m_UndefinedTeamColor.b = 255;
  64. m_UndefinedTeamColor.a = 0;
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Purpose:
  68. //-----------------------------------------------------------------------------
  69. bool CTFTeamManager::Init( void )
  70. {
  71. // Clear the list.
  72. Shutdown();
  73. // Create the team list.
  74. for ( int iTeam = 0; iTeam < TF_TEAM_COUNT; ++iTeam )
  75. {
  76. COMPILE_TIME_ASSERT( TF_TEAM_COUNT == ARRAYSIZE( g_aTeamNames ) );
  77. COMPILE_TIME_ASSERT( TF_TEAM_COUNT == ARRAYSIZE( g_aTeamColors ) );
  78. int index = Create( g_aTeamNames[iTeam], g_aTeamColors[iTeam] );
  79. Assert( index == iTeam );
  80. if ( index != iTeam )
  81. return false;
  82. }
  83. return true;
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Purpose:
  87. //-----------------------------------------------------------------------------
  88. void CTFTeamManager::Shutdown( void )
  89. {
  90. // Note, don't delete each team since they are in the gEntList and will
  91. // automatically be deleted from there, instead.
  92. g_Teams.Purge();
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Purpose:
  96. //-----------------------------------------------------------------------------
  97. int CTFTeamManager::Create( const char *pName, color32 color )
  98. {
  99. CTeam *pTeam = static_cast<CTeam*>( CreateEntityByName( "tf_team" ) );
  100. if ( pTeam )
  101. {
  102. // Add the team to the global list of teams.
  103. int iTeam = g_Teams.AddToTail( pTeam );
  104. // Initialize the team.
  105. pTeam->Init( pName, iTeam );
  106. pTeam->NetworkProp()->SetUpdateInterval( 0.75f );
  107. // Set the team color.
  108. CTFTeam *pTFTeam = static_cast<CTFTeam*>( pTeam );
  109. pTFTeam->SetColor( color );
  110. return iTeam;
  111. }
  112. // Error.
  113. return -1;
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Purpose:
  117. //-----------------------------------------------------------------------------
  118. int CTFTeamManager::GetFlagCaptures( int iTeam )
  119. {
  120. if ( !IsValidTeam( iTeam ) )
  121. return -1;
  122. CTFTeam *pTeam = GetGlobalTFTeam( iTeam );
  123. if ( !pTeam )
  124. return -1;
  125. return pTeam->GetFlagCaptures();
  126. }
  127. //-----------------------------------------------------------------------------
  128. // Purpose:
  129. //-----------------------------------------------------------------------------
  130. void CTFTeamManager::IncrementFlagCaptures( int iTeam )
  131. {
  132. if ( !IsValidTeam( iTeam ) )
  133. return;
  134. CTFTeam *pTeam = GetGlobalTFTeam( iTeam );
  135. if ( !pTeam )
  136. return;
  137. pTeam->IncrementFlagCaptures();
  138. }
  139. //-----------------------------------------------------------------------------
  140. // Purpose:
  141. //-----------------------------------------------------------------------------
  142. void CTFTeamManager::AddTeamScore( int iTeam, int iScoreToAdd )
  143. {
  144. if ( !IsValidTeam( iTeam ) )
  145. return;
  146. CTeam *pTeam = GetGlobalTeam( iTeam );
  147. if ( !pTeam )
  148. return;
  149. pTeam->AddScore( iScoreToAdd );
  150. }
  151. //-----------------------------------------------------------------------------
  152. // Purpose:
  153. //-----------------------------------------------------------------------------
  154. bool CTFTeamManager::IsValidTeam( int iTeam )
  155. {
  156. if ( ( iTeam >= 0 ) && ( iTeam < g_Teams.Count() ) )
  157. return true;
  158. return false;
  159. }
  160. //-----------------------------------------------------------------------------
  161. // Purpose:
  162. //-----------------------------------------------------------------------------
  163. int CTFTeamManager::GetTeamCount( void )
  164. {
  165. return g_Teams.Count();
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Purpose:
  169. //-----------------------------------------------------------------------------
  170. CTFTeam *CTFTeamManager::GetTeam( int iTeam )
  171. {
  172. Assert( ( iTeam >= 0 ) && ( iTeam < g_Teams.Count() ) );
  173. if ( IsValidTeam( iTeam ) )
  174. {
  175. return static_cast<CTFTeam*>( g_Teams[iTeam] );
  176. }
  177. return NULL;
  178. }
  179. //-----------------------------------------------------------------------------
  180. // Purpose:
  181. //-----------------------------------------------------------------------------
  182. CTFTeam *CTFTeamManager::GetSpectatorTeam()
  183. {
  184. return GetTeam( 0 );
  185. }
  186. //-----------------------------------------------------------------------------
  187. // Purpose:
  188. //-----------------------------------------------------------------------------
  189. color32 CTFTeamManager::GetUndefinedTeamColor( void )
  190. {
  191. return m_UndefinedTeamColor;
  192. }
  193. //-----------------------------------------------------------------------------
  194. // Purpose: Sends a message to the center of the player's screen.
  195. //-----------------------------------------------------------------------------
  196. void CTFTeamManager::PlayerCenterPrint( CBasePlayer *pPlayer, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 )
  197. {
  198. ClientPrint( pPlayer, HUD_PRINTCENTER, msg_name, param1, param2, param3, param4 );
  199. }
  200. //-----------------------------------------------------------------------------
  201. // Purpose: Sends a message to the center of the given teams screen.
  202. //-----------------------------------------------------------------------------
  203. void CTFTeamManager::TeamCenterPrint( int iTeam, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 )
  204. {
  205. CTeamRecipientFilter filter( iTeam, true );
  206. UTIL_ClientPrintFilter( filter, HUD_PRINTCENTER, msg_name, param1, param2, param3, param4 );
  207. }
  208. //-----------------------------------------------------------------------------
  209. // Purpose: Sends a message to the center of the player's teams screen (minus
  210. // the player).
  211. //-----------------------------------------------------------------------------
  212. void CTFTeamManager::PlayerTeamCenterPrint( CBasePlayer *pPlayer, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 )
  213. {
  214. CTeamRecipientFilter filter( pPlayer->GetTeamNumber(), true );
  215. filter.RemoveRecipient( pPlayer );
  216. UTIL_ClientPrintFilter( filter, HUD_PRINTCENTER, msg_name, param1, param2, param3, param4 );
  217. }
  218. //=============================================================================
  219. //
  220. // TF Team Functions.
  221. //
  222. //-----------------------------------------------------------------------------
  223. // Purpose: Constructor.
  224. //-----------------------------------------------------------------------------
  225. CTFTeam::CTFTeam()
  226. {
  227. m_TeamColor.r = 0;
  228. m_TeamColor.g = 0;
  229. m_TeamColor.b = 0;
  230. m_TeamColor.a = 0;
  231. m_nFlagCaptures = 0;
  232. m_nTotalFlagCaptures = 0;
  233. m_flTotalSecondsKOTHPointOwned = 0.f;
  234. m_flTotalPLRTrackPercentTraveled = 0.f;
  235. m_hLeader = NULL;
  236. }
  237. //-----------------------------------------------------------------------------
  238. // Purpose:
  239. //-----------------------------------------------------------------------------
  240. void CTFTeam::SetColor( color32 color )
  241. {
  242. m_TeamColor = color;
  243. }
  244. //-----------------------------------------------------------------------------
  245. // Purpose:
  246. //-----------------------------------------------------------------------------
  247. color32 CTFTeam::GetColor( void )
  248. {
  249. return m_TeamColor;
  250. }
  251. //-----------------------------------------------------------------------------
  252. // Purpose:
  253. // Input: pPlayer - print to just that client, NULL = all clients
  254. //-----------------------------------------------------------------------------
  255. void CTFTeam::ShowScore( CBasePlayer *pPlayer )
  256. {
  257. if ( pPlayer )
  258. {
  259. ClientPrint( pPlayer, HUD_PRINTNOTIFY, UTIL_VarArgs( "Team %s: %d\n", GetName(), GetScore() ) );
  260. }
  261. else
  262. {
  263. UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs( "Team %s: %d\n", GetName(), GetScore() ) );
  264. }
  265. }
  266. //-----------------------------------------------------------------------------
  267. // OBJECTS
  268. //-----------------------------------------------------------------------------
  269. //-----------------------------------------------------------------------------
  270. // Purpose: Add the specified object to this team.
  271. //-----------------------------------------------------------------------------
  272. void CTFTeam::AddObject( CBaseObject *pObject )
  273. {
  274. TRACE_OBJECT( UTIL_VarArgs( "%0.2f CTFTeam::AddObject adding object %p:%s to team %s\n", gpGlobals->curtime,
  275. pObject, pObject->GetClassname(), GetName() ) );
  276. bool alreadyInList = IsObjectOnTeam( pObject );
  277. Assert( !alreadyInList );
  278. if ( !alreadyInList )
  279. {
  280. m_aObjects.AddToTail( pObject );
  281. }
  282. NetworkStateChanged();
  283. }
  284. //-----------------------------------------------------------------------------
  285. // Returns true if the object is in the team's list of objects
  286. //-----------------------------------------------------------------------------
  287. bool CTFTeam::IsObjectOnTeam( CBaseObject *pObject ) const
  288. {
  289. return ( m_aObjects.Find( pObject ) != -1 );
  290. }
  291. //-----------------------------------------------------------------------------
  292. // Purpose: Remove this object from the team
  293. // Removes all references from all sublists as well
  294. //-----------------------------------------------------------------------------
  295. void CTFTeam::RemoveObject( CBaseObject *pObject )
  296. {
  297. if ( m_aObjects.Count() <= 0 )
  298. return;
  299. if ( m_aObjects.Find( pObject ) != -1 )
  300. {
  301. TRACE_OBJECT( UTIL_VarArgs( "%0.2f CTFTeam::RemoveObject removing %p:%s from %s\n", gpGlobals->curtime,
  302. pObject, pObject->GetClassname(), GetName() ) );
  303. m_aObjects.FindAndRemove( pObject );
  304. }
  305. else
  306. {
  307. TRACE_OBJECT( UTIL_VarArgs( "%0.2f CTFTeam::RemoveObject couldn't remove %p:%s from %s\n", gpGlobals->curtime,
  308. pObject, pObject->GetClassname(), GetName() ) );
  309. }
  310. NetworkStateChanged();
  311. }
  312. //-----------------------------------------------------------------------------
  313. // Purpose:
  314. //-----------------------------------------------------------------------------
  315. int CTFTeam::GetNumObjects( int iObjectType )
  316. {
  317. // Asking for a count of a specific object type?
  318. if ( iObjectType > 0 )
  319. {
  320. int iCount = 0;
  321. for ( int i = 0; i < GetNumObjects(); i++ )
  322. {
  323. CBaseObject *pObject = GetObject(i);
  324. if ( pObject && pObject->GetType() == iObjectType )
  325. {
  326. iCount++;
  327. }
  328. }
  329. return iCount;
  330. }
  331. return m_aObjects.Count();
  332. }
  333. //-----------------------------------------------------------------------------
  334. // Purpose:
  335. //-----------------------------------------------------------------------------
  336. CBaseObject *CTFTeam::GetObject( int num )
  337. {
  338. Assert( num >= 0 && num < m_aObjects.Count() );
  339. return m_aObjects[ num ];
  340. }
  341. //-----------------------------------------------------------------------------
  342. // Purpose: Get a pointer to the specified TF team
  343. //-----------------------------------------------------------------------------
  344. CTFTeam *GetGlobalTFTeam( int iIndex )
  345. {
  346. if ( iIndex < 0 || iIndex >= GetNumberOfTeams() )
  347. return NULL;
  348. return ( dynamic_cast< CTFTeam* >( g_Teams[iIndex] ) );
  349. }
  350. //-----------------------------------------------------------------------------
  351. // Set the team leader
  352. //-----------------------------------------------------------------------------
  353. bool CTFTeam::SetTeamLeader( CBasePlayer *pPlayer )
  354. {
  355. Assert ( pPlayer );
  356. // player must be on this team
  357. if ( m_aPlayers.Find(pPlayer) == m_aPlayers.InvalidIndex() )
  358. {
  359. Assert( !"can't set a player as leader of a team he's not on" );
  360. return false;
  361. }
  362. m_hLeader = pPlayer;
  363. return true;
  364. }
  365. //-----------------------------------------------------------------------------
  366. // Purpose: Get Leader
  367. //-----------------------------------------------------------------------------
  368. CBasePlayer *CTFTeam::GetTeamLeader( void )
  369. {
  370. return m_hLeader.Get();
  371. }
  372. //-----------------------------------------------------------------------------
  373. // Purpose: Add the specified player to this team. Remove them from their current team, if any.
  374. //-----------------------------------------------------------------------------
  375. void CTFTeam::AddPlayer( CBasePlayer *pPlayer )
  376. {
  377. BaseClass::AddPlayer( pPlayer );
  378. if ( GetTeamLeader() == NULL )
  379. {
  380. SetTeamLeader( pPlayer );
  381. }
  382. TFGameRules()->TeamPlayerCountChanged( this );
  383. }
  384. //-----------------------------------------------------------------------------
  385. // Purpose: Remove this player from the team
  386. //-----------------------------------------------------------------------------
  387. void CTFTeam::RemovePlayer( CBasePlayer *pPlayer )
  388. {
  389. BaseClass::RemovePlayer( pPlayer );
  390. if ( pPlayer == m_hLeader.Get() )
  391. {
  392. m_hLeader = NULL;
  393. if ( m_aPlayers.Count() > 0 )
  394. {
  395. // pick a new leader randomly
  396. int iLeader = random->RandomInt( 0, m_aPlayers.Count()-1 );
  397. SetTeamLeader( m_aPlayers.Element(iLeader) );
  398. }
  399. }
  400. TFGameRules()->TeamPlayerCountChanged( this );
  401. }