source-engine/game/server/team_control_point_round.cpp
2022-03-01 23:00:42 +03:00

415 lines
12 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#include "cbase.h"
#include "team_control_point_master.h"
#include "teamplayroundbased_gamerules.h"
#include "team_control_point_round.h"
#if defined ( TF_DLL )
#include "tf_gamerules.h"
#endif
BEGIN_DATADESC( CTeamControlPointRound )
DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "StartDisabled" ),
DEFINE_KEYFIELD( m_iszCPNames, FIELD_STRING, "cpr_cp_names" ),
DEFINE_KEYFIELD( m_nPriority, FIELD_INTEGER, "cpr_priority" ),
DEFINE_KEYFIELD( m_iInvalidCapWinner, FIELD_INTEGER, "cpr_restrict_team_cap_win" ),
DEFINE_KEYFIELD( m_iszPrintName, FIELD_STRING, "cpr_printname" ),
// DEFINE_FIELD( m_ControlPoints, CUtlVector < CHandle < CTeamControlPoint > > ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
DEFINE_INPUTFUNC( FIELD_VOID, "RoundSpawn", InputRoundSpawn ),
DEFINE_OUTPUT( m_OnStart, "OnStart" ),
DEFINE_OUTPUT( m_OnEnd, "OnEnd" ),
DEFINE_OUTPUT( m_OnWonByTeam1, "OnWonByTeam1" ),
DEFINE_OUTPUT( m_OnWonByTeam2, "OnWonByTeam2" ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( team_control_point_round, CTeamControlPointRound );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamControlPointRound::Spawn( void )
{
SetTouch( NULL );
BaseClass::Spawn();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamControlPointRound::Activate( void )
{
BaseClass::Activate();
FindControlPoints();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamControlPointRound::FindControlPoints( void )
{
// Let out control point masters know that the round has started
CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL;
if ( pMaster )
{
// go through all the points
CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, pMaster->GetControlPointName() );
while( pEnt )
{
CTeamControlPoint *pPoint = assert_cast<CTeamControlPoint *>(pEnt);
if ( pPoint )
{
const char *pString = STRING( m_iszCPNames );
const char *pName = STRING( pPoint->GetEntityName() );
// HACK to work around a problem with cp_a being returned for an entity name with cp_A
const char *pos = Q_stristr( pString, pName );
if ( pos )
{
int len = Q_strlen( STRING( pPoint->GetEntityName() ) );
if ( *(pos + len) == ' ' || *(pos + len) == '\0' )
{
if( m_ControlPoints.Find( pPoint ) == m_ControlPoints.InvalidIndex() )
{
DevMsg( 2, "Adding control point %s to control point round %s\n", pPoint->GetEntityName().ToCStr(), GetEntityName().ToCStr() );
m_ControlPoints.AddToHead( pPoint );
}
}
}
}
pEnt = gEntList.FindEntityByClassname( pEnt, pMaster->GetControlPointName() );
}
}
if( m_ControlPoints.Count() == 0 )
{
Warning( "Error! No control points found in map for team_game_round %s!\n", GetEntityName().ToCStr() );
}
}
//-----------------------------------------------------------------------------
// Purpose: Check that the points aren't all held by one team if they are
// this will reset the round and will reset all the points
//-----------------------------------------------------------------------------
int CTeamControlPointRound::CheckWinConditions( void )
{
int iWinners = TeamOwnsAllPoints();
if ( ( m_iInvalidCapWinner != 1 ) &&
( iWinners >= FIRST_GAME_TEAM ) &&
( iWinners != m_iInvalidCapWinner ) )
{
bool bWinner = true;
#if defined( TF_DLL)
if ( TFGameRules() && TFGameRules()->IsInKothMode() )
{
CTeamRoundTimer *pTimer = NULL;
if ( iWinners == TF_TEAM_RED )
{
pTimer = TFGameRules()->GetRedKothRoundTimer();
}
else if ( iWinners == TF_TEAM_BLUE )
{
pTimer = TFGameRules()->GetBlueKothRoundTimer();
}
if ( pTimer )
{
if ( pTimer->GetTimeRemaining() > 0 || TFGameRules()->TimerMayExpire() == false )
{
bWinner = false;
}
}
}
#endif
if ( bWinner )
{
FireTeamWinOutput( iWinners );
return iWinners;
}
}
return -1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamControlPointRound::FireTeamWinOutput( int iWinningTeam )
{
// Remap team so that first game team = 1
switch( iWinningTeam - FIRST_GAME_TEAM+1 )
{
case 1:
m_OnWonByTeam1.FireOutput( this, this );
break;
case 2:
m_OnWonByTeam2.FireOutput( this, this );
break;
default:
Assert(0);
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CTeamControlPointRound::GetPointOwner( int point )
{
Assert( point >= 0 );
Assert( point < MAX_CONTROL_POINTS );
CTeamControlPoint *pPoint = m_ControlPoints[point];
if ( pPoint )
return pPoint->GetOwner();
return TEAM_UNASSIGNED;
}
//-----------------------------------------------------------------------------
// Purpose: This function returns the team that owns all the cap points.
// If its not the case that one team owns them all, it returns 0.
//
// Can be passed an overriding team. If this is not null, the passed team
// number will be used for that cp. Used to predict if that CP changing would
// win the game.
//-----------------------------------------------------------------------------
int CTeamControlPointRound::TeamOwnsAllPoints( CTeamControlPoint *pOverridePoint /* = NULL */, int iOverrideNewTeam /* = TEAM_UNASSIGNED */ )
{
int i;
int iWinningTeam[MAX_CONTROL_POINT_GROUPS];
for( i = 0 ; i < MAX_CONTROL_POINT_GROUPS ; i++ )
{
iWinningTeam[i] = TEAM_INVALID;
}
// if TEAM_INVALID, haven't found a flag for this group yet
// if TEAM_UNASSIGNED, the group is still being contested
// for each control point
for( i = 0 ; i < m_ControlPoints.Count() ; i++ )
{
int group = m_ControlPoints[i]->GetCPGroup();
int owner = m_ControlPoints[i]->GetOwner();
if ( pOverridePoint == m_ControlPoints[i] )
{
owner = iOverrideNewTeam;
}
// the first one we find in this group, set the win to true
if ( iWinningTeam[group] == TEAM_INVALID )
{
iWinningTeam[group] = owner;
}
// unassigned means this group is already contested, move on
else if ( iWinningTeam[group] == TEAM_UNASSIGNED )
{
continue;
}
// if we find another one in the group that isn't the same owner, set the win to false
else if ( owner != iWinningTeam[group] )
{
iWinningTeam[group] = TEAM_UNASSIGNED;
}
}
// report the first win we find as the winner
for ( i = 0 ; i < MAX_CONTROL_POINT_GROUPS ; i++ )
{
if ( iWinningTeam[i] >= FIRST_GAME_TEAM )
return iWinningTeam[i];
}
// no wins yet
return TEAM_UNASSIGNED;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTeamControlPointRound::WouldNewCPOwnerWinGame( CTeamControlPoint *pPoint, int iNewOwner )
{
return ( TeamOwnsAllPoints( pPoint, iNewOwner ) == iNewOwner );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamControlPointRound::InputEnable( inputdata_t &input )
{
m_bDisabled = false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamControlPointRound::InputDisable( inputdata_t &input )
{
m_bDisabled = true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamControlPointRound::InputRoundSpawn( inputdata_t &input )
{
// clear out old control points
m_ControlPoints.RemoveAll();
// find the control points
FindControlPoints();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamControlPointRound::SetupSpawnPoints( void )
{
CTeamplayRoundBasedRules *pRules = TeamplayRoundBasedRules();
if ( pRules )
{
pRules->SetupSpawnPointsForRound();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamControlPointRound::SelectedToPlay( void )
{
SetupSpawnPoints();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamControlPointRound::FireOnStartOutput( void )
{
m_OnStart.FireOutput( this, this );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamControlPointRound::FireOnEndOutput( void )
{
m_OnEnd.FireOutput( this, this );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTeamControlPointRound::IsControlPointInRound( CTeamControlPoint *pPoint )
{
if ( !pPoint )
{
return false;
}
return ( m_ControlPoints.Find( pPoint ) != m_ControlPoints.InvalidIndex() );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTeamControlPointRound::IsPlayable( void )
{
int iWinners = TeamOwnsAllPoints();
if ( m_iInvalidCapWinner == 1 ) // neither team can win this round by capping
{
return true;
}
if ( ( iWinners >= FIRST_GAME_TEAM ) &&
( iWinners != m_iInvalidCapWinner ) )
{
return false; // someone has already won this round
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTeamControlPointRound::MakePlayable( void )
{
CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL;
if ( pMaster )
{
if ( !IsPlayable() )
{
// we need to try switching the owners of the teams to make this round playable
for ( int iTeam = FIRST_GAME_TEAM ; iTeam < GetNumberOfTeams() ; iTeam++ )
{
for ( int iControlPoint = 0 ; iControlPoint < m_ControlPoints.Count() ; iControlPoint++ )
{
if ( ( !pMaster->IsBaseControlPoint( m_ControlPoints[iControlPoint]->GetPointIndex() ) ) && // this is NOT the base point for one of the teams (we don't want to assign the base to the wrong team)
( !WouldNewCPOwnerWinGame( m_ControlPoints[iControlPoint], iTeam ) ) ) // making this change would make this round playable
{
// need to find the trigger area associated with this point
for ( int iObj=0; iObj<ITriggerAreaCaptureAutoList::AutoList().Count(); ++iObj )
{
CTriggerAreaCapture *pArea = static_cast< CTriggerAreaCapture * >( ITriggerAreaCaptureAutoList::AutoList()[iObj] );
if ( pArea->TeamCanCap( iTeam ) )
{
CHandle<CTeamControlPoint> hPoint = pArea->GetControlPoint();
if ( hPoint == m_ControlPoints[iControlPoint] )
{
// found!
pArea->ForceOwner( iTeam ); // this updates the trigger_area *and* the control_point
return true;
}
}
}
}
}
}
}
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: returns the first point found that the given team owns
//-----------------------------------------------------------------------------
CHandle<CTeamControlPoint> CTeamControlPointRound::GetPointOwnedBy( int iTeam )
{
for( int i = 0 ; i < m_ControlPoints.Count() ; i++ )
{
if ( m_ControlPoints[i]->GetOwner() == iTeam )
{
return m_ControlPoints[i];
}
}
return NULL;
}