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
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;
|
|
}
|
|
}
|