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.

717 lines
24 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: CS's custom CPlayerResource
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "cs_player.h"
  9. #include "cs_simple_hostage.h"
  10. #include "cs_player_resource.h"
  11. #include "econ_game_account_client.h"
  12. #include "weapon_c4.h"
  13. #include <coordsize.h>
  14. #include "cs_bot_manager.h"
  15. #include "cs_gamerules.h"
  16. #include "cs_bot.h"
  17. #include "cs_team.h"
  18. extern bool g_fGameOver;
  19. // Datatable
  20. IMPLEMENT_SERVERCLASS_ST(CCSPlayerResource, DT_CSPlayerResource)
  21. SendPropInt( SENDINFO( m_iPlayerC4 ), 8, SPROP_UNSIGNED ),
  22. SendPropInt( SENDINFO( m_iPlayerVIP ), 8, SPROP_UNSIGNED ),
  23. SendPropArray3( SENDINFO_ARRAY3(m_bHostageAlive), SendPropInt( SENDINFO_ARRAY(m_bHostageAlive), 1, SPROP_UNSIGNED ) ),
  24. SendPropArray3( SENDINFO_ARRAY3(m_isHostageFollowingSomeone), SendPropInt( SENDINFO_ARRAY(m_isHostageFollowingSomeone), 1, SPROP_UNSIGNED ) ),
  25. SendPropArray3( SENDINFO_ARRAY3(m_iHostageEntityIDs), SendPropInt( SENDINFO_ARRAY(m_iHostageEntityIDs), -1, SPROP_UNSIGNED ) ),
  26. SendPropVector( SENDINFO(m_bombsiteCenterA), -1, SPROP_COORD),
  27. SendPropVector( SENDINFO(m_bombsiteCenterB), -1, SPROP_COORD),
  28. SendPropArray3( SENDINFO_ARRAY3(m_hostageRescueX), SendPropInt( SENDINFO_ARRAY(m_hostageRescueX), COORD_INTEGER_BITS+1, 0 ) ),
  29. SendPropArray3( SENDINFO_ARRAY3(m_hostageRescueY), SendPropInt( SENDINFO_ARRAY(m_hostageRescueY), COORD_INTEGER_BITS+1, 0 ) ),
  30. SendPropArray3( SENDINFO_ARRAY3(m_hostageRescueZ), SendPropInt( SENDINFO_ARRAY(m_hostageRescueZ), COORD_INTEGER_BITS+1, 0 ) ),
  31. SendPropArray3( SENDINFO_ARRAY3(m_iMVPs), SendPropInt( SENDINFO_ARRAY(m_iMVPs), COORD_INTEGER_BITS+1, SPROP_UNSIGNED ) ),
  32. SendPropArray3( SENDINFO_ARRAY3(m_iArmor), SendPropInt( SENDINFO_ARRAY(m_iArmor), COORD_INTEGER_BITS+1, SPROP_UNSIGNED ) ),
  33. SendPropArray3( SENDINFO_ARRAY3(m_bHasDefuser), SendPropInt( SENDINFO_ARRAY(m_bHasDefuser), 1, SPROP_UNSIGNED ) ),
  34. SendPropArray3( SENDINFO_ARRAY3(m_bHasHelmet), SendPropInt( SENDINFO_ARRAY(m_bHasHelmet), 1, SPROP_UNSIGNED ) ),
  35. SendPropArray3( SENDINFO_ARRAY3(m_iScore), SendPropInt( SENDINFO_ARRAY(m_iScore), 32) ),
  36. SendPropArray3( SENDINFO_ARRAY3(m_iCompetitiveRanking), SendPropInt( SENDINFO_ARRAY(m_iCompetitiveRanking), 32) ),
  37. SendPropArray3( SENDINFO_ARRAY3(m_iCompetitiveWins), SendPropInt( SENDINFO_ARRAY(m_iCompetitiveWins), 32) ),
  38. SendPropArray3( SENDINFO_ARRAY3( m_iCompTeammateColor ), SendPropInt( SENDINFO_ARRAY( m_iCompTeammateColor ), 32 ) ),
  39. #if CS_CONTROLLABLE_BOTS_ENABLED
  40. SendPropArray3( SENDINFO_ARRAY3(m_bControllingBot), SendPropInt( SENDINFO_ARRAY(m_bControllingBot), 1, SPROP_UNSIGNED ) ),
  41. SendPropArray3( SENDINFO_ARRAY3(m_iControlledPlayer), SendPropInt( SENDINFO_ARRAY(m_iControlledPlayer), 8, SPROP_UNSIGNED ) ),
  42. SendPropArray3( SENDINFO_ARRAY3(m_iControlledByPlayer), SendPropInt( SENDINFO_ARRAY(m_iControlledByPlayer), 8, SPROP_UNSIGNED ) ),
  43. #endif
  44. SendPropArray3( SENDINFO_ARRAY3(m_iBotDifficulty), SendPropInt( SENDINFO_ARRAY(m_iBotDifficulty), 32) ),
  45. SendPropArray3( SENDINFO_ARRAY3(m_szClan), SendPropStringT( SENDINFO_ARRAY(m_szClan) ) ),
  46. SendPropArray3( SENDINFO_ARRAY3(m_iTotalCashSpent), SendPropInt( SENDINFO_ARRAY(m_iTotalCashSpent), 32) ),
  47. SendPropArray3( SENDINFO_ARRAY3(m_iCashSpentThisRound), SendPropInt( SENDINFO_ARRAY(m_iCashSpentThisRound), 32) ),
  48. SendPropArray3( SENDINFO_ARRAY3(m_nEndMatchNextMapVotes), SendPropInt( SENDINFO_ARRAY(m_nEndMatchNextMapVotes), 32) ),
  49. SendPropBool( SENDINFO( m_bEndMatchNextMapAllVoted ) ),
  50. SendPropArray3( SENDINFO_ARRAY3(m_nActiveCoinRank), SendPropInt( SENDINFO_ARRAY(m_nActiveCoinRank), 32) ),
  51. SendPropArray3( SENDINFO_ARRAY3(m_nMusicID), SendPropInt( SENDINFO_ARRAY(m_nMusicID), 32) ),
  52. // SendPropArray3( SENDINFO_ARRAY3(m_bIsAssassinationTarget), SendPropBool( SENDINFO_ARRAY(m_bIsAssassinationTarget), 32) ),
  53. SendPropArray3( SENDINFO_ARRAY3(m_nPersonaDataPublicLevel), SendPropInt( SENDINFO_ARRAY(m_nPersonaDataPublicLevel), 32) ),
  54. SendPropArray3( SENDINFO_ARRAY3(m_nPersonaDataPublicCommendsLeader), SendPropInt( SENDINFO_ARRAY(m_nPersonaDataPublicCommendsLeader), 32) ),
  55. SendPropArray3( SENDINFO_ARRAY3(m_nPersonaDataPublicCommendsTeacher), SendPropInt( SENDINFO_ARRAY(m_nPersonaDataPublicCommendsTeacher), 32) ),
  56. SendPropArray3( SENDINFO_ARRAY3(m_nPersonaDataPublicCommendsFriendly), SendPropInt( SENDINFO_ARRAY(m_nPersonaDataPublicCommendsFriendly), 32) ),
  57. END_SEND_TABLE()
  58. BEGIN_DATADESC( CCSPlayerResource )
  59. // DEFINE_ARRAY( m_iPing, FIELD_INTEGER, MAX_PLAYERS+1 ),
  60. // DEFINE_ARRAY( m_iPacketloss, FIELD_INTEGER, MAX_PLAYERS+1 ),
  61. END_DATADESC()
  62. LINK_ENTITY_TO_CLASS( cs_player_manager, CCSPlayerResource );
  63. CCSPlayerResource::CCSPlayerResource( void )
  64. {
  65. m_bEndMatchNextMapAllVoted = false;
  66. m_bPreferencesAssigned_T = false;
  67. m_bPreferencesAssigned_CT = false;
  68. memset( m_nAttemptedToGetColor, false, sizeof( m_nAttemptedToGetColor ) );
  69. }
  70. //-----------------------------------------------------------------------------
  71. // Purpose:
  72. //-----------------------------------------------------------------------------
  73. void CCSPlayerResource::UpdatePlayerData( void )
  74. {
  75. int i;
  76. m_iPlayerC4 = 0;
  77. m_iPlayerVIP = 0;
  78. int nTotalPlayingPlayers = 0;
  79. for ( i = 1; i <= gpGlobals->maxClients; i++ )
  80. {
  81. int botDifficulty = -1;
  82. CCSPlayer *pPlayer = (CCSPlayer*)UTIL_PlayerByIndex( i );
  83. bool bSetValidRanking = false;
  84. if ( pPlayer && pPlayer->IsConnected() )
  85. {
  86. if ( pPlayer->IsVIP() )
  87. {
  88. // we should only have one VIP
  89. Assert( m_iPlayerVIP == 0 );
  90. m_iPlayerVIP = i;
  91. }
  92. if ( pPlayer->HasC4() )
  93. {
  94. // we should only have one bomb
  95. m_iPlayerC4 = i;
  96. }
  97. m_iMVPs.Set( i, pPlayer->GetNumMVPs() );
  98. m_bHasDefuser.Set( i, pPlayer->HasDefuser() );
  99. m_bHasHelmet.Set( i, pPlayer->m_bHasHelmet );
  100. m_iArmor.Set( i, pPlayer->ArmorValue() );
  101. m_iScore.Set( i, pPlayer->GetScore() );
  102. m_iTotalCashSpent.Set( i, pPlayer->GetTotalCashSpent() );
  103. m_iCashSpentThisRound.Set( i, pPlayer->GetCashSpentThisRound() );
  104. m_szClan.Set(i, AllocPooledString( pPlayer->GetClanTag() ) );
  105. m_nEndMatchNextMapVotes.Set( i, pPlayer->GetEndMatchNextMapVote() );
  106. m_nActiveCoinRank.Set( i, pPlayer->GetRank( MEDAL_CATEGORY_SEASON_COIN ) );
  107. m_nMusicID.Set( i, pPlayer->GetMusicID() );
  108. // UpdateAssassinationTargets();
  109. if ( CEconPersonaDataPublic const *pPublic = pPlayer->GetPersonaDataPublic() )
  110. {
  111. m_nPersonaDataPublicLevel.Set( i, pPublic->Obj().player_level() );
  112. m_nPersonaDataPublicCommendsLeader.Set( i, pPublic->Obj().commendation().cmd_leader() );
  113. m_nPersonaDataPublicCommendsTeacher.Set( i, pPublic->Obj().commendation().cmd_teaching() );
  114. m_nPersonaDataPublicCommendsFriendly.Set( i, pPublic->Obj().commendation().cmd_friendly() );
  115. }
  116. else
  117. {
  118. m_nPersonaDataPublicLevel.Set( i, -1 );
  119. m_nPersonaDataPublicCommendsLeader.Set( i, -1 );
  120. m_nPersonaDataPublicCommendsTeacher.Set( i, -1 );
  121. m_nPersonaDataPublicCommendsFriendly.Set( i, -1 );
  122. }
  123. if ( pPlayer->IsBot() )
  124. {
  125. CCSBot* pBot = dynamic_cast< CCSBot* >( pPlayer );
  126. if ( pBot )
  127. {
  128. // Retrieve and store the bot's difficulty level
  129. const BotProfile* pProfile = pBot->GetProfile();
  130. if ( pProfile )
  131. {
  132. botDifficulty = pProfile->GetMaxDifficulty();
  133. }
  134. m_iCompTeammateColor.Set( i, -2 );
  135. m_nAttemptedToGetColor[i] = true;
  136. // SetPlayerTeammateColor( i, false );
  137. }
  138. }
  139. else
  140. {
  141. if ( pPlayer->GetTeamNumber() != TEAM_SPECTATOR )
  142. nTotalPlayingPlayers++;
  143. SetPlayerTeammateColor( i, false );
  144. }
  145. if ( CSGameRules() && CSGameRules()->IsQueuedMatchmaking() )
  146. {
  147. for ( int k = 0; k < CCSGameRules::sm_QueuedServerReservation.rankings().size(); ++ k )
  148. {
  149. if ( CCSGameRules::sm_QueuedServerReservation.rankings( k ).account_id() == pPlayer->GetHumanPlayerAccountID() )
  150. {
  151. m_iCompetitiveRanking.Set( i, CCSGameRules::sm_QueuedServerReservation.rankings( k ).rank_id() );
  152. m_iCompetitiveWins.Set( i, CCSGameRules::sm_QueuedServerReservation.rankings( k ).wins() );
  153. bSetValidRanking = true;
  154. break;
  155. }
  156. }
  157. }
  158. }
  159. else
  160. {
  161. m_iMVPs.Set( i, 0 );
  162. m_bHasDefuser.Set( i, false );
  163. m_bHasHelmet.Set( i, false );
  164. m_iArmor.Set( i, 0 );
  165. m_szClan.Set( i, MAKE_STRING( "" ) );
  166. m_nEndMatchNextMapVotes.Set( i, -1 );
  167. m_nActiveCoinRank.Set( i, -1 );
  168. m_nMusicID.Set( i, -1 );
  169. m_bIsAssassinationTarget.Set( i, 0 );
  170. m_nPersonaDataPublicLevel.Set( i, -1 );
  171. m_nPersonaDataPublicCommendsLeader.Set( i, -1 );
  172. m_nPersonaDataPublicCommendsTeacher.Set( i, -1 );
  173. m_nPersonaDataPublicCommendsFriendly.Set( i, -1 );
  174. m_iCompTeammateColor.Set( i, -1 );
  175. m_nAttemptedToGetColor[i] = false;
  176. }
  177. if ( !bSetValidRanking )
  178. {
  179. m_iCompetitiveRanking.Set( i, 0 );
  180. m_iCompetitiveWins.Set( i, 0 );
  181. }
  182. m_iBotDifficulty.Set( i, botDifficulty );
  183. }
  184. if ( g_fGameOver && nTotalPlayingPlayers > 0 && CSGameRules() && CSGameRules()->IsEndMatchVotingForNextMap() )
  185. {
  186. if ( m_bEndMatchNextMapAllVoted == false )
  187. {
  188. // ignore whether all players voted and just return whether or not we ran out of time
  189. if ( CSGameRules()->m_eEndMatchMapVoteState == CSGameRules()->k_EEndMatchMapVoteState_VoteTimeEnded ||
  190. CSGameRules()->m_eEndMatchMapVoteState == CSGameRules()->k_EEndMatchMapVoteState_AllPlayersVoted ||
  191. CSGameRules()->m_eEndMatchMapVoteState == CSGameRules()->k_EEndMatchMapVoteState_SelectingWinner ||
  192. CSGameRules()->m_eEndMatchMapVoteState == CSGameRules()->k_EEndMatchMapVoteState_SettingNextLevel ||
  193. CSGameRules()->m_eEndMatchMapVoteState == CSGameRules()->k_EEndMatchMapVoteState_VoteAllDone )
  194. {
  195. m_bEndMatchNextMapAllVoted = true;
  196. }
  197. /* m_bEndMatchNextMapAllVoted = (CSGameRules()->m_eEndMatchMapVoteState == CSGameRules()->k_EEndMatchMapVoteState_VoteTimeEnded);*/
  198. // int nNumVotes = 0;
  199. // int nHighestSingleVoteSlot = 0;
  200. //
  201. // // this is done in three different places
  202. // // TODO: make a function out of this
  203. // int nVotes[MAX_ENDMATCH_VOTE_PANELS];
  204. // for ( int i = 0; i < MAX_ENDMATCH_VOTE_PANELS; i++ )
  205. // nVotes[i] = 0;
  206. //
  207. // for ( int i = 1; i <= MAX_PLAYERS; i++ )
  208. // {
  209. // int nMapSlot = m_nEndMatchNextMapVotes[i];
  210. // if ( nMapSlot != -1 && nMapSlot < MAX_ENDMATCH_VOTE_PANELS )
  211. // {
  212. // nVotes[nMapSlot] += 1;
  213. // nNumVotes += 1;
  214. // }
  215. // }
  216. // //////
  217. //
  218. // for ( int i = 0; i < MAX_ENDMATCH_VOTE_PANELS + 1; i++ )
  219. // {
  220. // if ( nVotes[nHighestSingleVoteSlot] < nVotes[i] )
  221. // nHighestSingleVoteSlot = i;
  222. // }
  223. //
  224. // if ( nTotalPlayingPlayers > 0 )
  225. // {
  226. // float flnVotesToSucceed = (float)nTotalPlayingPlayers * 0.501f;
  227. // int nVotesToSucceed = ceil( flnVotesToSucceed );
  228. //
  229. // if ( nNumVotes >= nTotalPlayingPlayers || nVotes[nHighestSingleVoteSlot] >= nVotesToSucceed || ( nextlevel.GetString() && *nextlevel.GetString() && engine->IsMapValid( nextlevel.GetString() ) ) )
  230. // m_bEndMatchNextMapAllVoted = true;
  231. // }
  232. }
  233. }
  234. else
  235. {
  236. // if we aren't at the end of the game or we don't have any players, no one has voted
  237. m_bEndMatchNextMapAllVoted = false;
  238. }
  239. int numHostages = g_Hostages.Count();
  240. for ( i = 0; i < MAX_HOSTAGES; i++ )
  241. {
  242. if ( i >= numHostages )
  243. {
  244. // engine->Con_NPrintf( i, "Dead" );
  245. m_bHostageAlive.Set( i, false );
  246. m_isHostageFollowingSomeone.Set( i, false );
  247. m_iHostageEntityIDs.Set( i, 0 );
  248. continue;
  249. }
  250. CHostage* pHostage = g_Hostages[i];
  251. m_bHostageAlive.Set( i, pHostage->IsRescuable() );
  252. if ( pHostage->IsValid() )
  253. {
  254. m_iHostageEntityIDs.Set( i, pHostage->entindex() );
  255. m_isHostageFollowingSomeone.Set( i, pHostage->IsFollowingSomeone() );
  256. // engine->Con_NPrintf( i, "ID:%d Pos:(%.0f,%.0f,%.0f)", pHostage->entindex(), pHostage->GetAbsOrigin().x, pHostage->GetAbsOrigin().y, pHostage->GetAbsOrigin().z );
  257. }
  258. else
  259. {
  260. // engine->Con_NPrintf( i, "Invalid" );
  261. }
  262. }
  263. if( !m_foundGoalPositions )
  264. {
  265. // We only need to update these once a map, but we need the client to know about them.
  266. CBaseEntity* ent = NULL;
  267. while ( ( ent = gEntList.FindEntityByClassname( ent, "func_bomb_target" ) ) != NULL )
  268. {
  269. const Vector &pos = ent->WorldSpaceCenter();
  270. CNavArea *area = TheNavMesh->GetNearestNavArea( pos, true, 10000.0f, false, false );
  271. const char *placeName = (area) ? TheNavMesh->PlaceToName( area->GetPlace() ) : NULL;
  272. if ( placeName == NULL )
  273. {
  274. // The bomb site has no area or place name, so just choose A then B
  275. if ( m_bombsiteCenterA.Get().IsZero() )
  276. {
  277. m_bombsiteCenterA = pos;
  278. }
  279. else
  280. {
  281. m_bombsiteCenterB = pos;
  282. }
  283. }
  284. else
  285. {
  286. // The bomb site has a place name, so choose accordingly
  287. if( FStrEq( placeName, "BombsiteA" ) || FStrEq( placeName, "Bombsite" ) )
  288. {
  289. m_bombsiteCenterA = pos;
  290. }
  291. else
  292. {
  293. m_bombsiteCenterB = pos;
  294. }
  295. }
  296. m_foundGoalPositions = true;
  297. }
  298. int hostageRescue = 0;
  299. while ( (( ent = gEntList.FindEntityByClassname( ent, "func_hostage_rescue" ) ) != NULL) && (hostageRescue < MAX_HOSTAGE_RESCUES) )
  300. {
  301. const Vector &pos = ent->WorldSpaceCenter();
  302. m_hostageRescueX.Set( hostageRescue, (int) pos.x );
  303. m_hostageRescueY.Set( hostageRescue, (int) pos.y );
  304. m_hostageRescueZ.Set( hostageRescue, (int) pos.z );
  305. hostageRescue++;
  306. m_foundGoalPositions = true;
  307. }
  308. }
  309. #if CS_CONTROLLABLE_BOTS_ENABLED
  310. for ( int i=0; i < MAX_PLAYERS+1; i++ )
  311. {
  312. CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) );
  313. bool bControllingBot = false;
  314. CCSPlayer *pControlledPlayer = NULL;
  315. CCSPlayer *pControlledByPlayer = NULL;
  316. if ( pPlayer && pPlayer->IsConnected() )
  317. {
  318. bControllingBot = pPlayer->IsControllingBot();
  319. pControlledPlayer = pPlayer->GetControlledBot();
  320. pControlledByPlayer = pPlayer->GetControlledByPlayer();
  321. }
  322. m_bControllingBot.Set( i, bControllingBot ? 1 : 0 );
  323. m_iControlledPlayer.Set( i, pControlledPlayer ? pControlledPlayer->entindex() : 0 );
  324. m_iControlledByPlayer.Set( i, pControlledByPlayer ? pControlledByPlayer->entindex() : 0 );
  325. }
  326. #endif
  327. BaseClass::UpdatePlayerData();
  328. }
  329. void CCSPlayerResource::Spawn( void )
  330. {
  331. m_iPlayerC4 = 0;
  332. m_iPlayerVIP = 0;
  333. m_bombsiteCenterA.Init();
  334. m_bombsiteCenterB.Init();
  335. m_foundGoalPositions = false;
  336. m_bPreferencesAssigned_CT = false;
  337. m_bPreferencesAssigned_T = false;
  338. memset( m_nAttemptedToGetColor, false, sizeof( m_nAttemptedToGetColor ) );
  339. for ( int i=0; i < MAX_HOSTAGES; i++ )
  340. {
  341. m_bHostageAlive.Set( i, 0 );
  342. m_isHostageFollowingSomeone.Set( i, 0 );
  343. m_iHostageEntityIDs.Set(i, 0);
  344. }
  345. for ( int i=0; i < MAX_HOSTAGE_RESCUES; i++ )
  346. {
  347. m_hostageRescueX.Set( i, 0 );
  348. m_hostageRescueY.Set( i, 0 );
  349. m_hostageRescueZ.Set( i, 0 );
  350. }
  351. for ( int i=0; i < MAX_PLAYERS+1; i++ )
  352. {
  353. m_iMVPs.Set( i, 0 );
  354. m_bHasDefuser.Set( i, false );
  355. m_bHasHelmet.Set( i, false );
  356. m_iArmor.Set( i, 0 );
  357. m_iScore.Set( i, 0 );
  358. m_iCompetitiveRanking.Set( i, 0 );
  359. m_iCompetitiveWins.Set( i, 0 );
  360. m_iCompTeammateColor.Set( i, -1 );
  361. m_iBotDifficulty.Set( i, -1 );
  362. m_szClan.Set( i, MAKE_STRING( "" ) );
  363. m_nActiveCoinRank.Set( i, -1 );
  364. m_nMusicID.Set( i, -1 );
  365. m_bIsAssassinationTarget.Set( i, 0 );
  366. m_nPersonaDataPublicLevel.Set( i, -1 );
  367. m_nPersonaDataPublicCommendsLeader.Set( i, -1 );
  368. m_nPersonaDataPublicCommendsTeacher.Set( i, -1 );
  369. m_nPersonaDataPublicCommendsFriendly.Set( i, -1 );
  370. }
  371. m_bEndMatchNextMapAllVoted = false;
  372. for ( int i=0; i < MAX_ENDMATCH_VOTE_PANELS+1; i++ )
  373. {
  374. m_nEndMatchNextMapVotes.Set( i, 0 );
  375. }
  376. BaseClass::Spawn();
  377. }
  378. const Vector CCSPlayerResource::GetBombsiteAPosition()
  379. {
  380. return m_bombsiteCenterA;
  381. }
  382. const Vector CCSPlayerResource::GetBombsiteBPosition()
  383. {
  384. return m_bombsiteCenterB;
  385. }
  386. const Vector CCSPlayerResource::GetHostageRescuePosition( int iIndex )
  387. {
  388. if ( iIndex < 0 || iIndex >= MAX_HOSTAGE_RESCUES )
  389. return vec3_origin;
  390. Vector ret;
  391. ret.x = m_hostageRescueX[iIndex];
  392. ret.y = m_hostageRescueY[iIndex];
  393. ret.z = m_hostageRescueZ[iIndex];
  394. return ret;
  395. }
  396. //--------------------------------------------------------------------------------------------------------
  397. int CCSPlayerResource::GetCompTeammateColor( int iIndex )
  398. {
  399. CCSPlayer *pPlayer = ( CCSPlayer* )UTIL_PlayerByIndex( iIndex );
  400. if ( !pPlayer )
  401. return -1;
  402. if ( pPlayer->IsBot() )
  403. return -2;
  404. return m_iCompTeammateColor[iIndex];
  405. }
  406. void CCSPlayerResource::ResetPlayerTeammateColor( int index )
  407. {
  408. CCSPlayer *pPlayer = ( CCSPlayer* )UTIL_PlayerByIndex( index );
  409. if ( !pPlayer )
  410. return;
  411. if ( CSGameRules() && CSGameRules()->IsPlayingAnyCompetitiveStrictRuleset() && CSGameRules()->IsQueuedMatchmaking() )
  412. return;
  413. int nTeamNum = pPlayer->GetTeamNumber();
  414. if ( nTeamNum > TEAM_SPECTATOR )
  415. {
  416. SetPlayerTeammateColor( index, true );
  417. return;
  418. }
  419. m_iCompTeammateColor.Set( index, -1 );
  420. }
  421. void CCSPlayerResource::ForcePlayersPickColors()
  422. {
  423. m_bPreferencesAssigned_CT = true;
  424. m_bPreferencesAssigned_T = true;
  425. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  426. m_nAttemptedToGetColor[i] = true;
  427. }
  428. void CCSPlayerResource::SetPlayerTeammateColor( int index, bool bReset )
  429. {
  430. CCSPlayer *pPlayer = ( CCSPlayer* )UTIL_PlayerByIndex( index );
  431. if ( !pPlayer )
  432. return;
  433. m_nAttemptedToGetColor[index] = true;
  434. if ( !CSGameRules() || !CSGameRules()->IsPlayingAnyCompetitiveStrictRuleset() )
  435. {
  436. m_iCompTeammateColor.Set( index, -1 );
  437. return;
  438. }
  439. if ( pPlayer->IsBot() )
  440. {
  441. m_iCompTeammateColor.Set( index, -2 );
  442. return;
  443. }
  444. int nTeamNum = pPlayer->GetTeamNumber();
  445. if ( nTeamNum > TEAM_SPECTATOR )
  446. {
  447. if ( CSGameRules() && CSGameRules()->IsPlayingAnyCompetitiveStrictRuleset() )
  448. {
  449. // check to see if we have a color already
  450. int idxThisPlayer = -1;
  451. // don't use the QMM code
  452. /*
  453. if ( CSGameRules()->IsQueuedMatchmaking() )
  454. {
  455. CCSPlayer *pThisPlayer = ( CCSPlayer* )UTIL_PlayerByIndex( index );
  456. CSteamID steamID;
  457. pThisPlayer->GetSteamID( &steamID );
  458. int numTotalPlayers = 0;
  459. static ConVarRef sv_mmqueue_reservation( "sv_mmqueue_reservation" );
  460. for ( char const *pszPrev = sv_mmqueue_reservation.GetString(), *pszNext = pszPrev;
  461. ( pszNext = strchr( pszPrev, '[' ) ) != NULL; pszPrev = pszNext + 1 )
  462. {
  463. uint32 uiAccountId = 0;
  464. sscanf( pszNext, "[%x]", &uiAccountId );
  465. if ( uiAccountId && ( steamID.GetAccountID() == uiAccountId ) )
  466. {
  467. idxThisPlayer = numTotalPlayers;
  468. }
  469. ++numTotalPlayers;
  470. }
  471. }
  472. */
  473. // let all players have at least one crack at getting their prefered color before we start assigning loser colors
  474. if ( (nTeamNum == TEAM_TERRORIST && m_bPreferencesAssigned_T == false) ||
  475. (nTeamNum == TEAM_CT && m_bPreferencesAssigned_CT == false) )
  476. {
  477. int nNumAttemptedToGetColor = 0;
  478. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  479. {
  480. CCSPlayer *pOtherPlayer = ( CCSPlayer* )UTIL_PlayerByIndex( i );
  481. if ( pOtherPlayer && pOtherPlayer->GetTeamNumber() == pPlayer->GetTeamNumber() )
  482. {
  483. if ( m_nAttemptedToGetColor[i] == true )
  484. nNumAttemptedToGetColor++;
  485. if ( nNumAttemptedToGetColor >= 5 )
  486. {
  487. if ( nTeamNum == TEAM_TERRORIST )
  488. m_bPreferencesAssigned_T = true;
  489. else
  490. m_bPreferencesAssigned_CT = true;
  491. break;
  492. }
  493. }
  494. }
  495. }
  496. // Valve MM gives us the player index - does this work?
  497. if ( idxThisPlayer > -1 )
  498. {
  499. m_iCompTeammateColor.Set( index, ( idxThisPlayer % 5 ) );
  500. }
  501. else if ( m_iCompTeammateColor[index] == -1 || bReset )//otherwise we have to do it ourselves
  502. {
  503. int nPreferredColor = pPlayer->GetTeammatePreferredColor( );
  504. if ( nPreferredColor == -1 )
  505. {
  506. pPlayer->InitTeammatePreferredColor( );
  507. nPreferredColor = pPlayer->GetTeammatePreferredColor( );
  508. }
  509. // we didn't initialize, so try again another time
  510. if ( nPreferredColor == -1 )
  511. return;
  512. int nAssignedColor = m_iCompTeammateColor[index] > -1 ? m_iCompTeammateColor[index] : nPreferredColor;
  513. bool bColorInUse = false;
  514. for ( int ii = 0; ii < 5; ii++ )
  515. {
  516. nAssignedColor = nAssignedColor % 5;
  517. bColorInUse = false;
  518. for ( int j = 1; j <= gpGlobals->maxClients; j++ )
  519. {
  520. CCSPlayer *pOtherPlayer = ( CCSPlayer* )UTIL_PlayerByIndex( j );
  521. if ( pOtherPlayer && pOtherPlayer->GetTeamNumber( ) == pPlayer->GetTeamNumber( ) )
  522. {
  523. if ( nAssignedColor == m_iCompTeammateColor[j] && pOtherPlayer != pPlayer )
  524. {
  525. // All players should get a crack at getting their prefered color before a
  526. // previously connected player crawls up the color scale and nabs it first
  527. if ( ( nTeamNum == TEAM_TERRORIST && m_bPreferencesAssigned_T == false) ||
  528. ( nTeamNum == TEAM_CT && m_bPreferencesAssigned_CT == false ) )
  529. return;
  530. bColorInUse = true;
  531. nAssignedColor++;
  532. break;
  533. }
  534. }
  535. }
  536. if ( bColorInUse == false )
  537. break;
  538. }
  539. // somehow this failed
  540. AssertMsg( !bColorInUse, "Trying to assign a color to a teammate, but all colors are already in use!" );
  541. nAssignedColor = bColorInUse == false ? nAssignedColor : -1;
  542. m_iCompTeammateColor.Set( index, nAssignedColor );
  543. }
  544. }
  545. else
  546. m_iCompTeammateColor.Set( index, -1 );
  547. }
  548. }
  549. bool CCSPlayerResource::IsAssassinationTarget( int index ) const
  550. {
  551. return m_bIsAssassinationTarget[ index ];
  552. }
  553. bool Helper_DoesPlayerHaveAssassinateQuestForTeam( const CCSPlayer *pPlayer, int iTeamNum )
  554. {
  555. // If this player has an assassination quest targeting this team, prefer not to pick them as the target
  556. CEconQuestDefinition *pQuest = GetItemSchema()->GetQuestDefinition( pPlayer->Inventory()->GetActiveQuestID() );
  557. return ( pQuest && IsAssassinationQuest( pQuest ) && ( ( int ) pQuest->GetTargetTeam() == iTeamNum ) );
  558. }
  559. bool Helper_ValidateAssassinationTarget( const CCSPlayer *pCurrentAssassinationTarget, int iTeamNum )
  560. {
  561. // Validate current assassination target, pick new one if needed
  562. if ( !pCurrentAssassinationTarget || !pCurrentAssassinationTarget->IsConnected() ||
  563. pCurrentAssassinationTarget->GetTeamNumber() != iTeamNum || pCurrentAssassinationTarget->IsDead() ||
  564. pCurrentAssassinationTarget->IsControllingBot() || Helper_DoesPlayerHaveAssassinateQuestForTeam( pCurrentAssassinationTarget, iTeamNum ) )
  565. {
  566. return false;
  567. }
  568. return true;
  569. }
  570. ConVar sv_assassination_target_ratio( "sv_assassination_target_ratio", "5" );
  571. void CCSPlayerResource::UpdateAssassinationTargets( const CEconQuestDefinition * pQuest )
  572. {
  573. CCSTeam *pTeam = GetGlobalCSTeam( pQuest->GetTargetTeam() );
  574. if ( !pTeam )
  575. return;
  576. // 1 out of X players is an assassination target, no less than 1 and more more than MAX_ASSASSINATION_TARGETS.
  577. CUtlVector<CCSPlayer*> vecCandiates;
  578. auto iTargetsNeeded = Min( Max( 1, pTeam->GetHumanMembers( &vecCandiates ) / Max( 1, sv_assassination_target_ratio.GetInt() ) ), 3 );
  579. CUtlVector< CCSPlayer* > vecNotIdealPlayers;
  580. FOR_EACH_VEC_BACK( vecCandiates, iter )
  581. {
  582. CCSPlayer* pCur = vecCandiates[ iter ];
  583. // Validate current assassination targets, remove from candidate list
  584. if ( pCur->IsAssassinationTarget() )
  585. {
  586. // Still valid, then reduce count of needed targets
  587. if ( Helper_ValidateAssassinationTarget( pCur, pQuest->GetTargetTeam() ) )
  588. {
  589. iTargetsNeeded--;
  590. }
  591. else
  592. {
  593. // Prefer not to pick recently invalidated players
  594. m_bIsAssassinationTarget.GetForModify( pCur->entindex() ) = false;
  595. vecNotIdealPlayers.AddToHead( pCur );
  596. }
  597. vecCandiates.Remove( iter );
  598. }
  599. else if ( Helper_DoesPlayerHaveAssassinateQuestForTeam( pCur, GetTeamNumber() ) )
  600. {
  601. // Prefer not to pick players with this quest
  602. vecCandiates.Remove( iter );
  603. vecNotIdealPlayers.AddToTail( pCur );
  604. }
  605. }
  606. while ( iTargetsNeeded-- > 0 )
  607. {
  608. CUtlVector< CCSPlayer* > &vecBucket = vecCandiates.Count() > 0 ? vecCandiates : vecNotIdealPlayers;
  609. CCSPlayer *pTarget = vecBucket[ RandomInt( 0, vecBucket.Count() - 1 ) ];
  610. vecBucket.FindAndFastRemove( pTarget );
  611. m_bIsAssassinationTarget.GetForModify( pTarget->entindex() ) = true;
  612. }
  613. }