//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "cbase.h" #include "dod_control_point_master.h" BEGIN_DATADESC( CControlPointMaster ) DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "StartDisabled" ), DEFINE_KEYFIELD( m_iTimerLength, FIELD_INTEGER, "cpm_timer_length" ), DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), DEFINE_INPUTFUNC( FIELD_VOID, "RoundInit", InputRoundInit ), DEFINE_FUNCTION( CPMThink ), DEFINE_OUTPUT( m_AlliesWinOutput, "OnAlliesWin" ), DEFINE_OUTPUT( m_AxisWinOutput, "OnAxisWin" ), DEFINE_INPUTFUNC( FIELD_INTEGER, "AddTimerSeconds", InputAddTimerSeconds ), END_DATADESC() LINK_ENTITY_TO_CLASS( dod_control_point_master, CControlPointMaster ); CControlPointMaster::CControlPointMaster() { m_bUseTimer = false; m_iTimerTeam = TEAM_UNASSIGNED; SetDefLessFunc( m_ControlPoints ); } void CControlPointMaster::Spawn( void ) { SetTouch( NULL ); m_bFoundPoints = false; BaseClass::Spawn(); } ConVar mp_tickpointinterval( "mp_tickpointinterval", "30", FCVAR_GAMEDLL, "Delay between point gives.", true, 1, false, 0 ); void CControlPointMaster::RoundRespawn( void ) { m_fGivePointsTime = gpGlobals->curtime + mp_tickpointinterval.GetInt(); } // KeyValue // ======== // this function interfaces with the keyvalues set by the mapper // // Values // point_give_delay_time - how often to give time based points ( seconds ) // allies_capture_target - target to fire on allies complete capture // axis_capture_target - target to fire on axis complete capture bool CControlPointMaster::KeyValue( const char *szKeyName, const char *szValue ) { if (FStrEq(szKeyName, "cpm_use_timer")) { m_bUseTimer = ( atoi(szValue) > 0 ); } else if (FStrEq(szKeyName, "cpm_timer_team")) { m_iTimerTeam = atoi(szValue); } else { return CBaseEntity::KeyValue( szKeyName, szValue ); } return true; } void CControlPointMaster::Reset( void ) { } bool CControlPointMaster::FindControlPoints( void ) { //go through all the points CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "dod_control_point" ); int numFound = 0; while( pEnt ) { CControlPoint *pPoint = (CControlPoint *)pEnt; if( pPoint->IsActive() ) { int index = pPoint->GetPointIndex(); Assert( index >= 0 ); if( m_ControlPoints.Find( index ) == m_ControlPoints.InvalidIndex()) { DevMsg( 2, "Adding control point %s with index %d\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, "dod_control_point" ); } 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; jGetPointIndex() < lowestValue ) { lowestIndex = j; lowestValue = m_ControlPoints[j]->GetPointIndex(); } } //Don't examine this point again Assert( lowestIndex >= 0 ); 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; } g_pObjectiveResource->SetNumControlPoints( m_ControlPoints.Count() ); unsigned int i; for( i=0;iGetPointIndex(); g_pObjectiveResource->SetOwningTeam( iPointIndex, pPoint->GetOwner() ); g_pObjectiveResource->SetCPVisible( iPointIndex, pPoint->PointIsVisible() ); g_pObjectiveResource->SetCPPosition( iPointIndex, pPoint->GetAbsOrigin() ); g_pObjectiveResource->SetBombsRequired( iPointIndex, pPoint->GetBombsRequired() ); g_pObjectiveResource->SetBombsRemaining( iPointIndex, pPoint->GetBombsRemaining() ); g_pObjectiveResource->SetCPIcons( iPointIndex, pPoint->GetHudIconIndexForTeam(TEAM_ALLIES), pPoint->GetHudIconIndexForTeam(TEAM_AXIS), pPoint->GetHudIconIndexForTeam(TEAM_UNASSIGNED), pPoint->GetTimerCapHudIcon(), pPoint->GetBombedHudIcon() ); } return true; } // Think // ===== // Think is 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 // // I moved the search for spawn points to the initial think - sometimes the points spawned // after the master and it wasnt finding them. void CControlPointMaster::CPMThink( void ) { // search for all "dod_control_point" entities in the map // and put them in the array // only done the first Think //try to establish if any dod_area_capture ents are linked to our flags //via dod_point_relay //if there exists a point relay that has this as the target, //AND there exists a capture area that has that relay as a target //then we have our area! //every think //go through all the control points and make sure theyre the same as the last think //check masters //if they are, do nothing //else // //Note! Only one cpm should ever be active at the same time //funny things may happen if there are two of em! //if we are recently mastered on or off, touch the cps //--------------------------------------------------------------------------- //below here we shouldn't execute unless we are an active control point master //if the round has been decided, don't do any more thinking //if this cpm is not active, dont' do any thinking int iRoundState = DODGameRules()->State_Get(); // No points or triggering new wins if we are not active if( m_bDisabled || iRoundState != STATE_RND_RUNNING ) { SetContextThink( &CControlPointMaster::CPMThink, gpGlobals->curtime + 0.2, FLAGS_CONTEXT ); return; } // is it time to give time-based points yet? if( gpGlobals->curtime > m_fGivePointsTime ) { int AlliesPoints = 0; int AxisPoints = 0; //give points based on who owns what unsigned int i; for( i=0;iGetOwner() ) { case TEAM_ALLIES: AlliesPoints += m_ControlPoints[i]->PointValue(); break; case TEAM_AXIS: AxisPoints += m_ControlPoints[i]->PointValue(); break; default: break; } } //================ //give team points //================ // See if there are players active on these teams bool bFoundAllies = ( GetGlobalTeam(TEAM_ALLIES)->GetNumPlayers() > 0 ); bool bFoundAxis = ( GetGlobalTeam(TEAM_AXIS)->GetNumPlayers() > 0 ); bool bReportScore = true; // don't give team points to a team with no-one on it! if( AlliesPoints > 0 && bFoundAllies && DODGameRules()->State_Get() == STATE_RND_RUNNING ) { if( bReportScore ) { if (AlliesPoints == 1) UTIL_ClientPrintAll( HUD_PRINTTALK, "#game_score_allie_point" ); else { char buf[8]; Q_snprintf( buf, sizeof(buf), "%d", AlliesPoints ); UTIL_ClientPrintAll( HUD_PRINTTALK, "#game_score_allie_points", buf ); } } GetGlobalTeam(TEAM_ALLIES)->AddScore( AlliesPoints ); IGameEvent *event = gameeventmanager->CreateEvent( "dod_tick_points" ); if ( event ) { event->SetInt( "team", TEAM_ALLIES ); event->SetInt( "score", AlliesPoints ); event->SetInt( "totalscore", GetGlobalTeam(TEAM_ALLIES)->GetScore() ); gameeventmanager->FireEvent( event ); } } if( AxisPoints > 0 && bFoundAxis && DODGameRules()->State_Get() == STATE_RND_RUNNING ) { if( bReportScore ) { if (AxisPoints == 1) UTIL_ClientPrintAll( HUD_PRINTTALK, "#game_score_axis_point" ); else { char buf[8]; Q_snprintf( buf, sizeof(buf), "%d", AxisPoints ); UTIL_ClientPrintAll( HUD_PRINTTALK, "#game_score_axis_points", buf ); } } GetGlobalTeam(TEAM_AXIS)->AddScore( AxisPoints ); IGameEvent *event = gameeventmanager->CreateEvent( "dod_tick_points" ); if ( event ) { event->SetInt( "team", TEAM_AXIS ); event->SetInt( "score", AxisPoints ); event->SetInt( "totalscore", GetGlobalTeam(TEAM_AXIS)->GetScore() ); gameeventmanager->FireEvent( event ); } } // the next time we'll give points m_fGivePointsTime = gpGlobals->curtime + mp_tickpointinterval.GetInt(); } // If we call this from dod_control_point, this function should never // trigger a win. but we'll leave it here just incase. CheckWinConditions(); // the next time we 'think' SetContextThink( &CControlPointMaster::CPMThink, gpGlobals->curtime + 0.2, FLAGS_CONTEXT ); } void CControlPointMaster::CheckWinConditions( void ) { // ============ // 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 // ============ switch( TeamOwnsAllPoints() ) { case TEAM_ALLIES: //allies own all { TeamWins( TEAM_ALLIES ); } break; case TEAM_AXIS: //axis owns all { TeamWins( TEAM_AXIS ); } break; default: break; } } void CControlPointMaster::InputRoundInit( inputdata_t &input ) { //clear out old control points m_ControlPoints.RemoveAll(); //find the control points //if successful, do CPMThink if( FindControlPoints() ) { SetContextThink( &CControlPointMaster::CPMThink, gpGlobals->curtime + 0.1, FLAGS_CONTEXT ); } //init the ClientAreas int index = 0; CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "dod_capture_area" ); while( pEnt ) { CAreaCapture *pArea = (CAreaCapture *)pEnt; Assert( pArea ); pArea->area_SetIndex( index ); index++; pEnt = gEntList.FindEntityByClassname( pEnt, "dod_capture_area" ); } g_pObjectiveResource->ResetControlPoints(); } void CControlPointMaster::FireTeamWinOutput( int iWinningTeam ) { switch( iWinningTeam ) { case TEAM_ALLIES: m_AlliesWinOutput.FireOutput(this,this); break; case TEAM_AXIS: m_AxisWinOutput.FireOutput(this,this); break; default: Assert(0); break; } } void CControlPointMaster::TeamWins( int iWinningTeam ) { DODGameRules()->SetWinningTeam( iWinningTeam ); FireTeamWinOutput( iWinningTeam ); } void CControlPointMaster::BecomeActive( void ) { Assert( m_bDisabled ); m_bDisabled = false; } void CControlPointMaster::BecomeInactive( void ) { Assert( !m_bDisabled ); m_bDisabled = true; } int CControlPointMaster::GetPointOwner( int point ) { Assert( point >= 0 ); Assert( point < MAX_CONTROL_POINTS ); CControlPoint *pPoint = m_ControlPoints[point]; if( pPoint ) { return pPoint->GetOwner(); } else return TEAM_UNASSIGNED; } // TeamOwnsAllPoints // ================= // 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 // New - cps are now 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 CControlPointMaster::TeamOwnsAllPoints( CControlPoint *pOverridePoint /* = NULL */, int iOverrideNewTeam /* = TEAM_UNASSIGNED */ ) { unsigned int i; int iWinningTeam[MAX_CONTROL_POINT_GROUPS]; for( i=0;iGetCPGroup(); 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;iGetOwner() != pPoint->GetDefaultOwner() ) { if ( pPoint->GetOwner() == team ) { // we own a flag we didn't initially numFlags++; } else // { // the enemy owns one of our flags numFlags--; } } } return numFlags; } void CControlPointMaster::InputAddTimerSeconds( inputdata_t &inputdata ) { DODGameRules()->AddTimerSeconds( inputdata.value.Int() ); } void CControlPointMaster::GetTimerData( int &iTimerSeconds, int &iTimerWinTeam ) { iTimerSeconds = m_iTimerLength; iTimerWinTeam = m_iTimerTeam; } bool CControlPointMaster::WouldNewCPOwnerWinGame( CControlPoint *pPoint, int iNewOwner ) { return ( TeamOwnsAllPoints( pPoint, iNewOwner ) == iNewOwner ); } int CControlPointMaster::GetNumPoints( void ) { return m_ControlPoints.Count(); } CControlPoint *CControlPointMaster::GetCPByIndex( int index ) { CControlPoint *pPoint = NULL; if ( index >= 0 && index < (int)m_ControlPoints.Count() ) { pPoint = m_ControlPoints[index]; } return pPoint; } // custom scoring entity BEGIN_DATADESC( CDODCustomScoring ) DEFINE_INPUTFUNC( FIELD_INTEGER, "GiveTickPoints", InputGivePoints ), DEFINE_KEYFIELD( m_iPointTeam, FIELD_INTEGER, "TeamNum" ), DEFINE_KEYFIELD( m_iTickLength, FIELD_INTEGER, "point_give_delay" ), DEFINE_KEYFIELD( m_iPointsToGive, FIELD_INTEGER, "point_give_amount" ), DEFINE_KEYFIELD( m_iNumPointGives, FIELD_INTEGER, "point_give_max_times" ), DEFINE_THINKFUNC( PointsThink ), END_DATADESC() LINK_ENTITY_TO_CLASS( dod_scoring, CDODCustomScoring );