diff options
Diffstat (limited to 'game/server/team_control_point_round.cpp')
| -rw-r--r-- | game/server/team_control_point_round.cpp | 414 |
1 files changed, 414 insertions, 0 deletions
diff --git a/game/server/team_control_point_round.cpp b/game/server/team_control_point_round.cpp new file mode 100644 index 0000000..1fe7980 --- /dev/null +++ b/game/server/team_control_point_round.cpp @@ -0,0 +1,414 @@ +//========= 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 */ ) const +{ + 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; +} |