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.
1347 lines
41 KiB
1347 lines
41 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//===========================================================================// |
|
|
|
#include "cbase.h" |
|
#include "team_objectiveresource.h" |
|
#include "team_control_point_master.h" |
|
#include "teamplayroundbased_gamerules.h" |
|
|
|
#if defined ( TF_DLL ) |
|
#include "tf_gamerules.h" |
|
#endif |
|
|
|
BEGIN_DATADESC( CTeamControlPointMaster ) |
|
DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "StartDisabled" ), |
|
DEFINE_KEYFIELD( m_iszCapLayoutInHUD, FIELD_STRING, "caplayout" ), |
|
DEFINE_KEYFIELD( m_iInvalidCapWinner, FIELD_INTEGER, "cpm_restrict_team_cap_win" ), |
|
DEFINE_KEYFIELD( m_bSwitchTeamsOnWin, FIELD_BOOLEAN, "switch_teams" ), |
|
DEFINE_KEYFIELD( m_bScorePerCapture, FIELD_BOOLEAN, "score_style" ), |
|
DEFINE_KEYFIELD( m_bPlayAllRounds, FIELD_BOOLEAN, "play_all_rounds" ), |
|
|
|
DEFINE_KEYFIELD( m_flPartialCapturePointsRate, FIELD_FLOAT, "partial_cap_points_rate" ), |
|
|
|
DEFINE_KEYFIELD( m_flCustomPositionX, FIELD_FLOAT, "custom_position_x" ), |
|
DEFINE_KEYFIELD( m_flCustomPositionY, FIELD_FLOAT, "custom_position_y" ), |
|
|
|
// DEFINE_FIELD( m_ControlPoints, CUtlMap < int , CTeamControlPoint * > ), |
|
// DEFINE_FIELD( m_bFoundPoints, FIELD_BOOLEAN ), |
|
// DEFINE_FIELD( m_ControlPointRounds, CUtlVector < CTeamControlPointRound * > ), |
|
// DEFINE_FIELD( m_iCurrentRoundIndex, FIELD_INTEGER ), |
|
// DEFINE_ARRAY( m_iszTeamBaseIcons, FIELD_STRING, MAX_TEAMS ), |
|
// DEFINE_ARRAY( m_iTeamBaseIcons, FIELD_INTEGER, MAX_TEAMS ), |
|
// DEFINE_FIELD( m_bFirstRoundAfterRestart, FIELD_BOOLEAN ), |
|
|
|
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), |
|
|
|
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetWinner", InputSetWinner ), |
|
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetWinnerAndForceCaps", InputSetWinnerAndForceCaps ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "RoundSpawn", InputRoundSpawn ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "RoundActivate", InputRoundActivate ), |
|
DEFINE_INPUTFUNC( FIELD_STRING, "SetCapLayout", InputSetCapLayout ), |
|
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetCapLayoutCustomPositionX", InputSetCapLayoutCustomPositionX ), |
|
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetCapLayoutCustomPositionY", InputSetCapLayoutCustomPositionY ), |
|
|
|
DEFINE_FUNCTION( CPMThink ), |
|
|
|
DEFINE_OUTPUT( m_OnWonByTeam1, "OnWonByTeam1" ), |
|
DEFINE_OUTPUT( m_OnWonByTeam2, "OnWonByTeam2" ), |
|
|
|
END_DATADESC() |
|
|
|
LINK_ENTITY_TO_CLASS( team_control_point_master, CTeamControlPointMaster ); |
|
|
|
ConVar mp_time_between_capscoring( "mp_time_between_capscoring", "30", FCVAR_GAMEDLL, "Delay between scoring of owned capture points.", true, 1, false, 0 ); |
|
|
|
// sort function for the list of control_point_rounds (we're sorting them by priority...highest first) |
|
int ControlPointRoundSort( CTeamControlPointRound* const *p1, CTeamControlPointRound* const *p2 ) |
|
{ |
|
// check the priority |
|
if ( (*p2)->GetPriorityValue() > (*p1)->GetPriorityValue() ) |
|
{ |
|
return 1; |
|
} |
|
|
|
return -1; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: init |
|
//----------------------------------------------------------------------------- |
|
CTeamControlPointMaster::CTeamControlPointMaster() |
|
{ |
|
m_flPartialCapturePointsRate = 0.0f; |
|
m_flCustomPositionX = -1.f; |
|
m_flCustomPositionY = -1.f; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::Spawn( void ) |
|
{ |
|
Precache(); |
|
|
|
SetTouch( NULL ); |
|
m_bFoundPoints = false; |
|
SetDefLessFunc( m_ControlPoints ); |
|
|
|
m_iCurrentRoundIndex = -1; |
|
m_bFirstRoundAfterRestart = true; |
|
m_flLastOwnershipChangeTime = -1; |
|
|
|
BaseClass::Spawn(); |
|
|
|
if ( g_hControlPointMasters.Find(this) == g_hControlPointMasters.InvalidIndex() ) |
|
{ |
|
g_hControlPointMasters.AddToTail( this ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::UpdateOnRemove( void ) |
|
{ |
|
BaseClass::UpdateOnRemove(); |
|
|
|
g_hControlPointMasters.FindAndRemove( this ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTeamControlPointMaster::KeyValue( const char *szKeyName, const char *szValue ) |
|
{ |
|
if ( !Q_strncmp( szKeyName, "team_base_icon_", 15 ) ) |
|
{ |
|
int iTeam = atoi(szKeyName+15); |
|
Assert( iTeam >= 0 && iTeam < MAX_TEAMS ); |
|
|
|
m_iszTeamBaseIcons[iTeam] = AllocPooledString(szValue); |
|
} |
|
else |
|
{ |
|
return BaseClass::KeyValue( szKeyName, szValue ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::Precache( void ) |
|
{ |
|
for ( int i = 0; i < MAX_TEAMS; i++ ) |
|
{ |
|
if ( m_iszTeamBaseIcons[i] != NULL_STRING ) |
|
{ |
|
PrecacheMaterial( STRING( m_iszTeamBaseIcons[i] ) ); |
|
m_iTeamBaseIcons[i] = GetMaterialIndex( STRING( m_iszTeamBaseIcons[i] ) ); |
|
Assert( m_iTeamBaseIcons[i] != 0 ); |
|
} |
|
} |
|
|
|
BaseClass::Precache(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::Activate( void ) |
|
{ |
|
BaseClass::Activate(); |
|
|
|
// Find control points right away. This allows client hud elements to know the |
|
// number & starting state of control points before the game actually starts. |
|
FindControlPoints(); |
|
FindControlPointRounds(); |
|
|
|
SetBaseControlPoints(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::RoundRespawn( void ) |
|
{ |
|
|
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::Reset( void ) |
|
{ |
|
|
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTeamControlPointMaster::FindControlPoints( void ) |
|
{ |
|
//go through all the points |
|
CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, GetControlPointName() ); |
|
|
|
int numFound = 0; |
|
|
|
while( pEnt ) |
|
{ |
|
CTeamControlPoint *pPoint = assert_cast<CTeamControlPoint *>(pEnt); |
|
|
|
if( pPoint->IsActive() && !pPoint->IsMarkedForDeletion() ) |
|
{ |
|
int index = pPoint->GetPointIndex(); |
|
|
|
Assert( index >= 0 ); |
|
|
|
if( m_ControlPoints.Find( index ) == m_ControlPoints.InvalidIndex()) |
|
{ |
|
DevMsg( 2, "**** Adding control point %s with index %d to control point master\n", pPoint->GetName(), index ); |
|
m_ControlPoints.Insert( index, pPoint ); |
|
numFound++; |
|
} |
|
else |
|
{ |
|
Warning( "!!!!\nMultiple control points with the same index, duplicates ignored\n!!!!\n" ); |
|
UTIL_Remove( pPoint ); |
|
} |
|
} |
|
|
|
pEnt = gEntList.FindEntityByClassname( pEnt, GetControlPointName() ); |
|
} |
|
|
|
if( numFound > MAX_CONTROL_POINTS ) |
|
{ |
|
Warning( "Too many control points! Max is %d\n", MAX_CONTROL_POINTS ); |
|
} |
|
|
|
//Remap the indeces of the control points so they are 0-based |
|
//====================== |
|
unsigned int j; |
|
|
|
bool bHandled[MAX_CONTROL_POINTS]; |
|
memset( bHandled, 0, sizeof(bHandled) ); |
|
|
|
unsigned int numPoints = m_ControlPoints.Count(); |
|
unsigned int newIndex = 0; |
|
|
|
while( newIndex < numPoints ) |
|
{ |
|
//Find the lowest numbered, unhandled point |
|
int lowestIndex = -1; |
|
int lowestValue = 999; |
|
|
|
//find the lowest unhandled index |
|
for( j=0; j<numPoints; j++ ) |
|
{ |
|
if( !bHandled[j] && m_ControlPoints[j]->GetPointIndex() < lowestValue ) |
|
{ |
|
lowestIndex = j; |
|
lowestValue = m_ControlPoints[j]->GetPointIndex(); |
|
} |
|
} |
|
|
|
//Don't examine this point again |
|
bHandled[lowestIndex] = true; |
|
|
|
//Give it its new index |
|
m_ControlPoints[lowestIndex]->SetPointIndex( newIndex ); |
|
newIndex++; |
|
} |
|
|
|
if( m_ControlPoints.Count() == 0 ) |
|
{ |
|
Warning( "Error! No control points found in map!\n"); |
|
return false; |
|
} |
|
|
|
// Now setup the objective resource |
|
ObjectiveResource()->SetNumControlPoints( m_ControlPoints.Count() ); |
|
for ( unsigned int i = 0; i < m_ControlPoints.Count(); i++ ) |
|
{ |
|
CTeamControlPoint *pPoint = m_ControlPoints[i]; |
|
|
|
int iPointIndex = m_ControlPoints[i]->GetPointIndex(); |
|
|
|
ObjectiveResource()->SetOwningTeam( iPointIndex, pPoint->GetOwner() ); |
|
ObjectiveResource()->SetCPVisible( iPointIndex, pPoint->PointIsVisible() ); |
|
ObjectiveResource()->SetCPPosition( iPointIndex, pPoint->GetAbsOrigin() ); |
|
ObjectiveResource()->SetWarnOnCap( iPointIndex, pPoint->GetWarnOnCap() ); |
|
ObjectiveResource()->SetWarnSound( iPointIndex, pPoint->GetWarnSound() ); |
|
ObjectiveResource()->SetCPGroup( iPointIndex, pPoint->GetCPGroup() ); |
|
for ( int team = 0; team < GetNumberOfTeams(); team++ ) |
|
{ |
|
ObjectiveResource()->SetCPIcons( iPointIndex, team, pPoint->GetHudIconIndexForTeam(team) ); |
|
ObjectiveResource()->SetCPOverlays( iPointIndex, team, pPoint->GetHudOverlayIndexForTeam(team) ); |
|
for ( int prevpoint = 0; prevpoint < MAX_PREVIOUS_POINTS; prevpoint++ ) |
|
{ |
|
ObjectiveResource()->SetPreviousPoint( iPointIndex, team, prevpoint, pPoint->GetPreviousPointForTeam(team, prevpoint) ); |
|
} |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::SetBaseControlPoints( void ) |
|
{ |
|
for ( int team = 0; team < GetNumberOfTeams(); team++ ) |
|
{ |
|
ObjectiveResource()->SetTeamBaseIcons( team, m_iTeamBaseIcons[team] ); |
|
ObjectiveResource()->SetBaseCP( GetBaseControlPoint(team), team ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTeamControlPointMaster::FindControlPointRounds( void ) |
|
{ |
|
bool bFoundRounds = false; |
|
|
|
m_ControlPointRounds.RemoveAll(); |
|
CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, GetControlPointRoundName() ); |
|
|
|
while( pEnt ) |
|
{ |
|
CTeamControlPointRound *pRound = assert_cast<CTeamControlPointRound *>( pEnt ); |
|
|
|
if( pRound && ( m_ControlPointRounds.Find( pRound ) == m_ControlPointRounds.InvalidIndex() ) ) |
|
{ |
|
DevMsg( 2, "**** Adding control point round %s to control point master\n", pRound->GetEntityName().ToCStr() ); |
|
m_ControlPointRounds.AddToHead( pRound ); |
|
} |
|
|
|
pEnt = gEntList.FindEntityByClassname( pEnt, GetControlPointRoundName() ); |
|
} |
|
|
|
if ( m_ControlPointRounds.Count() > 0 ) |
|
{ |
|
// sort them in our list by priority (highest priority first) |
|
m_ControlPointRounds.Sort( ControlPointRoundSort ); |
|
bFoundRounds = true; |
|
} |
|
|
|
if ( g_pObjectiveResource ) |
|
{ |
|
g_pObjectiveResource->SetPlayingMiniRounds( bFoundRounds ); |
|
g_pObjectiveResource->SetCapLayoutInHUD( STRING(m_iszCapLayoutInHUD) ); |
|
g_pObjectiveResource->SetCapLayoutCustomPosition( m_flCustomPositionX, m_flCustomPositionY ); |
|
} |
|
|
|
return bFoundRounds; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTeamControlPointMaster::IsInRound( CTeamControlPoint *pPoint ) |
|
{ |
|
// are we playing a round and is this point in the round? |
|
if ( m_ControlPointRounds.Count() > 0 && m_iCurrentRoundIndex != -1 ) |
|
{ |
|
return m_ControlPointRounds[m_iCurrentRoundIndex]->IsControlPointInRound( pPoint ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTeamControlPointMaster::NumPlayableControlPointRounds( void ) |
|
{ |
|
int nRetVal = 0; |
|
|
|
for ( int i = 0 ; i < m_ControlPointRounds.Count() ; ++i ) |
|
{ |
|
CTeamControlPointRound *pRound = m_ControlPointRounds[i]; |
|
|
|
if ( pRound ) |
|
{ |
|
if ( pRound->IsPlayable() ) |
|
{ |
|
// we found one that's playable |
|
nRetVal++; |
|
} |
|
} |
|
} |
|
|
|
return nRetVal; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTeamControlPointMaster::SelectSpecificRound( void ) |
|
{ |
|
CTeamControlPointRound *pRound = NULL; |
|
CTeamplayRoundBasedRules *pRules = dynamic_cast<CTeamplayRoundBasedRules*>( GameRules() ); |
|
|
|
if ( pRules ) |
|
{ |
|
if ( pRules->GetRoundToPlayNext() != NULL_STRING ) |
|
{ |
|
// do we have the name of a round? |
|
pRound = dynamic_cast<CTeamControlPointRound*>( gEntList.FindEntityByName( NULL, STRING( pRules->GetRoundToPlayNext() ) ) ); |
|
|
|
if ( pRound ) |
|
{ |
|
if ( ( m_ControlPointRounds.Find( pRound )== m_ControlPointRounds.InvalidIndex() ) || |
|
( !pRound->IsPlayable() && !pRound->MakePlayable() ) ) |
|
{ |
|
pRound = NULL; |
|
} |
|
} |
|
|
|
pRules->SetRoundToPlayNext( NULL_STRING ); |
|
} |
|
} |
|
|
|
// do we have a round to play? |
|
if ( pRound ) |
|
{ |
|
m_iCurrentRoundIndex = m_ControlPointRounds.Find( pRound ); |
|
m_ControlPointRounds[m_iCurrentRoundIndex]->SelectedToPlay(); |
|
|
|
if ( pRules ) |
|
{ |
|
pRules->SetRoundOverlayDetails(); |
|
} |
|
|
|
FireRoundStartOutput(); |
|
DevMsg( 2, "**** Selected round %s to play\n", m_ControlPointRounds[m_iCurrentRoundIndex]->GetEntityName().ToCStr() ); |
|
|
|
if ( !pRules->IsInWaitingForPlayers() ) |
|
{ |
|
UTIL_LogPrintf( "World triggered \"Mini_Round_Selected\" (round \"%s\")\n", m_ControlPointRounds[m_iCurrentRoundIndex]->GetEntityName().ToCStr() ); |
|
UTIL_LogPrintf( "World triggered \"Mini_Round_Start\"\n" ); |
|
} |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::RegisterRoundBeingPlayed( void ) |
|
{ |
|
// let the game rules know what round we're playing |
|
CTeamplayRoundBasedRules *pRules = dynamic_cast<CTeamplayRoundBasedRules*>( GameRules() ); |
|
if ( pRules ) |
|
{ |
|
string_t iszEntityName = m_ControlPointRounds[m_iCurrentRoundIndex]->GetEntityName(); |
|
|
|
pRules->AddPlayedRound( iszEntityName ); |
|
|
|
if ( m_bFirstRoundAfterRestart ) |
|
{ |
|
pRules->SetFirstRoundPlayed( iszEntityName ); |
|
m_bFirstRoundAfterRestart = false; |
|
} |
|
} |
|
|
|
IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_round_selected" ); |
|
if ( event ) |
|
{ |
|
event->SetString( "round", m_ControlPointRounds[m_iCurrentRoundIndex]->GetEntityName().ToCStr() ); |
|
gameeventmanager->FireEvent( event ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTeamControlPointMaster::GetControlPointRoundToPlay( void ) |
|
{ |
|
int i = 0; |
|
|
|
// are we trying to pick a specific round? |
|
if ( SelectSpecificRound() ) |
|
{ |
|
SetBaseControlPoints(); |
|
RegisterRoundBeingPlayed(); |
|
return true; |
|
} |
|
|
|
// rounds are sorted with the higher priority rounds first |
|
for ( i = 0 ; i < m_ControlPointRounds.Count() ; ++i ) |
|
{ |
|
CTeamControlPointRound *pRound = m_ControlPointRounds[i]; |
|
|
|
if ( pRound ) |
|
{ |
|
if ( pRound->IsPlayable() ) |
|
{ |
|
// we found one that's playable |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if ( i >= m_ControlPointRounds.Count() || m_ControlPointRounds[i] == NULL ) |
|
{ |
|
// we didn't find one to play |
|
m_iCurrentRoundIndex = -1; |
|
return false; |
|
} |
|
|
|
// we have a priority value, now we need to randomly pick a round with this priority that's playable |
|
int nPriority = m_ControlPointRounds[i]->GetPriorityValue(); |
|
CUtlVector<int> nRounds; |
|
|
|
CTeamplayRoundBasedRules *pRules = dynamic_cast<CTeamplayRoundBasedRules*>( GameRules() ); |
|
string_t iszLastRoundPlayed = pRules ? pRules->GetLastPlayedRound() : NULL_STRING; |
|
int iLastRoundPlayed = -1; |
|
|
|
string_t iszFirstRoundPlayed = pRules ? pRules->GetFirstRoundPlayed() : NULL_STRING; |
|
int iFirstRoundPlayed = -1; // after a full restart |
|
|
|
// loop through and find the rounds with this priority value |
|
for ( i = 0 ; i < m_ControlPointRounds.Count() ; ++i ) |
|
{ |
|
CTeamControlPointRound *pRound = m_ControlPointRounds[i]; |
|
|
|
if ( pRound ) |
|
{ |
|
string_t iszRoundName = pRound->GetEntityName(); |
|
|
|
if ( pRound->IsPlayable() && pRound->GetPriorityValue() == nPriority ) |
|
{ |
|
if ( iszLastRoundPlayed == iszRoundName ) // is this the last round we played? |
|
{ |
|
iLastRoundPlayed = i; |
|
} |
|
|
|
if ( m_bFirstRoundAfterRestart ) |
|
{ |
|
// is this the first round we played after the last full restart? |
|
if ( ( iszFirstRoundPlayed != NULL_STRING ) && ( iszFirstRoundPlayed == iszRoundName ) ) |
|
{ |
|
iFirstRoundPlayed = i; |
|
} |
|
} |
|
|
|
nRounds.AddToHead(i); |
|
} |
|
} |
|
} |
|
|
|
if ( nRounds.Count() <= 0 ) |
|
{ |
|
// we didn't find one to play |
|
m_iCurrentRoundIndex = -1; |
|
return false; |
|
} |
|
|
|
// if we have more than one and the last played round is in our list, remove it |
|
if ( nRounds.Count() > 1 ) |
|
{ |
|
if ( iLastRoundPlayed != -1 ) |
|
{ |
|
int elementIndex = nRounds.Find( iLastRoundPlayed ); |
|
nRounds.Remove( elementIndex ); |
|
} |
|
} |
|
|
|
// if this is the first round after a full restart, we still have more than one round in our list, |
|
// and the first played round (after the last full restart) is in our list, remove it |
|
if ( m_bFirstRoundAfterRestart ) |
|
{ |
|
if ( nRounds.Count() > 1 ) |
|
{ |
|
if ( iFirstRoundPlayed != -1 ) |
|
{ |
|
int elementIndex = nRounds.Find( iFirstRoundPlayed ); |
|
nRounds.Remove( elementIndex ); |
|
} |
|
} |
|
} |
|
|
|
// pick one to play but try to avoid picking one that we have recently played if there are other rounds to play |
|
int index = random->RandomInt( 0, nRounds.Count() - 1 ); |
|
|
|
// only need to check this if we have more than one round with this priority value |
|
if ( pRules && nRounds.Count() > 1 ) |
|
{ |
|
// keep picking a round until we find one that's not a previously played round |
|
// or until we don't have any more rounds to choose from |
|
while ( pRules->IsPreviouslyPlayedRound( m_ControlPointRounds[ nRounds[ index ] ]->GetEntityName() ) && |
|
nRounds.Count() > 1 ) |
|
{ |
|
nRounds.Remove( index ); // we have played this round recently so get it out of the list |
|
index = random->RandomInt( 0, nRounds.Count() - 1 ); |
|
} |
|
} |
|
|
|
// pick one to play and fire its OnSelected output |
|
m_iCurrentRoundIndex = nRounds[ index ]; |
|
m_ControlPointRounds[m_iCurrentRoundIndex]->SelectedToPlay(); |
|
|
|
if ( pRules ) |
|
{ |
|
pRules->SetRoundOverlayDetails(); |
|
} |
|
|
|
FireRoundStartOutput(); |
|
DevMsg( 2, "**** Selected round %s to play\n", m_ControlPointRounds[m_iCurrentRoundIndex]->GetEntityName().ToCStr() ); |
|
|
|
if ( !pRules->IsInWaitingForPlayers() ) |
|
{ |
|
UTIL_LogPrintf( "World triggered \"Mini_Round_Selected\" (round \"%s\")\n", m_ControlPointRounds[m_iCurrentRoundIndex]->GetEntityName().ToCStr() ); |
|
UTIL_LogPrintf( "World triggered \"Mini_Round_Start\"\n" ); |
|
} |
|
|
|
SetBaseControlPoints(); |
|
RegisterRoundBeingPlayed(); |
|
|
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called every 0.1 seconds and checks the status of all the control points |
|
// if one team owns them all, it gives points and resets |
|
// Think also gives the time based points at the specified time intervals |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::CPMThink( void ) |
|
{ |
|
if ( m_bDisabled || !TeamplayGameRules()->PointsMayBeCaptured() ) |
|
{ |
|
SetContextThink( &CTeamControlPointMaster::CPMThink, gpGlobals->curtime + 0.2, CPM_THINK ); |
|
return; |
|
} |
|
|
|
// If we call this from team_control_point, this function should never |
|
// trigger a win. but we'll leave it here just in case. |
|
CheckWinConditions(); |
|
|
|
// the next time we 'think' |
|
SetContextThink( &CTeamControlPointMaster::CPMThink, gpGlobals->curtime + 0.2, CPM_THINK ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::CheckWinConditions( void ) |
|
{ |
|
if ( m_bDisabled ) |
|
return; |
|
|
|
if ( m_ControlPointRounds.Count() > 0 ) |
|
{ |
|
if ( m_iCurrentRoundIndex != -1 ) |
|
{ |
|
// Check the current round to see if one team is a winner yet |
|
int iWinners = m_ControlPointRounds[m_iCurrentRoundIndex]->CheckWinConditions(); |
|
if ( iWinners != -1 && iWinners >= FIRST_GAME_TEAM ) |
|
{ |
|
bool bForceMapReset = ( NumPlayableControlPointRounds() == 0 ); // are there any more rounds to play? |
|
|
|
if ( !bForceMapReset ) |
|
{ |
|
// we have more rounds to play |
|
TeamplayGameRules()->SetWinningTeam( iWinners, WINREASON_ALL_POINTS_CAPTURED, bForceMapReset ); |
|
} |
|
else |
|
{ |
|
// we have played all of the available rounds |
|
TeamplayGameRules()->SetWinningTeam( iWinners, WINREASON_ALL_POINTS_CAPTURED, bForceMapReset, m_bSwitchTeamsOnWin ); |
|
} |
|
|
|
FireTeamWinOutput( iWinners ); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
// 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 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 ) |
|
{ |
|
TeamplayGameRules()->SetWinningTeam( iWinners, WINREASON_ALL_POINTS_CAPTURED, true, m_bSwitchTeamsOnWin ); |
|
FireTeamWinOutput( iWinners ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::InputSetWinner( inputdata_t &input ) |
|
{ |
|
int iTeam = input.value.Int(); |
|
InternalSetWinner( iTeam ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::InputSetWinnerAndForceCaps( inputdata_t &input ) |
|
{ |
|
int iTeam = input.value.Int(); |
|
|
|
// Set all cap points in the current round to be owned by the winning team |
|
for ( unsigned int i = 0; i < m_ControlPoints.Count(); i++ ) |
|
{ |
|
CTeamControlPoint *pPoint = m_ControlPoints[i]; |
|
if ( pPoint && (!PlayingMiniRounds() || ObjectiveResource()->IsInMiniRound(pPoint->GetPointIndex()) ) ) |
|
{ |
|
pPoint->ForceOwner( iTeam ); |
|
} |
|
} |
|
|
|
InternalSetWinner( iTeam ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::InternalSetWinner( int iTeam ) |
|
{ |
|
bool bForceMapReset = true; |
|
|
|
if ( m_ControlPointRounds.Count() > 0 ) |
|
{ |
|
// if we're playing rounds and there are more to play, don't do a full reset |
|
bForceMapReset = ( NumPlayableControlPointRounds() == 0 ); |
|
} |
|
|
|
if ( iTeam == TEAM_UNASSIGNED ) |
|
{ |
|
TeamplayGameRules()->SetStalemate( STALEMATE_TIMER, bForceMapReset ); |
|
} |
|
else |
|
{ |
|
if ( !bForceMapReset ) |
|
{ |
|
TeamplayGameRules()->SetWinningTeam( iTeam, WINREASON_ALL_POINTS_CAPTURED, bForceMapReset ); |
|
} |
|
else |
|
{ |
|
TeamplayGameRules()->SetWinningTeam( iTeam, WINREASON_ALL_POINTS_CAPTURED, bForceMapReset, m_bSwitchTeamsOnWin ); |
|
} |
|
|
|
FireTeamWinOutput( iTeam ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::HandleRandomOwnerControlPoints( void ) |
|
{ |
|
CUtlVector<CTeamControlPoint*> vecPoints; |
|
CUtlVector<int> vecTeams; |
|
|
|
int i = 0; |
|
|
|
// loop through and find all of the points that want random owners after a full restart |
|
for ( i = 0 ; i < (int)m_ControlPoints.Count() ; i++ ) |
|
{ |
|
CTeamControlPoint *pPoint = m_ControlPoints[i]; |
|
|
|
if ( pPoint && pPoint->RandomOwnerOnRestart() ) |
|
{ |
|
vecPoints.AddToHead( pPoint ); |
|
vecTeams.AddToHead( pPoint->GetTeamNumber() ); |
|
} |
|
} |
|
|
|
// now loop through and mix up the owners (if we found any points with this flag set) |
|
for ( i = 0 ; i < vecPoints.Count() ; i++ ) |
|
{ |
|
CTeamControlPoint *pPoint = vecPoints[i]; |
|
|
|
if ( pPoint ) |
|
{ |
|
int index = random->RandomInt( 0, vecTeams.Count() - 1 ); |
|
pPoint->ForceOwner( vecTeams[index] ); |
|
|
|
vecTeams.Remove( index ); |
|
} |
|
} |
|
|
|
vecPoints.RemoveAll(); |
|
vecTeams.RemoveAll(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::InputRoundSpawn( inputdata_t &input ) |
|
{ |
|
//clear out old control points |
|
m_ControlPoints.RemoveAll(); |
|
|
|
//find the control points, and if successful, do CPMThink |
|
if ( FindControlPoints() ) |
|
{ |
|
/* if ( m_bFirstRoundAfterRestart ) |
|
{ |
|
CTeamplayRoundBasedRules *pRules = dynamic_cast<CTeamplayRoundBasedRules*>( GameRules() ); |
|
if ( pRules && ( pRules->GetRoundToPlayNext() == NULL_STRING ) ) |
|
{ |
|
// we only want to handle the random points if we don't have a specific round to play next |
|
// (prevents points being randomized again after "waiting for players" has finished and we're going to play the same round) |
|
HandleRandomOwnerControlPoints(); |
|
} |
|
} |
|
*/ |
|
SetContextThink( &CTeamControlPointMaster::CPMThink, gpGlobals->curtime + 0.1, CPM_THINK ); |
|
} |
|
|
|
// clear out the old rounds |
|
m_ControlPointRounds.RemoveAll(); |
|
|
|
// find the rounds (if the map has any) |
|
FindControlPointRounds(); |
|
|
|
SetBaseControlPoints(); |
|
|
|
ObjectiveResource()->ResetControlPoints(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::InputRoundActivate( inputdata_t &input ) |
|
{ |
|
// if we're using mini-rounds and haven't picked one yet, find one to play |
|
if ( PlayingMiniRounds() && GetCurrentRound() == NULL ) |
|
{ |
|
GetControlPointRoundToPlay(); |
|
} |
|
|
|
if ( PlayingMiniRounds() ) |
|
{ |
|
// Tell the objective resource what control points are in use in the selected mini-round |
|
CTeamControlPointRound *pRound = GetCurrentRound(); |
|
if ( pRound ) |
|
{ |
|
for ( unsigned int i = 0; i < m_ControlPoints.Count(); i++ ) |
|
{ |
|
CTeamControlPoint *pPoint = m_ControlPoints[i]; |
|
if ( pPoint ) |
|
{ |
|
ObjectiveResource()->SetInMiniRound( pPoint->GetPointIndex(), pRound->IsControlPointInRound( pPoint ) ); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::InputSetCapLayout( inputdata_t &inputdata ) |
|
{ |
|
m_iszCapLayoutInHUD = inputdata.value.StringID(); |
|
g_pObjectiveResource->SetCapLayoutInHUD( STRING(m_iszCapLayoutInHUD) ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::InputSetCapLayoutCustomPositionX( inputdata_t &inputdata ) |
|
{ |
|
m_flCustomPositionX = inputdata.value.Float(); |
|
g_pObjectiveResource->SetCapLayoutCustomPosition( m_flCustomPositionX, m_flCustomPositionY ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::InputSetCapLayoutCustomPositionY( inputdata_t &inputdata ) |
|
{ |
|
m_flCustomPositionY = inputdata.value.Float(); |
|
g_pObjectiveResource->SetCapLayoutCustomPosition( m_flCustomPositionX, m_flCustomPositionY ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::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: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::FireRoundStartOutput( void ) |
|
{ |
|
CTeamControlPointRound *pRound = GetCurrentRound(); |
|
|
|
if ( pRound ) |
|
{ |
|
pRound->FireOnStartOutput(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::FireRoundEndOutput( void ) |
|
{ |
|
CTeamControlPointRound *pRound = GetCurrentRound(); |
|
|
|
if ( pRound ) |
|
{ |
|
pRound->FireOnEndOutput(); |
|
m_iCurrentRoundIndex = -1; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
float CTeamControlPointMaster::PointLastContestedAt( int point ) |
|
{ |
|
CTeamControlPoint *pPoint = GetControlPoint(point); |
|
if ( pPoint ) |
|
return pPoint->LastContestedAt(); |
|
|
|
return -1; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// 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. |
|
// CPs are broken into groups. A team can win by owning all flags within a single group. |
|
// |
|
// 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 CTeamControlPointMaster::TeamOwnsAllPoints( CTeamControlPoint *pOverridePoint /* = NULL */, int iOverrideNewTeam /* = TEAM_UNASSIGNED */ ) |
|
{ |
|
unsigned 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 CTeamControlPointMaster::WouldNewCPOwnerWinGame( CTeamControlPoint *pPoint, int iNewOwner ) |
|
{ |
|
return ( TeamOwnsAllPoints( pPoint, iNewOwner ) == iNewOwner ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTeamControlPointMaster::IsBaseControlPoint( int iPointIndex ) |
|
{ |
|
bool retVal = false; |
|
|
|
for ( int iTeam = LAST_SHARED_TEAM+1; iTeam < GetNumberOfTeams(); iTeam++ ) |
|
{ |
|
if ( GetBaseControlPoint( iTeam ) == iPointIndex ) |
|
{ |
|
retVal = true; |
|
break; |
|
} |
|
} |
|
|
|
return retVal; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Get the control point for the specified team that's at their end of |
|
// the control point chain. |
|
//----------------------------------------------------------------------------- |
|
int CTeamControlPointMaster::GetBaseControlPoint( int iTeam ) |
|
{ |
|
int iRetVal = -1; |
|
int nLowestValue = 999, nHighestValue = -1; |
|
int iLowestIndex = 0, iHighestIndex = 0; |
|
|
|
for( int i = 0 ; i < (int)m_ControlPoints.Count() ; i++ ) |
|
{ |
|
CTeamControlPoint *pPoint = m_ControlPoints[i]; |
|
|
|
int iPointIndex = m_ControlPoints[i]->GetPointIndex(); |
|
|
|
if ( PlayingMiniRounds() && iTeam > LAST_SHARED_TEAM ) |
|
{ |
|
if ( IsInRound( pPoint ) ) // is this point in the current round? |
|
{ |
|
if ( iPointIndex > nHighestValue ) |
|
{ |
|
nHighestValue = iPointIndex; |
|
iHighestIndex = i; |
|
} |
|
|
|
if ( iPointIndex < nLowestValue ) |
|
{ |
|
nLowestValue = iPointIndex; |
|
iLowestIndex = i; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
if ( pPoint->GetDefaultOwner() != iTeam ) |
|
{ |
|
continue; |
|
} |
|
|
|
// If it's the first or the last point, it's their base |
|
if ( iPointIndex == 0 || iPointIndex == (((int)m_ControlPoints.Count())-1) ) |
|
{ |
|
iRetVal = iPointIndex; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if ( PlayingMiniRounds() && iTeam > LAST_SHARED_TEAM ) |
|
{ |
|
if ( nLowestValue != 999 && nHighestValue != -1 ) |
|
{ |
|
CTeamControlPoint *pLowestPoint = m_ControlPoints[iLowestIndex]; |
|
CTeamControlPoint *pHighestPoint = m_ControlPoints[iHighestIndex]; |
|
|
|
// which point is owned by this team? |
|
if ( ( pLowestPoint->GetDefaultOwner() == iTeam && pHighestPoint->GetDefaultOwner() == iTeam ) || // if the same team owns both, take the highest value to be the last point |
|
( pHighestPoint->GetDefaultOwner() == iTeam ) ) |
|
{ |
|
iRetVal = nHighestValue; |
|
} |
|
else if ( pLowestPoint->GetDefaultOwner() == iTeam ) |
|
{ |
|
iRetVal = nLowestValue; |
|
} |
|
} |
|
} |
|
|
|
return iRetVal; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::InputEnable( inputdata_t &input ) |
|
{ |
|
m_bDisabled = false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::InputDisable( inputdata_t &input ) |
|
{ |
|
m_bDisabled = true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTeamControlPointMaster::GetNumPointsOwnedByTeam( int iTeam ) |
|
{ |
|
int nCount = 0; |
|
|
|
for( int i = 0 ; i < (int)m_ControlPoints.Count() ; i++ ) |
|
{ |
|
CTeamControlPoint *pPoint = m_ControlPoints[i]; |
|
|
|
if ( pPoint && ( pPoint->GetTeamNumber() == iTeam ) ) |
|
{ |
|
nCount++; |
|
} |
|
} |
|
|
|
return nCount; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: returns how many more mini-rounds it will take for specified team |
|
// to win, if they keep winning every mini-round |
|
//----------------------------------------------------------------------------- |
|
int CTeamControlPointMaster::CalcNumRoundsRemaining( int iTeam ) |
|
{ |
|
// To determine how many rounds remain for a given team if it consistently wins mini-rounds, we have to |
|
// simulate forward each mini-round and track the control point ownership that would result |
|
|
|
// vector of control points the team owns in our forward-simulation |
|
CUtlVector<CTeamControlPoint *> vecControlPointsOwned; |
|
|
|
// start with all the control points the team currently owns |
|
FOR_EACH_MAP_FAST( m_ControlPoints, iControlPoint ) |
|
{ |
|
if ( m_ControlPoints[iControlPoint]->GetOwner() == iTeam ) |
|
{ |
|
vecControlPointsOwned.AddToTail( m_ControlPoints[iControlPoint] ); |
|
} |
|
} |
|
|
|
int iRoundsRemaining = 0; |
|
|
|
// keep simulating what will happen next if this team keeps winning, until |
|
// it owns all the control points in the map |
|
while ( vecControlPointsOwned.Count() < (int) m_ControlPoints.Count() ) |
|
{ |
|
iRoundsRemaining++; |
|
|
|
// choose the next highest-priority round that is playable |
|
for ( int i = 0 ; i < m_ControlPointRounds.Count() ; ++i ) |
|
{ |
|
CTeamControlPointRound *pRound = m_ControlPointRounds[i]; |
|
if ( !pRound ) |
|
continue; |
|
|
|
// see if one team owns all control points in this round |
|
int iRoundOwningTeam = TEAM_INVALID; |
|
int iControlPoint; |
|
for ( iControlPoint = 0; iControlPoint < pRound->m_ControlPoints.Count(); iControlPoint++ ) |
|
{ |
|
CTeamControlPoint *pControlPoint = pRound->m_ControlPoints[iControlPoint]; |
|
int iControlPointOwningTeam = TEAM_INVALID; |
|
|
|
// determine who owns this control point. |
|
// First, check our simulated ownership |
|
if ( vecControlPointsOwned.InvalidIndex() != vecControlPointsOwned.Find( pControlPoint ) ) |
|
{ |
|
// This team has won this control point in forward simulation |
|
iControlPointOwningTeam = iTeam; |
|
} |
|
else |
|
{ |
|
// use actual control point ownership |
|
iControlPointOwningTeam = pControlPoint->GetOwner(); |
|
} |
|
|
|
if ( 0 == iControlPoint ) |
|
{ |
|
// if this is the first control point, assign ownership to the team that owns this control point |
|
iRoundOwningTeam = iControlPointOwningTeam; |
|
} |
|
else |
|
{ |
|
// for all other control points, if the control point ownership does not match other control points, reset |
|
// round ownership to no team |
|
if ( iRoundOwningTeam != iControlPointOwningTeam ) |
|
{ |
|
iRoundOwningTeam = TEAM_INVALID; |
|
} |
|
} |
|
} |
|
// this round is playable if all control points are not owned by one team (or owned by a team that can't win by capping them) |
|
bool bPlayable = ( ( iRoundOwningTeam < FIRST_GAME_TEAM ) || ( pRound->GetInvalidCapWinner() == 1 ) || ( iRoundOwningTeam == pRound->GetInvalidCapWinner() ) ); |
|
if ( !bPlayable ) |
|
continue; |
|
|
|
// Pretend this team played and won this round. It now owns all control points from this round. Add all the |
|
// control points from this round that are not already own the owned list to the owned list |
|
int iNewControlPointsOwned = 0; |
|
FOR_EACH_VEC( pRound->m_ControlPoints, iControlPoint ) |
|
{ |
|
CTeamControlPoint *pControlPoint = pRound->m_ControlPoints[iControlPoint]; |
|
if ( vecControlPointsOwned.InvalidIndex() == vecControlPointsOwned.Find( pControlPoint ) ) |
|
{ |
|
vecControlPointsOwned.AddToTail( pControlPoint ); |
|
iNewControlPointsOwned++; |
|
} |
|
} |
|
// sanity check: team being simulated should be owning at least one more new control point per round, or they're not making progress |
|
Assert( iNewControlPointsOwned > 0 ); |
|
|
|
// now go back and pick the next playable round (if any) given the control points this team now owns, |
|
// repeat until all control points are owned. The number of iterations it takes is the # of rounds remaining |
|
// for this team to win. |
|
break; |
|
} |
|
} |
|
|
|
return iRoundsRemaining; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
float CTeamControlPointMaster::GetPartialCapturePointRate( void ) |
|
{ |
|
return m_flPartialCapturePointsRate; |
|
} |
|
|
|
/* |
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPointMaster::ListRounds( void ) |
|
{ |
|
if ( PlayingMiniRounds() ) |
|
{ |
|
ConMsg( "Rounds in this map:\n\n" ); |
|
|
|
for ( int i = 0; i < m_ControlPointRounds.Count() ; ++i ) |
|
{ |
|
CTeamControlPointRound* pRound = m_ControlPointRounds[i]; |
|
|
|
if ( pRound ) |
|
{ |
|
const char *pszName = STRING( pRound->GetEntityName() ); |
|
ConMsg( "%s\n", pszName ); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
ConMsg( "* No rounds in this map *\n" ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void cc_ListRounds( void ) |
|
{ |
|
CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL; |
|
if ( pMaster ) |
|
{ |
|
pMaster->ListRounds(); |
|
} |
|
} |
|
|
|
static ConCommand listrounds( "listrounds", cc_ListRounds, "List the rounds for the current map", FCVAR_CHEAT ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void cc_PlayRound( const CCommand& args ) |
|
{ |
|
if ( args.ArgC() > 1 ) |
|
{ |
|
CTeamplayRoundBasedRules *pRules = dynamic_cast<CTeamplayRoundBasedRules*>( GameRules() ); |
|
CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL; |
|
|
|
if ( pRules && pMaster ) |
|
{ |
|
if ( pMaster->PlayingMiniRounds() ) |
|
{ |
|
// did we get the name of a round? |
|
CTeamControlPointRound *pRound = dynamic_cast<CTeamControlPointRound*>( gEntList.FindEntityByName( NULL, args[1] ) ); |
|
|
|
if ( pRound ) |
|
{ |
|
pRules->SetRoundToPlayNext( pRound->GetEntityName() ); |
|
mp_restartgame.SetValue( 5 ); |
|
} |
|
else |
|
{ |
|
ConMsg( "* Round \"%s\" not found in this map *\n", args[1] ); |
|
} |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
ConMsg( "Usage: playround < round name >\n" ); |
|
} |
|
} |
|
|
|
static ConCommand playround( "playround", cc_PlayRound, "Play the selected round\n\tArgument: {round name given by \"listrounds\" command}", FCVAR_CHEAT ); |
|
*/ |