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

//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: CS's custom CPlayerResource
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "cs_player.h"
#include "cs_simple_hostage.h"
#include "cs_player_resource.h"
#include "econ_game_account_client.h"
#include "weapon_c4.h"
#include <coordsize.h>
#include "cs_bot_manager.h"
#include "cs_gamerules.h"
#include "cs_bot.h"
#include "cs_team.h"
extern bool g_fGameOver;
// Datatable
IMPLEMENT_SERVERCLASS_ST(CCSPlayerResource, DT_CSPlayerResource)
SendPropInt( SENDINFO( m_iPlayerC4 ), 8, SPROP_UNSIGNED ),
SendPropInt( SENDINFO( m_iPlayerVIP ), 8, SPROP_UNSIGNED ),
SendPropArray3( SENDINFO_ARRAY3(m_bHostageAlive), SendPropInt( SENDINFO_ARRAY(m_bHostageAlive), 1, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_isHostageFollowingSomeone), SendPropInt( SENDINFO_ARRAY(m_isHostageFollowingSomeone), 1, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iHostageEntityIDs), SendPropInt( SENDINFO_ARRAY(m_iHostageEntityIDs), -1, SPROP_UNSIGNED ) ),
SendPropVector( SENDINFO(m_bombsiteCenterA), -1, SPROP_COORD),
SendPropVector( SENDINFO(m_bombsiteCenterB), -1, SPROP_COORD),
SendPropArray3( SENDINFO_ARRAY3(m_hostageRescueX), SendPropInt( SENDINFO_ARRAY(m_hostageRescueX), COORD_INTEGER_BITS+1, 0 ) ),
SendPropArray3( SENDINFO_ARRAY3(m_hostageRescueY), SendPropInt( SENDINFO_ARRAY(m_hostageRescueY), COORD_INTEGER_BITS+1, 0 ) ),
SendPropArray3( SENDINFO_ARRAY3(m_hostageRescueZ), SendPropInt( SENDINFO_ARRAY(m_hostageRescueZ), COORD_INTEGER_BITS+1, 0 ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iMVPs), SendPropInt( SENDINFO_ARRAY(m_iMVPs), COORD_INTEGER_BITS+1, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iArmor), SendPropInt( SENDINFO_ARRAY(m_iArmor), COORD_INTEGER_BITS+1, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_bHasDefuser), SendPropInt( SENDINFO_ARRAY(m_bHasDefuser), 1, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_bHasHelmet), SendPropInt( SENDINFO_ARRAY(m_bHasHelmet), 1, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iScore), SendPropInt( SENDINFO_ARRAY(m_iScore), 32) ),
SendPropArray3( SENDINFO_ARRAY3(m_iCompetitiveRanking), SendPropInt( SENDINFO_ARRAY(m_iCompetitiveRanking), 32) ),
SendPropArray3( SENDINFO_ARRAY3(m_iCompetitiveWins), SendPropInt( SENDINFO_ARRAY(m_iCompetitiveWins), 32) ),
SendPropArray3( SENDINFO_ARRAY3( m_iCompTeammateColor ), SendPropInt( SENDINFO_ARRAY( m_iCompTeammateColor ), 32 ) ),
#if CS_CONTROLLABLE_BOTS_ENABLED
SendPropArray3( SENDINFO_ARRAY3(m_bControllingBot), SendPropInt( SENDINFO_ARRAY(m_bControllingBot), 1, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iControlledPlayer), SendPropInt( SENDINFO_ARRAY(m_iControlledPlayer), 8, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iControlledByPlayer), SendPropInt( SENDINFO_ARRAY(m_iControlledByPlayer), 8, SPROP_UNSIGNED ) ),
#endif
SendPropArray3( SENDINFO_ARRAY3(m_iBotDifficulty), SendPropInt( SENDINFO_ARRAY(m_iBotDifficulty), 32) ),
SendPropArray3( SENDINFO_ARRAY3(m_szClan), SendPropStringT( SENDINFO_ARRAY(m_szClan) ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iTotalCashSpent), SendPropInt( SENDINFO_ARRAY(m_iTotalCashSpent), 32) ),
SendPropArray3( SENDINFO_ARRAY3(m_iCashSpentThisRound), SendPropInt( SENDINFO_ARRAY(m_iCashSpentThisRound), 32) ),
SendPropArray3( SENDINFO_ARRAY3(m_nEndMatchNextMapVotes), SendPropInt( SENDINFO_ARRAY(m_nEndMatchNextMapVotes), 32) ),
SendPropBool( SENDINFO( m_bEndMatchNextMapAllVoted ) ),
SendPropArray3( SENDINFO_ARRAY3(m_nActiveCoinRank), SendPropInt( SENDINFO_ARRAY(m_nActiveCoinRank), 32) ),
SendPropArray3( SENDINFO_ARRAY3(m_nMusicID), SendPropInt( SENDINFO_ARRAY(m_nMusicID), 32) ),
// SendPropArray3( SENDINFO_ARRAY3(m_bIsAssassinationTarget), SendPropBool( SENDINFO_ARRAY(m_bIsAssassinationTarget), 32) ),
SendPropArray3( SENDINFO_ARRAY3(m_nPersonaDataPublicLevel), SendPropInt( SENDINFO_ARRAY(m_nPersonaDataPublicLevel), 32) ),
SendPropArray3( SENDINFO_ARRAY3(m_nPersonaDataPublicCommendsLeader), SendPropInt( SENDINFO_ARRAY(m_nPersonaDataPublicCommendsLeader), 32) ),
SendPropArray3( SENDINFO_ARRAY3(m_nPersonaDataPublicCommendsTeacher), SendPropInt( SENDINFO_ARRAY(m_nPersonaDataPublicCommendsTeacher), 32) ),
SendPropArray3( SENDINFO_ARRAY3(m_nPersonaDataPublicCommendsFriendly), SendPropInt( SENDINFO_ARRAY(m_nPersonaDataPublicCommendsFriendly), 32) ),
END_SEND_TABLE()
BEGIN_DATADESC( CCSPlayerResource )
// DEFINE_ARRAY( m_iPing, FIELD_INTEGER, MAX_PLAYERS+1 ),
// DEFINE_ARRAY( m_iPacketloss, FIELD_INTEGER, MAX_PLAYERS+1 ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( cs_player_manager, CCSPlayerResource );
CCSPlayerResource::CCSPlayerResource( void )
{
m_bEndMatchNextMapAllVoted = false;
m_bPreferencesAssigned_T = false;
m_bPreferencesAssigned_CT = false;
memset( m_nAttemptedToGetColor, false, sizeof( m_nAttemptedToGetColor ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCSPlayerResource::UpdatePlayerData( void )
{
int i;
m_iPlayerC4 = 0;
m_iPlayerVIP = 0;
int nTotalPlayingPlayers = 0;
for ( i = 1; i <= gpGlobals->maxClients; i++ )
{
int botDifficulty = -1;
CCSPlayer *pPlayer = (CCSPlayer*)UTIL_PlayerByIndex( i );
bool bSetValidRanking = false;
if ( pPlayer && pPlayer->IsConnected() )
{
if ( pPlayer->IsVIP() )
{
// we should only have one VIP
Assert( m_iPlayerVIP == 0 );
m_iPlayerVIP = i;
}
if ( pPlayer->HasC4() )
{
// we should only have one bomb
m_iPlayerC4 = i;
}
m_iMVPs.Set( i, pPlayer->GetNumMVPs() );
m_bHasDefuser.Set( i, pPlayer->HasDefuser() );
m_bHasHelmet.Set( i, pPlayer->m_bHasHelmet );
m_iArmor.Set( i, pPlayer->ArmorValue() );
m_iScore.Set( i, pPlayer->GetScore() );
m_iTotalCashSpent.Set( i, pPlayer->GetTotalCashSpent() );
m_iCashSpentThisRound.Set( i, pPlayer->GetCashSpentThisRound() );
m_szClan.Set(i, AllocPooledString( pPlayer->GetClanTag() ) );
m_nEndMatchNextMapVotes.Set( i, pPlayer->GetEndMatchNextMapVote() );
m_nActiveCoinRank.Set( i, pPlayer->GetRank( MEDAL_CATEGORY_SEASON_COIN ) );
m_nMusicID.Set( i, pPlayer->GetMusicID() );
// UpdateAssassinationTargets();
if ( CEconPersonaDataPublic const *pPublic = pPlayer->GetPersonaDataPublic() )
{
m_nPersonaDataPublicLevel.Set( i, pPublic->Obj().player_level() );
m_nPersonaDataPublicCommendsLeader.Set( i, pPublic->Obj().commendation().cmd_leader() );
m_nPersonaDataPublicCommendsTeacher.Set( i, pPublic->Obj().commendation().cmd_teaching() );
m_nPersonaDataPublicCommendsFriendly.Set( i, pPublic->Obj().commendation().cmd_friendly() );
}
else
{
m_nPersonaDataPublicLevel.Set( i, -1 );
m_nPersonaDataPublicCommendsLeader.Set( i, -1 );
m_nPersonaDataPublicCommendsTeacher.Set( i, -1 );
m_nPersonaDataPublicCommendsFriendly.Set( i, -1 );
}
if ( pPlayer->IsBot() )
{
CCSBot* pBot = dynamic_cast< CCSBot* >( pPlayer );
if ( pBot )
{
// Retrieve and store the bot's difficulty level
const BotProfile* pProfile = pBot->GetProfile();
if ( pProfile )
{
botDifficulty = pProfile->GetMaxDifficulty();
}
m_iCompTeammateColor.Set( i, -2 );
m_nAttemptedToGetColor[i] = true;
// SetPlayerTeammateColor( i, false );
}
}
else
{
if ( pPlayer->GetTeamNumber() != TEAM_SPECTATOR )
nTotalPlayingPlayers++;
SetPlayerTeammateColor( i, false );
}
if ( CSGameRules() && CSGameRules()->IsQueuedMatchmaking() )
{
for ( int k = 0; k < CCSGameRules::sm_QueuedServerReservation.rankings().size(); ++ k )
{
if ( CCSGameRules::sm_QueuedServerReservation.rankings( k ).account_id() == pPlayer->GetHumanPlayerAccountID() )
{
m_iCompetitiveRanking.Set( i, CCSGameRules::sm_QueuedServerReservation.rankings( k ).rank_id() );
m_iCompetitiveWins.Set( i, CCSGameRules::sm_QueuedServerReservation.rankings( k ).wins() );
bSetValidRanking = true;
break;
}
}
}
}
else
{
m_iMVPs.Set( i, 0 );
m_bHasDefuser.Set( i, false );
m_bHasHelmet.Set( i, false );
m_iArmor.Set( i, 0 );
m_szClan.Set( i, MAKE_STRING( "" ) );
m_nEndMatchNextMapVotes.Set( i, -1 );
m_nActiveCoinRank.Set( i, -1 );
m_nMusicID.Set( i, -1 );
m_bIsAssassinationTarget.Set( i, 0 );
m_nPersonaDataPublicLevel.Set( i, -1 );
m_nPersonaDataPublicCommendsLeader.Set( i, -1 );
m_nPersonaDataPublicCommendsTeacher.Set( i, -1 );
m_nPersonaDataPublicCommendsFriendly.Set( i, -1 );
m_iCompTeammateColor.Set( i, -1 );
m_nAttemptedToGetColor[i] = false;
}
if ( !bSetValidRanking )
{
m_iCompetitiveRanking.Set( i, 0 );
m_iCompetitiveWins.Set( i, 0 );
}
m_iBotDifficulty.Set( i, botDifficulty );
}
if ( g_fGameOver && nTotalPlayingPlayers > 0 && CSGameRules() && CSGameRules()->IsEndMatchVotingForNextMap() )
{
if ( m_bEndMatchNextMapAllVoted == false )
{
// ignore whether all players voted and just return whether or not we ran out of time
if ( CSGameRules()->m_eEndMatchMapVoteState == CSGameRules()->k_EEndMatchMapVoteState_VoteTimeEnded ||
CSGameRules()->m_eEndMatchMapVoteState == CSGameRules()->k_EEndMatchMapVoteState_AllPlayersVoted ||
CSGameRules()->m_eEndMatchMapVoteState == CSGameRules()->k_EEndMatchMapVoteState_SelectingWinner ||
CSGameRules()->m_eEndMatchMapVoteState == CSGameRules()->k_EEndMatchMapVoteState_SettingNextLevel ||
CSGameRules()->m_eEndMatchMapVoteState == CSGameRules()->k_EEndMatchMapVoteState_VoteAllDone )
{
m_bEndMatchNextMapAllVoted = true;
}
/* m_bEndMatchNextMapAllVoted = (CSGameRules()->m_eEndMatchMapVoteState == CSGameRules()->k_EEndMatchMapVoteState_VoteTimeEnded);*/
// int nNumVotes = 0;
// int nHighestSingleVoteSlot = 0;
//
// // this is done in three different places
// // TODO: make a function out of this
// int nVotes[MAX_ENDMATCH_VOTE_PANELS];
// for ( int i = 0; i < MAX_ENDMATCH_VOTE_PANELS; i++ )
// nVotes[i] = 0;
//
// for ( int i = 1; i <= MAX_PLAYERS; i++ )
// {
// int nMapSlot = m_nEndMatchNextMapVotes[i];
// if ( nMapSlot != -1 && nMapSlot < MAX_ENDMATCH_VOTE_PANELS )
// {
// nVotes[nMapSlot] += 1;
// nNumVotes += 1;
// }
// }
// //////
//
// for ( int i = 0; i < MAX_ENDMATCH_VOTE_PANELS + 1; i++ )
// {
// if ( nVotes[nHighestSingleVoteSlot] < nVotes[i] )
// nHighestSingleVoteSlot = i;
// }
//
// if ( nTotalPlayingPlayers > 0 )
// {
// float flnVotesToSucceed = (float)nTotalPlayingPlayers * 0.501f;
// int nVotesToSucceed = ceil( flnVotesToSucceed );
//
// if ( nNumVotes >= nTotalPlayingPlayers || nVotes[nHighestSingleVoteSlot] >= nVotesToSucceed || ( nextlevel.GetString() && *nextlevel.GetString() && engine->IsMapValid( nextlevel.GetString() ) ) )
// m_bEndMatchNextMapAllVoted = true;
// }
}
}
else
{
// if we aren't at the end of the game or we don't have any players, no one has voted
m_bEndMatchNextMapAllVoted = false;
}
int numHostages = g_Hostages.Count();
for ( i = 0; i < MAX_HOSTAGES; i++ )
{
if ( i >= numHostages )
{
// engine->Con_NPrintf( i, "Dead" );
m_bHostageAlive.Set( i, false );
m_isHostageFollowingSomeone.Set( i, false );
m_iHostageEntityIDs.Set( i, 0 );
continue;
}
CHostage* pHostage = g_Hostages[i];
m_bHostageAlive.Set( i, pHostage->IsRescuable() );
if ( pHostage->IsValid() )
{
m_iHostageEntityIDs.Set( i, pHostage->entindex() );
m_isHostageFollowingSomeone.Set( i, pHostage->IsFollowingSomeone() );
// engine->Con_NPrintf( i, "ID:%d Pos:(%.0f,%.0f,%.0f)", pHostage->entindex(), pHostage->GetAbsOrigin().x, pHostage->GetAbsOrigin().y, pHostage->GetAbsOrigin().z );
}
else
{
// engine->Con_NPrintf( i, "Invalid" );
}
}
if( !m_foundGoalPositions )
{
// We only need to update these once a map, but we need the client to know about them.
CBaseEntity* ent = NULL;
while ( ( ent = gEntList.FindEntityByClassname( ent, "func_bomb_target" ) ) != NULL )
{
const Vector &pos = ent->WorldSpaceCenter();
CNavArea *area = TheNavMesh->GetNearestNavArea( pos, true, 10000.0f, false, false );
const char *placeName = (area) ? TheNavMesh->PlaceToName( area->GetPlace() ) : NULL;
if ( placeName == NULL )
{
// The bomb site has no area or place name, so just choose A then B
if ( m_bombsiteCenterA.Get().IsZero() )
{
m_bombsiteCenterA = pos;
}
else
{
m_bombsiteCenterB = pos;
}
}
else
{
// The bomb site has a place name, so choose accordingly
if( FStrEq( placeName, "BombsiteA" ) || FStrEq( placeName, "Bombsite" ) )
{
m_bombsiteCenterA = pos;
}
else
{
m_bombsiteCenterB = pos;
}
}
m_foundGoalPositions = true;
}
int hostageRescue = 0;
while ( (( ent = gEntList.FindEntityByClassname( ent, "func_hostage_rescue" ) ) != NULL) && (hostageRescue < MAX_HOSTAGE_RESCUES) )
{
const Vector &pos = ent->WorldSpaceCenter();
m_hostageRescueX.Set( hostageRescue, (int) pos.x );
m_hostageRescueY.Set( hostageRescue, (int) pos.y );
m_hostageRescueZ.Set( hostageRescue, (int) pos.z );
hostageRescue++;
m_foundGoalPositions = true;
}
}
#if CS_CONTROLLABLE_BOTS_ENABLED
for ( int i=0; i < MAX_PLAYERS+1; i++ )
{
CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) );
bool bControllingBot = false;
CCSPlayer *pControlledPlayer = NULL;
CCSPlayer *pControlledByPlayer = NULL;
if ( pPlayer && pPlayer->IsConnected() )
{
bControllingBot = pPlayer->IsControllingBot();
pControlledPlayer = pPlayer->GetControlledBot();
pControlledByPlayer = pPlayer->GetControlledByPlayer();
}
m_bControllingBot.Set( i, bControllingBot ? 1 : 0 );
m_iControlledPlayer.Set( i, pControlledPlayer ? pControlledPlayer->entindex() : 0 );
m_iControlledByPlayer.Set( i, pControlledByPlayer ? pControlledByPlayer->entindex() : 0 );
}
#endif
BaseClass::UpdatePlayerData();
}
void CCSPlayerResource::Spawn( void )
{
m_iPlayerC4 = 0;
m_iPlayerVIP = 0;
m_bombsiteCenterA.Init();
m_bombsiteCenterB.Init();
m_foundGoalPositions = false;
m_bPreferencesAssigned_CT = false;
m_bPreferencesAssigned_T = false;
memset( m_nAttemptedToGetColor, false, sizeof( m_nAttemptedToGetColor ) );
for ( int i=0; i < MAX_HOSTAGES; i++ )
{
m_bHostageAlive.Set( i, 0 );
m_isHostageFollowingSomeone.Set( i, 0 );
m_iHostageEntityIDs.Set(i, 0);
}
for ( int i=0; i < MAX_HOSTAGE_RESCUES; i++ )
{
m_hostageRescueX.Set( i, 0 );
m_hostageRescueY.Set( i, 0 );
m_hostageRescueZ.Set( i, 0 );
}
for ( int i=0; i < MAX_PLAYERS+1; i++ )
{
m_iMVPs.Set( i, 0 );
m_bHasDefuser.Set( i, false );
m_bHasHelmet.Set( i, false );
m_iArmor.Set( i, 0 );
m_iScore.Set( i, 0 );
m_iCompetitiveRanking.Set( i, 0 );
m_iCompetitiveWins.Set( i, 0 );
m_iCompTeammateColor.Set( i, -1 );
m_iBotDifficulty.Set( i, -1 );
m_szClan.Set( i, MAKE_STRING( "" ) );
m_nActiveCoinRank.Set( i, -1 );
m_nMusicID.Set( i, -1 );
m_bIsAssassinationTarget.Set( i, 0 );
m_nPersonaDataPublicLevel.Set( i, -1 );
m_nPersonaDataPublicCommendsLeader.Set( i, -1 );
m_nPersonaDataPublicCommendsTeacher.Set( i, -1 );
m_nPersonaDataPublicCommendsFriendly.Set( i, -1 );
}
m_bEndMatchNextMapAllVoted = false;
for ( int i=0; i < MAX_ENDMATCH_VOTE_PANELS+1; i++ )
{
m_nEndMatchNextMapVotes.Set( i, 0 );
}
BaseClass::Spawn();
}
const Vector CCSPlayerResource::GetBombsiteAPosition()
{
return m_bombsiteCenterA;
}
const Vector CCSPlayerResource::GetBombsiteBPosition()
{
return m_bombsiteCenterB;
}
const Vector CCSPlayerResource::GetHostageRescuePosition( int iIndex )
{
if ( iIndex < 0 || iIndex >= MAX_HOSTAGE_RESCUES )
return vec3_origin;
Vector ret;
ret.x = m_hostageRescueX[iIndex];
ret.y = m_hostageRescueY[iIndex];
ret.z = m_hostageRescueZ[iIndex];
return ret;
}
//--------------------------------------------------------------------------------------------------------
int CCSPlayerResource::GetCompTeammateColor( int iIndex )
{
CCSPlayer *pPlayer = ( CCSPlayer* )UTIL_PlayerByIndex( iIndex );
if ( !pPlayer )
return -1;
if ( pPlayer->IsBot() )
return -2;
return m_iCompTeammateColor[iIndex];
}
void CCSPlayerResource::ResetPlayerTeammateColor( int index )
{
CCSPlayer *pPlayer = ( CCSPlayer* )UTIL_PlayerByIndex( index );
if ( !pPlayer )
return;
if ( CSGameRules() && CSGameRules()->IsPlayingAnyCompetitiveStrictRuleset() && CSGameRules()->IsQueuedMatchmaking() )
return;
int nTeamNum = pPlayer->GetTeamNumber();
if ( nTeamNum > TEAM_SPECTATOR )
{
SetPlayerTeammateColor( index, true );
return;
}
m_iCompTeammateColor.Set( index, -1 );
}
void CCSPlayerResource::ForcePlayersPickColors()
{
m_bPreferencesAssigned_CT = true;
m_bPreferencesAssigned_T = true;
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
m_nAttemptedToGetColor[i] = true;
}
void CCSPlayerResource::SetPlayerTeammateColor( int index, bool bReset )
{
CCSPlayer *pPlayer = ( CCSPlayer* )UTIL_PlayerByIndex( index );
if ( !pPlayer )
return;
m_nAttemptedToGetColor[index] = true;
if ( !CSGameRules() || !CSGameRules()->IsPlayingAnyCompetitiveStrictRuleset() )
{
m_iCompTeammateColor.Set( index, -1 );
return;
}
if ( pPlayer->IsBot() )
{
m_iCompTeammateColor.Set( index, -2 );
return;
}
int nTeamNum = pPlayer->GetTeamNumber();
if ( nTeamNum > TEAM_SPECTATOR )
{
if ( CSGameRules() && CSGameRules()->IsPlayingAnyCompetitiveStrictRuleset() )
{
// check to see if we have a color already
int idxThisPlayer = -1;
// don't use the QMM code
/*
if ( CSGameRules()->IsQueuedMatchmaking() )
{
CCSPlayer *pThisPlayer = ( CCSPlayer* )UTIL_PlayerByIndex( index );
CSteamID steamID;
pThisPlayer->GetSteamID( &steamID );
int numTotalPlayers = 0;
static ConVarRef sv_mmqueue_reservation( "sv_mmqueue_reservation" );
for ( char const *pszPrev = sv_mmqueue_reservation.GetString(), *pszNext = pszPrev;
( pszNext = strchr( pszPrev, '[' ) ) != NULL; pszPrev = pszNext + 1 )
{
uint32 uiAccountId = 0;
sscanf( pszNext, "[%x]", &uiAccountId );
if ( uiAccountId && ( steamID.GetAccountID() == uiAccountId ) )
{
idxThisPlayer = numTotalPlayers;
}
++numTotalPlayers;
}
}
*/
// let all players have at least one crack at getting their prefered color before we start assigning loser colors
if ( (nTeamNum == TEAM_TERRORIST && m_bPreferencesAssigned_T == false) ||
(nTeamNum == TEAM_CT && m_bPreferencesAssigned_CT == false) )
{
int nNumAttemptedToGetColor = 0;
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CCSPlayer *pOtherPlayer = ( CCSPlayer* )UTIL_PlayerByIndex( i );
if ( pOtherPlayer && pOtherPlayer->GetTeamNumber() == pPlayer->GetTeamNumber() )
{
if ( m_nAttemptedToGetColor[i] == true )
nNumAttemptedToGetColor++;
if ( nNumAttemptedToGetColor >= 5 )
{
if ( nTeamNum == TEAM_TERRORIST )
m_bPreferencesAssigned_T = true;
else
m_bPreferencesAssigned_CT = true;
break;
}
}
}
}
// Valve MM gives us the player index - does this work?
if ( idxThisPlayer > -1 )
{
m_iCompTeammateColor.Set( index, ( idxThisPlayer % 5 ) );
}
else if ( m_iCompTeammateColor[index] == -1 || bReset )//otherwise we have to do it ourselves
{
int nPreferredColor = pPlayer->GetTeammatePreferredColor( );
if ( nPreferredColor == -1 )
{
pPlayer->InitTeammatePreferredColor( );
nPreferredColor = pPlayer->GetTeammatePreferredColor( );
}
// we didn't initialize, so try again another time
if ( nPreferredColor == -1 )
return;
int nAssignedColor = m_iCompTeammateColor[index] > -1 ? m_iCompTeammateColor[index] : nPreferredColor;
bool bColorInUse = false;
for ( int ii = 0; ii < 5; ii++ )
{
nAssignedColor = nAssignedColor % 5;
bColorInUse = false;
for ( int j = 1; j <= gpGlobals->maxClients; j++ )
{
CCSPlayer *pOtherPlayer = ( CCSPlayer* )UTIL_PlayerByIndex( j );
if ( pOtherPlayer && pOtherPlayer->GetTeamNumber( ) == pPlayer->GetTeamNumber( ) )
{
if ( nAssignedColor == m_iCompTeammateColor[j] && pOtherPlayer != pPlayer )
{
// All players should get a crack at getting their prefered color before a
// previously connected player crawls up the color scale and nabs it first
if ( ( nTeamNum == TEAM_TERRORIST && m_bPreferencesAssigned_T == false) ||
( nTeamNum == TEAM_CT && m_bPreferencesAssigned_CT == false ) )
return;
bColorInUse = true;
nAssignedColor++;
break;
}
}
}
if ( bColorInUse == false )
break;
}
// somehow this failed
AssertMsg( !bColorInUse, "Trying to assign a color to a teammate, but all colors are already in use!" );
nAssignedColor = bColorInUse == false ? nAssignedColor : -1;
m_iCompTeammateColor.Set( index, nAssignedColor );
}
}
else
m_iCompTeammateColor.Set( index, -1 );
}
}
bool CCSPlayerResource::IsAssassinationTarget( int index ) const
{
return m_bIsAssassinationTarget[ index ];
}
bool Helper_DoesPlayerHaveAssassinateQuestForTeam( const CCSPlayer *pPlayer, int iTeamNum )
{
// If this player has an assassination quest targeting this team, prefer not to pick them as the target
CEconQuestDefinition *pQuest = GetItemSchema()->GetQuestDefinition( pPlayer->Inventory()->GetActiveQuestID() );
return ( pQuest && IsAssassinationQuest( pQuest ) && ( ( int ) pQuest->GetTargetTeam() == iTeamNum ) );
}
bool Helper_ValidateAssassinationTarget( const CCSPlayer *pCurrentAssassinationTarget, int iTeamNum )
{
// Validate current assassination target, pick new one if needed
if ( !pCurrentAssassinationTarget || !pCurrentAssassinationTarget->IsConnected() ||
pCurrentAssassinationTarget->GetTeamNumber() != iTeamNum || pCurrentAssassinationTarget->IsDead() ||
pCurrentAssassinationTarget->IsControllingBot() || Helper_DoesPlayerHaveAssassinateQuestForTeam( pCurrentAssassinationTarget, iTeamNum ) )
{
return false;
}
return true;
}
ConVar sv_assassination_target_ratio( "sv_assassination_target_ratio", "5" );
void CCSPlayerResource::UpdateAssassinationTargets( const CEconQuestDefinition * pQuest )
{
CCSTeam *pTeam = GetGlobalCSTeam( pQuest->GetTargetTeam() );
if ( !pTeam )
return;
// 1 out of X players is an assassination target, no less than 1 and more more than MAX_ASSASSINATION_TARGETS.
CUtlVector<CCSPlayer*> vecCandiates;
auto iTargetsNeeded = Min( Max( 1, pTeam->GetHumanMembers( &vecCandiates ) / Max( 1, sv_assassination_target_ratio.GetInt() ) ), 3 );
CUtlVector< CCSPlayer* > vecNotIdealPlayers;
FOR_EACH_VEC_BACK( vecCandiates, iter )
{
CCSPlayer* pCur = vecCandiates[ iter ];
// Validate current assassination targets, remove from candidate list
if ( pCur->IsAssassinationTarget() )
{
// Still valid, then reduce count of needed targets
if ( Helper_ValidateAssassinationTarget( pCur, pQuest->GetTargetTeam() ) )
{
iTargetsNeeded--;
}
else
{
// Prefer not to pick recently invalidated players
m_bIsAssassinationTarget.GetForModify( pCur->entindex() ) = false;
vecNotIdealPlayers.AddToHead( pCur );
}
vecCandiates.Remove( iter );
}
else if ( Helper_DoesPlayerHaveAssassinateQuestForTeam( pCur, GetTeamNumber() ) )
{
// Prefer not to pick players with this quest
vecCandiates.Remove( iter );
vecNotIdealPlayers.AddToTail( pCur );
}
}
while ( iTargetsNeeded-- > 0 )
{
CUtlVector< CCSPlayer* > &vecBucket = vecCandiates.Count() > 0 ? vecCandiates : vecNotIdealPlayers;
CCSPlayer *pTarget = vecBucket[ RandomInt( 0, vecBucket.Count() - 1 ) ];
vecBucket.FindAndFastRemove( pTarget );
m_bIsAssassinationTarget.GetForModify( pTarget->entindex() ) = true;
}
}