void CTeamTrainWatcher::InternalSetNumTrainCappers( int iNumCappers, CBaseEntity *pTrigger ) { if ( IsDisabled() ) return; m_nNumCappers = iNumCappers; // inputdata.pCaller is hopefully an area capture // lets see if its blocked, and not start receding if it is CTriggerAreaCapture *pAreaCap = dynamic_cast<CTriggerAreaCapture *>( pTrigger ); if ( pAreaCap ) { m_bCapBlocked = pAreaCap->IsBlocked(); m_hAreaCap = pAreaCap; } if ( iNumCappers <= 0 && !m_bCapBlocked && m_bTrainCanRecede ) { if ( !m_bWaitingToRecede ) { // start receding in [tf_escort_cart_recede_time] seconds m_bWaitingToRecede = true; if ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->InOvertime() ) { m_flRecedeTotalTime = tf_escort_recede_time_overtime.GetFloat(); } else { m_flRecedeTotalTime = tf_escort_recede_time.GetFloat(); if ( m_nTrainRecedeTime > 0 ) { m_flRecedeTotalTime = m_nTrainRecedeTime; } } m_flRecedeStartTime = gpGlobals->curtime; m_flRecedeTime = m_flRecedeStartTime + m_flRecedeTotalTime; } } else { // cancel receding m_bWaitingToRecede = false; m_flRecedeTime = 0; } HandleTrainMovement(); }
//----------------------------------------------------------------------------- // 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: //----------------------------------------------------------------------------- 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; }
// ========================================================== // given a start node and a list of goal nodes // calculate the distance between each // ========================================================== void CTeamTrainWatcher::WatcherActivate( void ) { m_flRecedeTime = 0; m_bWaitingToRecede = false; m_bCapBlocked = false; m_flNextSpeakForwardConceptTime = 0; m_hAreaCap = NULL; m_flTrainDistanceFromStart = 0.0f; m_bAlarmPlayed = false; m_Sparks.Purge(); StopCaptureAlarm(); // init our train m_hTrain = dynamic_cast<CFuncTrackTrain*>( gEntList.FindEntityByName( NULL, m_iszTrain ) ); if ( !m_hTrain ) { Warning("%s failed to find train named '%s'\n", GetClassname(), STRING( m_iszTrain ) ); } // find the trigger area that will give us movement updates and find the sparks (if we're going to handle the train movement) if ( m_bHandleTrainMovement ) { if ( m_hTrain ) { CTriggerAreaCapture *pArea = dynamic_cast<CTriggerAreaCapture *>( gEntList.FindEntityByClassname( NULL, "trigger_capture_area" ) ); while( pArea ) { if ( pArea->GetParent() == m_hTrain.Get() ) { // this is the capture area we care about, so let it know that we want updates on the capture numbers pArea->SetTrainWatcher( this ); break; } pArea = dynamic_cast<CTriggerAreaCapture *>( gEntList.FindEntityByClassname( pArea, "trigger_capture_area" ) ); } } // init the sprites (if any) CEnvSpark *pSpark = dynamic_cast<CEnvSpark*>( gEntList.FindEntityByName( NULL, m_iszSparkName ) ); while ( pSpark ) { m_Sparks.AddToTail( pSpark ); pSpark = dynamic_cast<CEnvSpark*>( gEntList.FindEntityByName( pSpark, m_iszSparkName ) ); } } // init our array of path_tracks linked to control points m_iNumCPLinks = 0; int i; for ( i = 0 ; i < MAX_CONTROL_POINTS ; i++ ) { CPathTrack *pPathTrack = dynamic_cast<CPathTrack*>( gEntList.FindEntityByName( NULL, m_iszLinkedPathTracks[i] ) ); CTeamControlPoint *pCP = dynamic_cast<CTeamControlPoint*>( gEntList.FindEntityByName( NULL, m_iszLinkedCPs[i] ) ); if ( pPathTrack && pCP ) { m_CPLinks[m_iNumCPLinks].hPathTrack = pPathTrack; m_CPLinks[m_iNumCPLinks].hCP = pCP; m_CPLinks[m_iNumCPLinks].flDistanceFromStart = 0; // filled in when we parse the nodes m_CPLinks[m_iNumCPLinks].bAlertPlayed = false; m_iNumCPLinks++; } } // init our start and goal nodes m_hStartNode = dynamic_cast<CPathTrack*>( gEntList.FindEntityByName( NULL, m_iszStartNode ) ); if ( !m_hStartNode ) { Warning("%s failed to find path_track named '%s'\n", GetClassname(), STRING(m_iszStartNode) ); } m_hGoalNode = dynamic_cast<CPathTrack*>( gEntList.FindEntityByName( NULL, m_iszGoalNode ) ); if ( !m_hGoalNode ) { Warning("%s failed to find path_track named '%s'\n", GetClassname(), STRING(m_iszGoalNode) ); } m_flTotalPathDistance = 0.0f; CUtlVector< float > hillData; bool bOnHill = false; bool bDownHillData[TEAM_TRAIN_MAX_HILLS]; Q_memset( bDownHillData, 0, sizeof( bDownHillData ) ); int iHillCount = 0; if( m_hStartNode.Get() && m_hGoalNode.Get() ) { CPathTrack *pNode = m_hStartNode; CPathTrack *pPrev = pNode; CPathTrack *pHillStart = NULL; pNode = pNode->GetNext(); int iHillType = HILL_TYPE_NONE; // don't check the start node for links. If it's linked, it will have 0 distance anyway while ( pNode ) { Vector dir = pNode->GetLocalOrigin() - pPrev->GetLocalOrigin(); float length = dir.Length(); m_flTotalPathDistance += length; // gather our hill data for the HUD if ( pNode->GetHillType() != iHillType ) { if ( !bOnHill ) // we're at the start of a hill { hillData.AddToTail( m_flTotalPathDistance ); bOnHill = true; pHillStart = pNode; if ( iHillCount < TEAM_TRAIN_MAX_HILLS ) { bDownHillData[iHillCount] = pNode->IsDownHill() ? true : false; iHillCount++; } } else // we're at the end of a hill { float flDistance = m_flTotalPathDistance - length; // subtract length because the prev node was the end of the hill (not this one) if ( pHillStart && ( pHillStart == pPrev ) ) { flDistance = m_flTotalPathDistance; // we had a single node marked as a hill, so we'll use the current distance as the next marker } hillData.AddToTail( flDistance ); // is our current node the start of another hill? if ( pNode->GetHillType() != HILL_TYPE_NONE ) { hillData.AddToTail( m_flTotalPathDistance ); bOnHill = true; pHillStart = pNode; if ( iHillCount < TEAM_TRAIN_MAX_HILLS ) { bDownHillData[iHillCount] = pNode->IsDownHill() ? true : false; iHillCount++; } } else { bOnHill = false; pHillStart = NULL; } } iHillType = pNode->GetHillType(); } // if pNode is one of our cp nodes, store its distance from m_hStartNode for ( i = 0 ; i < m_iNumCPLinks ; i++ ) { if ( m_CPLinks[i].hPathTrack == pNode ) { m_CPLinks[i].flDistanceFromStart = m_flTotalPathDistance; break; } } if ( pNode == m_hGoalNode ) break; pPrev = pNode; pNode = pNode->GetNext(); } } // if we don't have an even number of entries in our hill data (beginning/end) add the final distance if ( ( hillData.Count() % 2 ) != 0 ) { hillData.AddToTail( m_flTotalPathDistance ); } if ( ObjectiveResource() ) { ObjectiveResource()->ResetHillData( GetTeamNumber() ); // convert our hill data into 0-1 percentages for networking if ( m_flTotalPathDistance > 0 && hillData.Count() > 0 ) { i = 0; while ( i < hillData.Count() ) { if ( i < TEAM_TRAIN_HILLS_ARRAY_SIZE - 1 ) // - 1 because we want to use 2 entries { // add/subtract to the hill start/end to fix rounding errors in the HUD when the train // stops at the bottom/top of a hill but the HUD thinks the train is still on the hill ObjectiveResource()->SetHillData( GetTeamNumber(), (hillData[i] / m_flTotalPathDistance) + 0.005f, (hillData[i+1] / m_flTotalPathDistance) - 0.005f, bDownHillData[i/2] ); } i = i + 2; } } } // We have total distance and increments in our links array for ( i=0;i<m_iNumCPLinks;i++ ) { int iCPIndex = m_CPLinks[i].hCP.Get()->GetPointIndex(); // This can be pulled once DoD includes team_objectiveresource.* and c_team_objectiveresource.* #ifndef DOD_DLL ObjectiveResource()->SetTrainPathDistance( iCPIndex, m_CPLinks[i].flDistanceFromStart / m_flTotalPathDistance ); #endif } #ifdef GLOWS_ENABLE FindGlowEntity(); #endif // GLOWS_ENABLE InternalSetSpeedForwardModifier( m_flSpeedForwardModifier ); SetContextThink( &CTeamTrainWatcher::WatcherThink, gpGlobals->curtime + 0.1, TW_THINK ); }