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.
414 lines
12 KiB
414 lines
12 KiB
//========= 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; |
|
}
|
|
|