Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

646 lines
19 KiB

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Team management class. Contains all the details for a specific team
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "team.h"
#include "player.h"
#include "team_spawnpoint.h"
#include "usermessages.h"
#if defined ( CSTRIKE15 )
#include "cs_bot.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CUtlVector< CTeam * > g_Teams;
extern ConVar mp_radar_showall;
//-----------------------------------------------------------------------------
// Purpose: SendProxy that converts the Team's player UtlVector to entindexes
//-----------------------------------------------------------------------------
void SendProxy_PlayerList( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
{
CTeam *pTeam = (CTeam*)pData;
// If this assertion fails, then SendProxyArrayLength_PlayerArray must have failed.
Assert( iElement < pTeam->m_aPlayers.Count() );
CBasePlayer *pPlayer = pTeam->m_aPlayers[iElement];
pOut->m_Int = pPlayer->entindex();
}
int SendProxyArrayLength_PlayerArray( const void *pStruct, int objectID )
{
CTeam *pTeam = (CTeam*)pStruct;
return pTeam->m_aPlayers.Count();
}
// Datatable
IMPLEMENT_SERVERCLASS_ST_NOBASE(CTeam, DT_Team)
SendPropInt( SENDINFO(m_iTeamNum), 5 ),
SendPropInt( SENDINFO(m_bSurrendered), 0 ),
SendPropInt( SENDINFO(m_scoreTotal), 0 ),
SendPropInt( SENDINFO(m_scoreFirstHalf), 0 ),
SendPropInt( SENDINFO(m_scoreSecondHalf), 0 ),
SendPropInt( SENDINFO(m_scoreOvertime), 0 ),
SendPropInt( SENDINFO(m_iClanID), 32, SPROP_UNSIGNED ),
SendPropString( SENDINFO( m_szTeamname ) ),
SendPropString( SENDINFO( m_szClanTeamname ) ),
SendPropString( SENDINFO( m_szTeamFlagImage ) ),
SendPropString( SENDINFO( m_szTeamLogoImage ) ),
SendPropString( SENDINFO( m_szTeamMatchStat ) ),
SendPropInt( SENDINFO( m_nGGLeaderEntIndex_CT ), 0 ),
SendPropInt( SENDINFO( m_nGGLeaderEntIndex_T ), 0 ),
SendPropInt( SENDINFO(m_numMapVictories), 4, SPROP_UNSIGNED ),
SendPropArray2(
SendProxyArrayLength_PlayerArray,
SendPropInt("player_array_element", 0, 4, 10, SPROP_UNSIGNED, SendProxy_PlayerList),
MAX_PLAYERS,
0,
"player_array"
)
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( team_manager, CTeam );
//-----------------------------------------------------------------------------
// Purpose: Get a pointer to the specified team manager
//-----------------------------------------------------------------------------
CTeam *GetGlobalTeam( int iIndex )
{
if ( iIndex < 0 || iIndex >= GetNumberOfTeams() )
return NULL;
return g_Teams[ iIndex ];
}
//-----------------------------------------------------------------------------
// Purpose: Get the number of team managers
//-----------------------------------------------------------------------------
int GetNumberOfTeams( void )
{
return g_Teams.Count();
}
const char* GetTeamName( int iTeam )
{
CTeam *pTeam = GetGlobalTeam( iTeam );
if ( pTeam )
{
return pTeam->GetName();
}
else
{
return "UNKNOWN TEAM";
}
}
int CTeam::m_nStaticGGLeader_CT = -1;
int CTeam::m_nStaticGGLeader_T = -1;
//-----------------------------------------------------------------------------
// Purpose: Needed because this is an entity, but should never be used
//-----------------------------------------------------------------------------
CTeam::CTeam( void )
{
memset( m_szTeamname.GetForModify(), 0, sizeof(m_szTeamname) );
memset( m_szClanTeamname.GetForModify(), 0, sizeof(m_szClanTeamname) );
memset( m_szTeamFlagImage.GetForModify(), 0, sizeof(m_szTeamFlagImage) );
memset( m_szTeamLogoImage.GetForModify(), 0, sizeof(m_szTeamLogoImage) );
memset( m_szTeamMatchStat.GetForModify(), 0, sizeof( m_szTeamMatchStat ) );
m_numMapVictories.GetForModify() = 0;
ResetTeamLeaders();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTeam::~CTeam( void )
{
m_aSpawnPoints.Purge();
m_aPlayers.Purge();
}
void CTeam::ResetTeamLeaders()
{
m_flLastPlayerSortTime = 0;
m_nGGLeaderEntIndex_CT = -1;
m_nGGLeaderEntIndex_T = -1;
m_bGGHasLeader_CT = false;
m_bGGHasLeader_T = false;
}
//-----------------------------------------------------------------------------
// Purpose: Called every frame
//-----------------------------------------------------------------------------
void CTeam::Think( void )
{
if ( m_flLastPlayerSortTime + 0.025f < gpGlobals->curtime )
{
DetermineGGLeaderAndSort();
}
}
void CTeam::DetermineGGLeaderAndSort( void )
{
CUtlVector< CCSPlayer* > playerList_CT;
CUtlVector< CCSPlayer* > playerList_T;
int iNumPlayers = GetNumPlayers();
// m_aPlayers.Sort( PlayerSortFunction );
for ( int i = 0; i < iNumPlayers; i++ )
{
CCSPlayer *player = static_cast< CCSPlayer* >( GetPlayer( i ) );
if ( player )
{
if ( player->GetTeamNumber() == TEAM_CT )
{
if ( player->GetPlayerGunGameWeaponIndex() > 0 )
m_bGGHasLeader_CT = true;
playerList_CT.AddToTail( player );
}
else if ( player->GetTeamNumber() == TEAM_TERRORIST )
{
if ( player->GetPlayerGunGameWeaponIndex() > 0 )
m_bGGHasLeader_T = true;
playerList_T.AddToTail( player );
}
}
}
m_nStaticGGLeader_CT = m_nGGLeaderEntIndex_CT;
m_nStaticGGLeader_T = m_nGGLeaderEntIndex_T;
playerList_CT.Sort( TeamGGSortFunction );
playerList_T.Sort( TeamGGSortFunction );
if ( playerList_CT.Count() > 0 && m_bGGHasLeader_CT )
m_nGGLeaderEntIndex_CT = playerList_CT[0]->entindex();
if ( playerList_T.Count() > 0 && m_bGGHasLeader_T )
m_nGGLeaderEntIndex_T = playerList_T[0]->entindex();
// send an event down so the client gets it asap
if ( m_nLastGGLeader_CT != m_nGGLeaderEntIndex_CT || m_nLastGGLeader_T != m_nGGLeaderEntIndex_T )
{
int nLeaderIndex = m_nGGLeaderEntIndex_CT;
if ( m_nLastGGLeader_T != m_nGGLeaderEntIndex_T )
nLeaderIndex = m_nGGLeaderEntIndex_T;
for ( int i = 1; i <= iNumPlayers; i++ )
{
CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) );
if ( pPlayer && pPlayer->entindex() == nLeaderIndex )
{
//if we made it this far, we are the current leader
IGameEvent *event = gameeventmanager->CreateEvent( "gg_team_leader" );
if ( event )
{
event->SetInt( "playerid", pPlayer->GetUserID() );
gameeventmanager->FireEvent( event );
}
break;
}
}
}
m_nLastGGLeader_CT = m_nGGLeaderEntIndex_CT;
m_nLastGGLeader_T = m_nGGLeaderEntIndex_T;
}
int CTeam::GetGGLeader( int nTeam )
{
if ( nTeam == TEAM_CT )
return m_nGGLeaderEntIndex_CT;
else if ( nTeam == TEAM_TERRORIST )
return m_nGGLeaderEntIndex_T;
return -1;
}
//-----------------------------------------------------------------------------
// Purpose: Used for sorting players in valve containers
//-----------------------------------------------------------------------------
int CTeam::TeamGGSortFunction( CCSPlayer* const *entry1, CCSPlayer* const *entry2 )
{
// bail out early if either player is an empty slot, i.e. has a player index of -1
if ( entry1 == NULL )
return 1;
if ( entry2 == NULL )
return -1;
if ( (*entry1)->entindex() == -1 )
return 1;
if ( (*entry2)->entindex() == -1 )
return -1;
// Higher GG Progressive weapon ranks higher. In case of ties for that, we rank according to player index so
// we don't overly shuffle the ordering
if ( (*entry1)->GetPlayerGunGameWeaponIndex() > (*entry2)->GetPlayerGunGameWeaponIndex() )
return -1;
else if ( (*entry1)->GetPlayerGunGameWeaponIndex() < (*entry2)->GetPlayerGunGameWeaponIndex() )
return 1;
else
{
int nLeader = m_nStaticGGLeader_CT;
if ( (*entry1)->GetTeamNumber() == TEAM_TERRORIST )
nLeader = m_nStaticGGLeader_T;
// Current GG leader always sorts in front in the case of a tie
if ( (*entry1)->entindex() == nLeader )
return -1;
else if ( (*entry2)->entindex() == nLeader )
return 1;
//else
// return entry1->entindex() - entry2->entindex();
}
return 0;
}
//-----------------------------------------------------------------------------
// Purpose: Teams are always transmitted to clients
//-----------------------------------------------------------------------------
int CTeam::UpdateTransmitState()
{
return SetTransmitState( FL_EDICT_ALWAYS );
}
//-----------------------------------------------------------------------------
// Visibility/scanners
//-----------------------------------------------------------------------------
int CTeam::ShouldTransmitToPlayer( CBasePlayer* pRecipient, CBaseEntity* pEntity )
{
// Always transmit the observer target to players and to spectators
if ( pRecipient && (pRecipient->IsObserver() && pRecipient->GetObserverTarget() == pEntity) )
return FL_EDICT_ALWAYS;
// Spec that isn't a coach
if ( pRecipient->IsSpectator() )
return FL_EDICT_ALWAYS;
// Same team
if ( pRecipient->GetAssociatedTeamNumber() == pEntity->GetTeamNumber() )
return FL_EDICT_ALWAYS;
// radar_show is 'all' or set to the target's team.
if ( mp_radar_showall.GetInt() &&
(
( mp_radar_showall.GetInt() == 1 ) ||
( mp_radar_showall.GetInt() == pRecipient->GetTeamNumber() )
) )
return FL_EDICT_ALWAYS;
return FL_EDICT_PVSCHECK;
}
//-----------------------------------------------------------------------------
// Initialization
//-----------------------------------------------------------------------------
void CTeam::Init( const char *pName, int iNumber )
{
InitializeSpawnpoints();
InitializePlayers();
ResetTeamLeaders();
m_bSurrendered = 0;
m_scoreTotal = 0;
m_scoreFirstHalf = 0;
m_scoreSecondHalf = 0;
m_scoreOvertime = 0;
Q_strncpy( m_szTeamname.GetForModify(), pName, MAX_TEAM_NAME_LENGTH );
m_iTeamNum = iNumber;
}
//-----------------------------------------------------------------------------
// DATA HANDLING
//-----------------------------------------------------------------------------
int CTeam::GetTeamNumber( void ) const
{
return m_iTeamNum;
}
//-----------------------------------------------------------------------------
// Purpose: Set the team's name
//-----------------------------------------------------------------------------
void CTeam::SetName( const char *pName )
{
Q_strncpy( m_szTeamname.GetForModify(), pName, MAX_TEAM_NAME_LENGTH );
}
//-----------------------------------------------------------------------------
// Purpose: Get the team's name
//-----------------------------------------------------------------------------
const char *CTeam::GetName( void )
{
return m_szTeamname;
}
//-----------------------------------------------------------------------------
// Purpose: Set the team's name
//-----------------------------------------------------------------------------
void CTeam::SetClanName( const char *pName )
{
Q_strncpy( m_szClanTeamname.GetForModify(), pName, MAX_TEAM_NAME_LENGTH );
}
//-----------------------------------------------------------------------------
// Purpose: Get the team's name
//-----------------------------------------------------------------------------
const char *CTeam::GetClanName( void )
{
return m_szClanTeamname;
}
void CTeam::SetClanID( uint32 iClanID )
{
m_iClanID = iClanID;
}
uint32 CTeam::GetClanID( void )
{
return m_iClanID;
}
//-----------------------------------------------------------------------------
// Purpose: Set the team's name
//-----------------------------------------------------------------------------
void CTeam::SetFlagImageString( const char *pName )
{
Q_strncpy( m_szTeamFlagImage.GetForModify(), pName, MAX_TEAM_FLAG_ICON_LENGTH );
}
//-----------------------------------------------------------------------------
// Purpose: Get the team's name
//-----------------------------------------------------------------------------
const char *CTeam::GetFlagImageString( void )
{
return m_szTeamFlagImage;
}
//-----------------------------------------------------------------------------
// Purpose: Set the team's name
//-----------------------------------------------------------------------------
void CTeam::SetLogoImageString( const char *pName )
{
Q_strncpy( m_szTeamLogoImage.GetForModify(), pName, MAX_TEAM_FLAG_ICON_LENGTH );
}
void CTeam::SetNumMapVictories( int numMapVictories )
{
if ( numMapVictories != m_numMapVictories )
{
m_numMapVictories = numMapVictories;
}
}
//-----------------------------------------------------------------------------
// Purpose: Get the team's name
//-----------------------------------------------------------------------------
const char *CTeam::GetLogoImageString( void )
{
return m_szTeamLogoImage;
}
//-----------------------------------------------------------------------------
// Purpose: Update the player's client data
//-----------------------------------------------------------------------------
void CTeam::UpdateClientData( CBasePlayer *pPlayer )
{
}
//------------------------------------------------------------------------------------------------------------------
// SPAWNPOINTS
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeam::InitializeSpawnpoints( void )
{
m_iLastSpawn = 0;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeam::AddSpawnpoint( CTeamSpawnPoint *pSpawnpoint )
{
m_aSpawnPoints.AddToTail( pSpawnpoint );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeam::RemoveSpawnpoint( CTeamSpawnPoint *pSpawnpoint )
{
for (int i = 0; i < m_aSpawnPoints.Count(); i++ )
{
if ( m_aSpawnPoints[i] == pSpawnpoint )
{
m_aSpawnPoints.Remove( i );
return;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Spawn the player at one of this team's spawnpoints. Return true if successful.
//-----------------------------------------------------------------------------
CBaseEntity *CTeam::SpawnPlayer( CBasePlayer *pPlayer )
{
if ( m_aSpawnPoints.Count() == 0 )
return NULL;
// Randomize the start spot
int iSpawn = m_iLastSpawn + random->RandomInt( 1,3 );
if ( iSpawn >= m_aSpawnPoints.Count() )
iSpawn -= m_aSpawnPoints.Count();
int iStartingSpawn = iSpawn;
// Now loop through the spawnpoints and pick one
int loopCount = 0;
do
{
if ( iSpawn >= m_aSpawnPoints.Count() )
{
++loopCount;
iSpawn = 0;
}
// check if pSpot is valid, and that the player is on the right team
if ( (loopCount > 3) || m_aSpawnPoints[iSpawn]->IsValid( pPlayer ) )
{
// DevMsg( 1, "player: spawning at (%s)\n", STRING(m_aSpawnPoints[iSpawn]->m_iName) );
m_aSpawnPoints[iSpawn]->m_OnPlayerSpawn.FireOutput( pPlayer, m_aSpawnPoints[iSpawn] );
m_iLastSpawn = iSpawn;
return m_aSpawnPoints[iSpawn];
}
iSpawn++;
} while ( iSpawn != iStartingSpawn ); // loop if we're not back to the start
return NULL;
}
//------------------------------------------------------------------------------------------------------------------
// PLAYERS
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeam::InitializePlayers( void )
{
}
//-----------------------------------------------------------------------------
// Purpose: Add the specified player to this team. Remove them from their current team, if any.
//-----------------------------------------------------------------------------
void CTeam::AddPlayer( CBasePlayer *pPlayer )
{
m_aPlayers.AddToTail( pPlayer );
NetworkStateChanged();
}
//-----------------------------------------------------------------------------
// Purpose: Remove this player from the team
//-----------------------------------------------------------------------------
void CTeam::RemovePlayer( CBasePlayer *pPlayer )
{
m_aPlayers.FindAndRemove( pPlayer );
NetworkStateChanged();
}
//-----------------------------------------------------------------------------
// Purpose: Return the number of players in this team.
//-----------------------------------------------------------------------------
int CTeam::GetNumPlayers( void )
{
return m_aPlayers.Count();
}
//-----------------------------------------------------------------------------
// Purpose: Get a specific player
//-----------------------------------------------------------------------------
CBasePlayer *CTeam::GetPlayer( int iIndex )
{
Assert( iIndex >= 0 && iIndex < m_aPlayers.Count() );
return m_aPlayers[ iIndex ];
}
//------------------------------------------------------------------------------------------------------------------
// SCORING
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeam::ResetScores( void )
{
m_bSurrendered = 0;
m_scoreTotal = 0;
m_scoreFirstHalf = 0;
m_scoreSecondHalf = 0;
m_scoreOvertime = 0;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeam::AwardAchievement( int iAchievement )
{
Assert( iAchievement >= 0 && iAchievement < 255 ); // must fit in short
CRecipientFilter filter;
int iNumPlayers = GetNumPlayers();
for ( int i=0;i<iNumPlayers;i++ )
{
if ( GetPlayer(i) )
{
filter.AddRecipient( GetPlayer(i) );
}
}
CCSUsrMsg_AchievementEvent msg;
msg.set_achievement( iAchievement );
SendUserMessage( filter, CS_UM_AchievementEvent, msg );
}
int CTeam::GetAliveMembers( void )
{
int iAlive = 0;
int iNumPlayers = GetNumPlayers();
for ( int i=0;i<iNumPlayers;i++ )
{
if ( GetPlayer(i) && GetPlayer(i)->IsAlive() )
{
iAlive++;
}
}
return iAlive;
}
#if defined ( CSTRIKE15 )
int CTeam::GetBotMembers( CUtlVector< CCSBot* > *pOutVecBots /*= NULL*/ )
{
int iBots = 0;
for ( int i = 0; i < GetNumPlayers(); i++ )
{
if ( GetPlayer( i ) && GetPlayer( i )->IsBot() )
{
if ( pOutVecBots )
{
CCSBot* pBot = dynamic_cast< CCSBot* > ( GetPlayer( i ) );
if ( pBot )
{
pOutVecBots->AddToTail( pBot );
}
}
iBots++;
}
}
return iBots;
}
int CTeam::GetHumanMembers( CUtlVector< class CCSPlayer* > *pOutVecPlayers /*= NULL */ )
{
int iPlayers = 0;
for ( int i = 0; i < GetNumPlayers(); i++ )
{
if ( GetPlayer( i ) && !GetPlayer( i )->IsBot() )
{
if ( pOutVecPlayers )
{
CCSPlayer* pPlayer = dynamic_cast< CCSPlayer * > ( GetPlayer( i ) );
if ( pPlayer )
{
pOutVecPlayers->AddToTail( pPlayer );
}
}
iPlayers++;
}
}
return iPlayers;
}
#endif