379 lines
12 KiB
C++
379 lines
12 KiB
C++
//===== Copyright © 1996-2006, 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"
|
|
|
|
// NOTE: This has to be the last file included!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
|
|
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 ( ( iWinners >= FIRST_GAME_TEAM ) &&
|
|
( iWinners != m_iInvalidCapWinner ) )
|
|
{
|
|
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 iWinningTeam = TEAM_INVALID;
|
|
|
|
// if TEAM_INVALID, haven't found a flag yet
|
|
// if TEAM_UNASSIGNED, it's still being contested
|
|
|
|
// for each control point
|
|
for( int i = 0 ; i < m_ControlPoints.Count() ; i++ )
|
|
{
|
|
int owner = m_ControlPoints[i]->GetOwner();
|
|
|
|
if ( pOverridePoint == m_ControlPoints[i] )
|
|
{
|
|
owner = iOverrideNewTeam;
|
|
}
|
|
|
|
// the first one we find, set the win to true
|
|
if ( iWinningTeam == TEAM_INVALID )
|
|
{
|
|
iWinningTeam = owner;
|
|
}
|
|
// unassigned means this is being contested, move on
|
|
else if ( iWinningTeam == 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 )
|
|
{
|
|
iWinningTeam = TEAM_UNASSIGNED;
|
|
}
|
|
}
|
|
|
|
// report the first win we find as the winner
|
|
if ( iWinningTeam >= FIRST_GAME_TEAM )
|
|
{
|
|
return iWinningTeam;
|
|
}
|
|
|
|
// 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 ( ( 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 i = FIRST_GAME_TEAM ; i < GetNumberOfTeams() ; i++ )
|
|
{
|
|
for ( int j = 0 ; j < m_ControlPoints.Count() ; j++ )
|
|
{
|
|
if ( ( !pMaster->IsBaseControlPoint( m_ControlPoints[j]->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[j], i ) ) ) // making this change would make this round playable
|
|
{
|
|
// need to find the trigger area associated with this point
|
|
CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, pMaster->GetTriggerAreaCaptureName() );
|
|
while( pEnt )
|
|
{
|
|
CTriggerAreaCapture *pArea = assert_cast<CTriggerAreaCapture*>( pEnt );
|
|
if ( pArea )
|
|
{
|
|
if ( pArea->TeamCanCap( i ) )
|
|
{
|
|
CHandle<CTeamControlPoint> hPoint = pArea->GetControlPoint();
|
|
if ( hPoint == m_ControlPoints[j] )
|
|
{
|
|
// found!
|
|
pArea->ForceOwner( i ); // this updates the trigger_area *and* the control_point
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
pEnt = gEntList.FindEntityByClassname( pEnt, pMaster->GetTriggerAreaCaptureName() );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|