//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTeamRoundTimer::InputRoundSpawn( inputdata_t &input ) { if ( !m_bResetTimeOnRoundStart && ( m_nState == RT_STATE_NORMAL ) ) { m_nTimeToUseAfterSetupFinished = GetTimeRemaining(); } else { m_nTimeToUseAfterSetupFinished = m_nTimerInitialLength; } if ( m_nSetupTimeLength > 0 ) { SetTimeRemaining( m_nSetupTimeLength ); SetState( RT_STATE_SETUP ); if ( ShowInHud() && !TeamplayRoundBasedRules()->IsInWaitingForPlayers() ) { UTIL_LogPrintf( "World triggered \"Round_Setup_Begin\"\n" ); } } else { SetTimeRemaining( m_nTimeToUseAfterSetupFinished ); SetState( RT_STATE_NORMAL ); } if ( !m_bStartPaused && !TeamplayRoundBasedRules()->IsInWaitingForPlayers() ) { ResumeTimer(); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTeamControlPoint::HandleScoring( int iTeam ) { if ( TeamplayRoundBasedRules() && !TeamplayRoundBasedRules()->ShouldScorePerRound() ) { GetGlobalTeam( iTeam )->AddScore( 1 ); TeamplayRoundBasedRules()->HandleTeamScoreModify( iTeam, 1 ); CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL; if ( pMaster && !pMaster->WouldNewCPOwnerWinGame( this, iTeam ) ) { #ifdef TF_DLL if ( TeamplayRoundBasedRules()->GetGameType() == TF_GAMETYPE_ESCORT ) { CBroadcastRecipientFilter filter; EmitSound( filter, entindex(), "Hud.EndRoundScored" ); } else #endif { CTeamRecipientFilter filter( iTeam ); EmitSound( filter, entindex(), "Hud.EndRoundScored" ); } } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTeamRoundTimer::SetState( int nState ) { m_nState = nState; if ( nState == RT_STATE_SETUP ) { if ( IsStopWatchTimer() == false ) { TeamplayRoundBasedRules()->SetSetup( true ); } SetTimerThink( RT_THINK_SETUP ); m_OnSetupStart.FireOutput( this, this ); } else { if ( IsStopWatchTimer() == false ) { TeamplayRoundBasedRules()->SetSetup( false ); } SetTimerThink( RT_THINK_NORMAL ); m_OnRoundStart.FireOutput( this, this ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTeamControlPoint::InputSetLocked( inputdata_t &inputdata ) { // never lock/unlock the point if we're in waiting for players if ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->IsInWaitingForPlayers() ) return; bool bLocked = inputdata.value.Int() > 0; InternalSetLocked( bLocked ); }
void CTeamTrainWatcher::PlayCaptureAlert( CTeamControlPoint *pPoint, bool bFinalPointInMap ) { if ( !pPoint ) return; if ( TeamplayRoundBasedRules() ) { TeamplayRoundBasedRules()->PlayTrainCaptureAlert( pPoint, bFinalPointInMap ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTeamControlPoint::UnlockThink( void ) { if ( m_flUnlockTime > 0 && m_flUnlockTime < gpGlobals->curtime && ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->State_Get() == GR_STATE_RND_RUNNING ) ) { InternalSetLocked( false ); return; } SetContextThink( &CTeamControlPoint::UnlockThink, gpGlobals->curtime + 0.1, CONTROL_POINT_UNLOCK_THINK ); }
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: Used by Area caps to set the owner //----------------------------------------------------------------------------- void CTeamControlPoint::InputSetOwner( inputdata_t &input ) { int iCapTeam = input.value.Int(); Assert( iCapTeam >= 0 && iCapTeam < GetNumberOfTeams() ); Assert( input.pCaller ); if ( !input.pCaller ) return; if ( GetOwner() == iCapTeam ) return; if ( TeamplayGameRules()->PointsMayBeCaptured() ) { // must be done before setting the owner HandleScoring( iCapTeam ); if ( input.pCaller->IsPlayer() ) { int iCappingPlayer = input.pCaller->entindex(); InternalSetOwner( iCapTeam, true, 1, &iCappingPlayer ); } else { InternalSetOwner( iCapTeam, false ); } ObjectiveResource()->SetOwningTeam( GetPointIndex(), m_iTeam ); TeamplayRoundBasedRules()->RecalculateControlPointState(); } }
//----------------------------------------------------------------------------- // Purpose: Used by ControlMaster to this point to its default owner //----------------------------------------------------------------------------- void CTeamControlPoint::InputReset( inputdata_t &input ) { m_flLastContestedAt = -1; InternalSetOwner( m_iDefaultOwner, false ); ObjectiveResource()->SetOwningTeam( GetPointIndex(), m_iTeam ); TeamplayRoundBasedRules()->RecalculateControlPointState(); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTeamControlPointRound::SetupSpawnPoints( void ) { CTeamplayRoundBasedRules *pRules = TeamplayRoundBasedRules(); if ( pRules ) { pRules->SetupSpawnPointsForRound(); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTriggerAreaCapture::HandleRespawnTimeAdjustments( int oldTeam, int newTeam ) { if ( oldTeam > LAST_SHARED_TEAM ) { // reverse the adjust made when the old team captured this point (if we made one) if ( m_TeamData[oldTeam].iSpawnAdjust != 0 ) { TeamplayRoundBasedRules()->AddTeamRespawnWaveTime( oldTeam, -m_TeamData[oldTeam].iSpawnAdjust ); } } if ( newTeam > LAST_SHARED_TEAM ) { if ( m_TeamData[newTeam].iSpawnAdjust != 0 ) { TeamplayRoundBasedRules()->AddTeamRespawnWaveTime( newTeam, m_TeamData[newTeam].iSpawnAdjust ); } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CControlPointProgressBar::SetupForPoint( CControlPointIcon *pIcon ) { C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( !pPlayer ) return; m_pAttachedToIcon = pIcon; bool bInWinState = TeamplayRoundBasedRules() ? TeamplayRoundBasedRules()->RoundHasBeenWon() : false; if ( m_pAttachedToIcon && !bInWinState ) { SetVisible( true ); int iCP = m_pAttachedToIcon->GetCapIndex(); int iCappingTeam = ObjectiveResource()->GetCappingTeam( iCP ); int iOwnerTeam = ObjectiveResource()->GetOwningTeam( iCP ); int iPlayerTeam = pPlayer->GetTeamNumber(); bool bCapBlocked = ObjectiveResource()->CapIsBlocked( iCP ); if ( !bCapBlocked && iCappingTeam != TEAM_UNASSIGNED && iCappingTeam != iOwnerTeam && iCappingTeam == iPlayerTeam ) { m_pBar->SetBgImage( ObjectiveResource()->GetGameSpecificCPBarBG( iCP, iCappingTeam ) ); m_pBar->SetFgImage( ObjectiveResource()->GetGameSpecificCPBarFG( iCP, iOwnerTeam ) ); m_pBar->SetVisible( true ); m_pBlocked->SetVisible( false ); m_pBarText->SetVisible( false ); } else { m_pBar->SetVisible( false ); m_pBlocked->SetVisible( true ); UpdateBarText(); } InvalidateLayout(); } else { SetVisible( false ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTeamControlPoint::Spawn( void ) { // Validate our default team if ( m_iDefaultOwner < 0 || m_iDefaultOwner >= GetNumberOfTeams() ) { Warning( "team_control_point '%s' has bad point_default_owner.\n", GetDebugName() ); m_iDefaultOwner = TEAM_UNASSIGNED; } #if defined (TF_DLL) || defined (TF_CLASSIC) if ( m_iszCaptureStartSound == NULL_STRING ) { m_iszCaptureStartSound = AllocPooledString( "Hologram.Start" ); } if ( m_iszCaptureEndSound == NULL_STRING ) { m_iszCaptureEndSound = AllocPooledString( "Hologram.Stop" ); } if ( m_iszCaptureInProgress == NULL_STRING ) { m_iszCaptureInProgress = AllocPooledString( "Hologram.Move" ); } if ( m_iszCaptureInterrupted == NULL_STRING ) { m_iszCaptureInterrupted = AllocPooledString( "Hologram.Interrupted" ); } #endif Precache(); InternalSetOwner( m_iDefaultOwner, false ); //init the owner of this point TeamplayRoundBasedRules()->RecalculateControlPointState(); SetActive( !m_bStartDisabled ); BaseClass::Spawn(); SetPlaybackRate( 1.0 ); SetThink( &CTeamControlPoint::AnimThink ); SetNextThink( gpGlobals->curtime + 0.1f ); if ( FBitSet( m_spawnflags, SF_CAP_POINT_HIDE_MODEL ) ) { AddEffects( EF_NODRAW ); } if ( FBitSet( m_spawnflags, SF_CAP_POINT_HIDE_SHADOW ) ) { AddEffects( EF_NOSHADOW ); } m_flLastContestedAt = -1; m_pCaptureInProgressSound = NULL; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTeamControlPoint::SetOwner( int iCapTeam, bool bMakeSound, int iNumCappers, int *pCappingPlayers ) { if ( TeamplayGameRules()->PointsMayBeCaptured() ) { // must be done before setting the owner HandleScoring( iCapTeam ); InternalSetOwner( iCapTeam, bMakeSound, iNumCappers, pCappingPlayers ); ObjectiveResource()->SetOwningTeam( GetPointIndex(), m_iTeam ); TeamplayRoundBasedRules()->RecalculateControlPointState(); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTeamControlPoint::InputSetUnlockTime( inputdata_t &inputdata ) { // never lock/unlock the point if we're in waiting for players if ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->IsInWaitingForPlayers() ) return; int nTime = inputdata.value.Int(); if ( nTime <= 0 ) { InternalSetLocked( false ); return; } m_flUnlockTime = gpGlobals->curtime + nTime; if ( ObjectiveResource() ) { ObjectiveResource()->SetCPUnlockTime( GetPointIndex(), m_flUnlockTime ); } SetContextThink( &CTeamControlPoint::UnlockThink, gpGlobals->curtime + 0.1, CONTROL_POINT_UNLOCK_THINK ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_TeamTrainWatcher::UpdateGlowEffect( void ) { // destroy the existing effect if ( m_pGlowEffect ) { DestroyGlowEffect(); } // create a new effect if we have a cart if ( m_hGlowEnt ) { float r, g, b; TeamplayRoundBasedRules()->GetTeamGlowColor( GetTeamNumber(), r, g, b ); m_pGlowEffect = new CGlowObject( m_hGlowEnt, Vector( r, g, b ), 1.0, true ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CControlPointProgressBar::UpdateBarText( void ) { C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( !pPlayer || !m_pBarText || !m_pAttachedToIcon ) return; m_pBarText->SetVisible( true ); int iCP = m_pAttachedToIcon->GetCapIndex(); int iCappingTeam = ObjectiveResource()->GetCappingTeam( iCP ); int iPlayerTeam = pPlayer->GetTeamNumber(); int iOwnerTeam = ObjectiveResource()->GetOwningTeam( iCP ); m_pBarText->SetPos( XRES(25), YRES(20) ); if ( !TeamplayGameRules()->PointsMayBeCaptured() ) { m_pBarText->SetText( "#Team_Capture_NotNow" ); return; } if ( mp_blockstyle.GetInt() == 1 && iCappingTeam != TEAM_UNASSIGNED && iCappingTeam != iPlayerTeam ) { if ( ObjectiveResource()->IsCPBlocked(iCP) ) { m_pBarText->SetText( "#Team_Blocking_Capture" ); return; } else if ( iOwnerTeam == TEAM_UNASSIGNED ) { m_pBarText->SetText( "#Team_Reverting_Capture" ); return; } } if ( ObjectiveResource()->GetOwningTeam(iCP) == iPlayerTeam ) { // If the opponents can never recapture this point back, we use a different string if ( iPlayerTeam != TEAM_UNASSIGNED ) { int iEnemyTeam = ( iPlayerTeam == TF_TEAM_RED ) ? TF_TEAM_BLUE : TF_TEAM_RED; if ( !ObjectiveResource()->TeamCanCapPoint( iCP, iEnemyTeam ) ) { m_pBarText->SetText( "#Team_Capture_Owned" ); return; } } m_pBarText->SetText( "#Team_Capture_OwnPoint" ); m_pBarText->SetPos( XRES(30), YRES(20) ); return; } if ( !TeamplayGameRules()->TeamMayCapturePoint( iPlayerTeam, iCP ) ) { if ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->IsInArenaMode() == true ) { m_pBarText->SetText( "#Team_Capture_NotNow" ); } else { m_pBarText->SetText( "#Team_Capture_Linear" ); } return; } char szReason[256]; if ( !TeamplayGameRules()->PlayerMayCapturePoint( pPlayer, iCP, szReason, sizeof(szReason) ) ) { m_pBarText->SetText( szReason ); return; } bool bHaveRequiredPlayers = true; // In Capstyle 1, more players simply cap faster, no required amounts. if ( mp_capstyle.GetInt() != 1 ) { int nNumTeammates = ObjectiveResource()->GetNumPlayersInArea( iCP, iPlayerTeam ); int nRequiredTeammates = ObjectiveResource()->GetRequiredCappers( iCP, iPlayerTeam ); bHaveRequiredPlayers = (nNumTeammates >= nRequiredTeammates); } if ( iCappingTeam == iPlayerTeam && bHaveRequiredPlayers ) { m_pBarText->SetText( "#Team_Capture_Blocked" ); return; } if ( !ObjectiveResource()->TeamCanCapPoint( iCP, iPlayerTeam ) ) { m_pBarText->SetText( "#Team_Cannot_Capture" ); return; } m_pBarText->SetText( "#Team_Waiting_for_teammate" ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTeamControlPoint::ForceOwner( int iTeam ) { InternalSetOwner( iTeam, false, 0, 0 ); ObjectiveResource()->SetOwningTeam( GetPointIndex(), m_iTeam ); TeamplayRoundBasedRules()->RecalculateControlPointState(); }
void CTeamTrainWatcher::WatcherThink( void ) { if ( m_bWaitingToRecede ) { if ( m_flRecedeTime < gpGlobals->curtime ) { m_bWaitingToRecede = false; // don't actually recede in overtime if ( TeamplayRoundBasedRules() && !TeamplayRoundBasedRules()->InOvertime() ) { // fire recede output m_OnTrainStartRecede.FireOutput( this, this ); HandleTrainMovement( true ); } } } bool bDisableAlarm = (TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->State_Get() != GR_STATE_RND_RUNNING); if ( bDisableAlarm ) { StopCaptureAlarm(); } // given its next node, we can walk the nodes and find the linear // distance to the next cp node, or to the goal node CFuncTrackTrain *pTrain = m_hTrain; if ( pTrain ) { int iOldTrainSpeedLevel = m_iTrainSpeedLevel; // how fast is the train moving? float flSpeed = pTrain->GetDesiredSpeed(); // divide speed into regions // anything negative is -1 if ( flSpeed < 0 ) { m_iTrainSpeedLevel = -1; // even though our desired speed might be negative, // our actual speed might be zero if we're at a dead end... // this will turn off the < image when the train is done moving backwards if ( pTrain->GetCurrentSpeed() == 0 ) { m_iTrainSpeedLevel = 0; } } else if ( flSpeed > m_flSpeedLevels[2] ) { m_iTrainSpeedLevel = 3; } else if ( flSpeed > m_flSpeedLevels[1] ) { m_iTrainSpeedLevel = 2; } else if ( flSpeed > m_flSpeedLevels[0] ) { m_iTrainSpeedLevel = 1; } else { m_iTrainSpeedLevel = 0; } if ( m_iTrainSpeedLevel != iOldTrainSpeedLevel ) { // make sure the sparks are off if we're not moving backwards anymore if ( m_bHandleTrainMovement ) { if ( m_iTrainSpeedLevel == 0 && iOldTrainSpeedLevel != 0 ) { HandleSparks( false ); } } // play any concepts that we might need to play if ( TeamplayRoundBasedRules() ) { if ( m_iTrainSpeedLevel == 0 && iOldTrainSpeedLevel != 0 ) { TeamplayRoundBasedRules()->HaveAllPlayersSpeakConceptIfAllowed( MP_CONCEPT_CART_STOP ); m_flNextSpeakForwardConceptTime = 0; } else if ( m_iTrainSpeedLevel < 0 && iOldTrainSpeedLevel == 0 ) { TeamplayRoundBasedRules()->HaveAllPlayersSpeakConceptIfAllowed( MP_CONCEPT_CART_MOVING_BACKWARD ); m_flNextSpeakForwardConceptTime = 0; } } } if ( m_iTrainSpeedLevel > 0 && m_flNextSpeakForwardConceptTime < gpGlobals->curtime ) { if ( m_hAreaCap.Get() ) { for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBaseMultiplayerPlayer *pPlayer = ToBaseMultiplayerPlayer( UTIL_PlayerByIndex( i ) ); if ( pPlayer ) { if ( m_hAreaCap->IsTouching( pPlayer ) ) { pPlayer->SpeakConceptIfAllowed( MP_CONCEPT_CART_MOVING_FORWARD ); } } } } m_flNextSpeakForwardConceptTime = gpGlobals->curtime + 3.0; } // what percent progress are we at? CPathTrack *pNode = ( pTrain->m_ppath ) ? pTrain->m_ppath->GetNext() : NULL; // if we're moving backwards, GetNext is going to be wrong if ( flSpeed < 0 ) { pNode = pTrain->m_ppath; } if ( pNode ) { float flDistanceToGoal = 0; // distance to next node Vector vecDir = pNode->GetLocalOrigin() - pTrain->GetLocalOrigin(); flDistanceToGoal = vecDir.Length(); // distance of next node to goal node if ( pNode && pNode != m_hGoalNode ) { // walk this until we get to goal node, or a dead end CPathTrack *pPrev = pNode; pNode = pNode->GetNext(); while ( pNode ) { vecDir = pNode->GetLocalOrigin() - pPrev->GetLocalOrigin(); flDistanceToGoal += vecDir.Length(); if ( pNode == m_hGoalNode ) break; pPrev = pNode; pNode = pNode->GetNext(); } } if ( m_flTotalPathDistance <= 0 ) { Assert( !"No path distance in team_train_watcher\n" ); m_flTotalPathDistance = 1; } m_flTotalProgress = clamp( 1.0 - ( flDistanceToGoal / m_flTotalPathDistance ), 0.0, 1.0 ); m_flTrainDistanceFromStart = m_flTotalPathDistance - flDistanceToGoal; // play alert sounds if necessary for ( int iCount = 0 ; iCount < m_iNumCPLinks ; iCount++ ) { if ( m_flTrainDistanceFromStart < m_CPLinks[iCount].flDistanceFromStart - TEAM_TRAIN_ALERT_DISTANCE ) { // back up twice the alert distance before resetting our flag to play the warning again if ( ( m_flTrainDistanceFromStart < m_CPLinks[iCount].flDistanceFromStart - ( TEAM_TRAIN_ALERT_DISTANCE * 2 ) ) || // has receded back twice the alert distance or... ( !m_bTrainCanRecede ) ) // used to catch the case where the train doesn't normally recede but has rolled back down a hill away from the CP { // reset our alert flag m_CPLinks[iCount].bAlertPlayed = false; } } else { if ( m_flTrainDistanceFromStart < m_CPLinks[iCount].flDistanceFromStart && !m_CPLinks[iCount].bAlertPlayed ) { m_CPLinks[iCount].bAlertPlayed = true; bool bFinalPointInMap = false; CTeamControlPoint *pCurrentPoint = m_CPLinks[iCount].hCP.Get(); CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL; if ( pMaster ) { // if we're not playing mini-rounds if ( !pMaster->PlayingMiniRounds() ) { for ( int i = FIRST_GAME_TEAM ; i < MAX_CONTROL_POINT_TEAMS ; i++ ) { if ( ObjectiveResource() && ObjectiveResource()->TeamCanCapPoint( pCurrentPoint->GetPointIndex(), i ) ) { if ( pMaster->WouldNewCPOwnerWinGame( pCurrentPoint, i ) ) { bFinalPointInMap = true; } } } } else { // or this is the last round if ( pMaster->NumPlayableControlPointRounds() == 1 ) { CTeamControlPointRound *pRound = pMaster->GetCurrentRound(); if ( pRound ) { for ( int i = FIRST_GAME_TEAM ; i < MAX_CONTROL_POINT_TEAMS ; i++ ) { if ( ObjectiveResource() && ObjectiveResource()->TeamCanCapPoint( pCurrentPoint->GetPointIndex(), i ) ) { if ( pRound->WouldNewCPOwnerWinGame( pCurrentPoint, i ) ) { bFinalPointInMap = true; } } } } } } } PlayCaptureAlert( pCurrentPoint, bFinalPointInMap ); } } } // check to see if we need to start or stop the alarm if ( flDistanceToGoal <= TEAM_TRAIN_ALARM_DISTANCE ) { if ( ObjectiveResource() ) { ObjectiveResource()->SetTrackAlarm( GetTeamNumber(), true ); } if ( !bDisableAlarm ) { if ( !m_pAlarm ) { if ( m_iNumCPLinks > 0 && !m_bAlarmPlayed ) { // start the alarm at the final point StartCaptureAlarm( m_CPLinks[m_iNumCPLinks-1].hCP.Get() ); m_bAlarmPlayed = true; // used to prevent the alarm from starting again on maps where the train doesn't recede (alarm loops for short time then only plays singles) } } else { if ( !m_bTrainCanRecede ) // if the train won't recede, we only want to play the alarm for a short time { if ( m_flAlarmEndTime > 0 && m_flAlarmEndTime < gpGlobals->curtime ) { StopCaptureAlarm(); SetContextThink( &CTeamTrainWatcher::WatcherAlarmThink, gpGlobals->curtime + TW_ALARM_THINK_INTERVAL, TW_ALARM_THINK ); } } } } } else { if ( ObjectiveResource() ) { ObjectiveResource()->SetTrackAlarm( GetTeamNumber(), false ); } StopCaptureAlarm(); m_bAlarmPlayed = false; } } if ( tf_show_train_path.GetBool() ) { CPathTrack *nextNode = NULL; CPathTrack *node = m_hStartNode; CPathTrack::BeginIteration(); while( node ) { node->Visit(); nextNode = node->GetNext(); if ( !nextNode || nextNode->HasBeenVisited() ) break; NDebugOverlay::Line( node->GetAbsOrigin(), nextNode->GetAbsOrigin(), 255, 255, 0, true, NDEBUG_PERSIST_TILL_NEXT_SERVER ); node = nextNode; } CPathTrack::EndIteration(); // show segment of path train is actually on node = pTrain->m_ppath; if ( node && node->GetNext() ) { NDebugOverlay::HorzArrow( node->GetAbsOrigin(), node->GetNext()->GetAbsOrigin(), 5.0f, 255, 0, 0, 255, true, NDEBUG_PERSIST_TILL_NEXT_SERVER ); } } } SetContextThink( &CTeamTrainWatcher::WatcherThink, gpGlobals->curtime + 0.1, TW_THINK ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTriggerAreaCapture::EndCapture( int team ) { IncrementCapAttemptNumber(); // Remap team to get first game team = 1 switch ( team - FIRST_GAME_TEAM+1 ) { case 1: m_OnCapTeam1.FireOutput( this, this ); break; case 2: m_OnCapTeam2.FireOutput( this, this ); break; default: Assert(0); break; } m_CapOutput.FireOutput(this,this); int numcappers = 0; int cappingplayers[MAX_AREA_CAPPERS]; GetNumCappingPlayers( team, numcappers, cappingplayers ); // Handle this before we assign the new team as the owner of this area HandleRespawnTimeAdjustments( m_nOwningTeam, team ); m_nOwningTeam = team; m_bCapturing = false; m_nCapturingTeam = TEAM_UNASSIGNED; SetCapTimeRemaining( 0 ); //there may have been more than one capper, but only report this one. //he hasn't gotten points yet, and his name will go in the cap string if its needed //first capper gets name sent and points given by flag. //other cappers get points manually above, no name in message //send the player in the cap string if( m_hPoint ) { OnEndCapture( m_nOwningTeam ); UpdateOwningTeam(); m_hPoint->SetOwner( m_nOwningTeam, true, numcappers, cappingplayers ); m_hPoint->CaptureEnd(); } SetNumCappers( 0 ); // tell all touching players to stop racking up capture points CTeam *pTeam = GetGlobalTeam( m_nCapturingTeam ); if ( pTeam ) { for ( int i=0;i<pTeam->GetNumPlayers();i++ ) { CBaseMultiplayerPlayer *pPlayer = ToBaseMultiplayerPlayer( pTeam->GetPlayer(i) ); if ( pPlayer && IsTouching( pPlayer ) ) { pPlayer->StopScoringEscortPoints(); } } } // play any special cap sounds if ( TeamplayRoundBasedRules() ) { TeamplayRoundBasedRules()->PlaySpecialCapSounds( m_nOwningTeam ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTriggerAreaCapture::CaptureThink( void ) { SetNextThink( gpGlobals->curtime + AREA_THINK_TIME ); // make sure this point is in the round being played (if we're playing one) CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL; if ( pMaster && m_hPoint ) { if ( !pMaster->IsInRound( m_hPoint ) ) { return; } } if ( !TeamplayGameRules()->PointsMayBeCaptured() ) { // Points aren't allowed to be captured. If we were // being captured, we need to clean up and reset. if ( m_bCapturing ) { BreakCapture( false ); UpdateNumPlayers(); } return; } // go through our list of players Assert( GetNumberOfTeams() <= MAX_CAPTURE_TEAMS ); int iNumPlayers[MAX_CAPTURE_TEAMS]; int iNumBlockablePlayers[MAX_CAPTURE_TEAMS]; // Players in the zone who can't cap, but can block / pause caps CBaseMultiplayerPlayer *pFirstPlayerTouching[MAX_CAPTURE_TEAMS]; for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ ) { iNumPlayers[i] = 0; iNumBlockablePlayers[i] = 0; pFirstPlayerTouching[i] = NULL; } if ( m_hPoint ) { // Loop through the entities we're touching, and find players for ( int i = 0; i < m_hTouchingEntities.Count(); i++ ) { CBaseEntity *ent = m_hTouchingEntities[i]; if ( ent && ent->IsPlayer() ) { CBaseMultiplayerPlayer *pPlayer = ToBaseMultiplayerPlayer(ent); if ( pPlayer->IsAlive() ) { int iTeam = pPlayer->GetTeamNumber(); // If a team's not allowed to cap a point, don't count players in it at all if ( !TeamplayGameRules()->TeamMayCapturePoint( iTeam, m_hPoint->GetPointIndex() ) ) continue; if ( !TeamplayGameRules()->PlayerMayCapturePoint( pPlayer, m_hPoint->GetPointIndex() ) ) { if ( TeamplayGameRules()->PlayerMayBlockPoint( pPlayer, m_hPoint->GetPointIndex() ) ) { if ( iNumPlayers[iTeam] == 0 && iNumBlockablePlayers[iTeam] == 0 ) { pFirstPlayerTouching[iTeam] = pPlayer; } iNumBlockablePlayers[iTeam] += TeamplayGameRules()->GetCaptureValueForPlayer( pPlayer ); } continue; } if ( iTeam >= FIRST_GAME_TEAM ) { if ( iNumPlayers[iTeam] == 0 && iNumBlockablePlayers[iTeam] == 0 ) { pFirstPlayerTouching[iTeam] = pPlayer; } iNumPlayers[iTeam] += TeamplayGameRules()->GetCaptureValueForPlayer( pPlayer ); } } } } } int iTeamsInZone = 0; bool bUpdatePlayers = false; m_nTeamInZone = TEAM_UNASSIGNED; for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ ) { iNumPlayers[i] *= mp_simulatemultiplecappers.GetInt(); if ( m_TeamData[i].iNumTouching != iNumPlayers[i] ) { m_TeamData[i].iNumTouching = iNumPlayers[i]; bUpdatePlayers = true; } m_TeamData[i].iBlockedTouching = m_TeamData[i].iNumTouching; if ( m_TeamData[i].iNumTouching ) { iTeamsInZone++; m_nTeamInZone = i; } } if ( iTeamsInZone > 1 ) { m_nTeamInZone = TEAM_UNASSIGNED; } else { // If we've got non-cappable, yet blockable players here for the team that's defending, they // need to block the cap. This catches cases like the TF invulnerability, which needs to block // caps, but isn't allowed to contribute to a cap. for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ ) { if ( !iNumBlockablePlayers[i] || m_nTeamInZone == i ) continue; iTeamsInZone++; } } UpdateTeamInZone(); bool bBlocked = false; // If the cap is being blocked, reset the number of players so the client // knows to stop the capture as well. if ( mp_blockstyle.GetInt() == 1 ) { if ( m_bCapturing && iTeamsInZone > 1 ) { bBlocked = true; for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ ) { iNumPlayers[i] = 0; if ( m_TeamData[i].iNumTouching != iNumPlayers[i] ) { m_TeamData[i].iNumTouching = iNumPlayers[i]; bUpdatePlayers = true; } } } } if ( bUpdatePlayers ) { UpdateNumPlayers( bBlocked ); } // When a player blocks, tell them the cap index and attempt number // only give successive blocks to them if the attempt number is different if ( m_bCapturing ) { if ( m_hPoint ) { m_hPoint->SetLastContestedAt( gpGlobals->curtime ); } // Calculate the amount of modification to the cap time float flTimeDelta = gpGlobals->curtime - m_flLastReductionTime; float flReduction = flTimeDelta; if ( CaptureModeScalesWithPlayers() ) { // Diminishing returns for successive players. for ( int i = 1; i < m_TeamData[m_nTeamInZone].iNumTouching; i++ ) { flReduction += (flTimeDelta / (float)(i+1)); } } m_flLastReductionTime = gpGlobals->curtime; //if more than one team is in the zone if( iTeamsInZone > 1 ) { if ( !m_bBlocked ) { m_bBlocked = true; UpdateBlocked(); } // See if anyone gets credit for the block float flPercentToGo = m_fTimeRemaining / m_flCapTime; if ( CaptureModeScalesWithPlayers() ) { flPercentToGo = m_fTimeRemaining / ((m_flCapTime * 2) * m_TeamData[m_nCapturingTeam].iNumRequiredToCap); } if ( ( flPercentToGo <= 0.5 || TeamplayGameRules()->PointsMayAlwaysBeBlocked() ) && m_hPoint ) { // find the first player that is not on the capturing team // they have just broken a cap and should be rewarded // tell the player the capture attempt number, for checking later CBaseMultiplayerPlayer *pBlockingPlayer = NULL; for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ ) { if ( m_nCapturingTeam == i ) continue; if ( pFirstPlayerTouching[i] ) { pBlockingPlayer = pFirstPlayerTouching[i]; break; } } Assert( pBlockingPlayer ); if ( pBlockingPlayer ) { bool bRepeatBlocker = false; for ( int i = m_Blockers.Count()-1; i >= 0; i-- ) { if ( m_Blockers[i].hPlayer != pBlockingPlayer ) continue; // If this guy's was a blocker, but not valid now, remove him from the list if ( m_Blockers[i].iCapAttemptNumber != m_iCapAttemptNumber || !IsTouching(m_Blockers[i].hPlayer) || ( TeamplayGameRules()->PointsMayAlwaysBeBlocked() && m_Blockers[i].flNextBlockTime < gpGlobals->curtime && m_bStartTouch ) ) { m_Blockers.Remove(i); continue; } bRepeatBlocker = true; break; } if ( !bRepeatBlocker ) { m_hPoint->CaptureBlocked( pBlockingPlayer ); // Add this guy to our blocker list int iNew = m_Blockers.AddToTail(); m_Blockers[iNew].hPlayer = pBlockingPlayer; m_Blockers[iNew].iCapAttemptNumber = m_iCapAttemptNumber; m_Blockers[iNew].flNextBlockTime = gpGlobals->curtime + 10.0f; } } } if ( mp_blockstyle.GetInt() == 0 ) { BreakCapture( false ); } return; } if ( m_bBlocked ) { m_bBlocked = false; UpdateBlocked(); } float flTotalTimeToCap = m_flCapTime; if ( CaptureModeScalesWithPlayers() ) { flTotalTimeToCap = ((m_flCapTime * 2) * m_TeamData[m_nCapturingTeam].iNumRequiredToCap); } // Now remove the reduction amount after we've determined there's only 1 team in the area if ( m_nCapturingTeam == m_nTeamInZone ) { SetCapTimeRemaining( m_fTimeRemaining - flReduction ); } else if ( m_nOwningTeam == TEAM_UNASSIGNED && m_nTeamInZone != TEAM_UNASSIGNED ) { SetCapTimeRemaining( m_fTimeRemaining + flReduction ); } else { // Caps deteriorate over time if ( TeamplayRoundBasedRules() && m_hPoint && TeamplayRoundBasedRules()->TeamMayCapturePoint(m_nCapturingTeam,m_hPoint->GetPointIndex()) ) { float flDecreaseScale = CaptureModeScalesWithPlayers() ? mp_capdeteriorate_time.GetFloat() : flTotalTimeToCap; float flDecrease = (flTotalTimeToCap / flDecreaseScale) * flTimeDelta; if ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->InOvertime() ) { flDecrease *= 6; } SetCapTimeRemaining( m_fTimeRemaining + flDecrease ); } else { SetCapTimeRemaining( flTotalTimeToCap ); } } /* //if no-one is in the area if( iTeamsInZone == 0 ) { BreakCapture( true ); return; } //if they've lost the number of players needed to cap int iTeamMembersHere = m_TeamData[m_nCapturingTeam].iNumTouching + iNumBlockablePlayers[m_nCapturingTeam]; if ( (iTeamMembersHere == 0 ) || (mp_capstyle.GetInt() == 0 && iTeamMembersHere < m_TeamData[m_nCapturingTeam].iNumRequiredToCap) ) { BreakCapture( true ); return; } */ // if the cap is done if ( m_fTimeRemaining <= 0 ) { EndCapture( m_nCapturingTeam ); return; //we're done } else { // We may get several simultaneous CaptureThink calls from StartTouch if there are several players on the trigger // when it is enabled (like in Raid mode). We haven't started reducing m_fTimeRemaining yet but the second call to CaptureThink // from StartTouch has m_bCapturing set to true and we hit this condition and call BreakCapture right away. // We put this check here to prevent calling BreakCapture from the StartTouch call to CaptureThink. If the capture should // really be broken it will happen the next time the trigger thinks on its own. if ( !m_bStartTouch ) { if ( m_fTimeRemaining >= flTotalTimeToCap ) { BreakCapture( false ); return; } } } } else { // If there are any teams in the zone that aren't the owner, try to start capping if ( iTeamsInZone > 0 ) { for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ ) { if ( !m_TeamData[i].bCanCap || m_nOwningTeam == i ) continue; if ( m_TeamData[i].iNumTouching == 0 ) continue; if ( m_TeamData[i].iNumTouching < m_TeamData[i].iNumRequiredToStartCap ) continue; if ( !CaptureModeScalesWithPlayers() && m_TeamData[i].iNumTouching < m_TeamData[i].iNumRequiredToCap ) continue; StartCapture( i, CAPTURE_NORMAL ); break; } } } }
//----------------------------------------------------------------------------- // Purpose: Add seconds to the timer while it is running or paused //----------------------------------------------------------------------------- void CTeamRoundTimer::AddTimerSeconds( int iSecondsToAdd, int iTeamResponsible /* = TEAM_UNASSIGNED*/ ) { if ( IsDisabled() ) return; if ( TeamplayRoundBasedRules()->InStalemate() ) return; // we only want to add time if we're round_running or team_win so the control points // don't add time when they try to set their default owner when the map is first loading if ( TeamplayRoundBasedRules()->State_Get() != GR_STATE_RND_RUNNING && TeamplayRoundBasedRules()->State_Get() != GR_STATE_TEAM_WIN ) return; if ( m_nTimerMaxLength > 0 ) { // will adding this many seconds push us over our max length? if ( GetTimeRemaining() + iSecondsToAdd > m_nTimerMaxLength ) { // adjust to only add up to our max length iSecondsToAdd = m_nTimerMaxLength - GetTimeRemaining(); } } if ( m_bTimerPaused ) { m_flTimeRemaining += (float)iSecondsToAdd; } else { m_flTimerEndTime += (float)iSecondsToAdd; } m_nTimerLength += iSecondsToAdd; CalculateOutputMessages(); if ( ObjectiveResource() && ObjectiveResource()->GetTimerInHUD() == entindex() ) { if ( !TeamplayRoundBasedRules()->InStalemate() && !TeamplayRoundBasedRules()->RoundHasBeenWon() ) { if ( iTeamResponsible >= LAST_SHARED_TEAM+1 ) { for ( int iTeam = LAST_SHARED_TEAM+1 ; iTeam < GetNumberOfTeams(); iTeam++ ) { if ( iTeam == iTeamResponsible ) { CTeamRecipientFilter filter( iTeam, true ); EmitSound( filter, entindex(), ROUND_TIMER_TIME_ADDED_WINNER ); } else { CTeamRecipientFilter filter( iTeam, true ); EmitSound( filter, entindex(), ROUND_TIMER_TIME_ADDED_LOSER ); } } } else { CReliableBroadcastRecipientFilter filter; EmitSound( filter, entindex(), ROUND_TIMER_TIME_ADDED ); } } // is this the timer we're showing in the HUD? if ( m_bShowInHUD ) { IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_timer_time_added" ); if ( event ) { event->SetInt( "timer", entindex() ); event->SetInt( "seconds_added", iSecondsToAdd ); gameeventmanager->FireEvent( event ); } } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTeamRoundTimer::RoundTimerThink( void ) { if ( TeamplayRoundBasedRules()->IsInPreMatch() == true && IsDisabled() == false ) { inputdata_t data; InputDisable( data ); } if ( IsDisabled() || m_bTimerPaused || IsInCommentaryMode() || gpGlobals->eLoadType == MapLoad_Background ) { SetContextThink( &CTeamRoundTimer::RoundTimerThink, gpGlobals->curtime + 0.05, ROUND_TIMER_THINK ); return; } // Don't do anything when the game has been won or if we're loading a bugbait report if ( TeamplayRoundBasedRules()->RoundHasBeenWon() || TeamplayRoundBasedRules()->IsLoadingBugBaitReport() ) { // We want to stop timers when the round has been won, but we don't want to // force mapmakers to deal with having to unpause it. This little hack works around that. if ( !m_bTimerPaused ) { PauseTimer(); m_bPauseDueToWin = true; } SetContextThink( &CTeamRoundTimer::RoundTimerThink, gpGlobals->curtime + 0.05, ROUND_TIMER_THINK ); return; } else if ( m_bPauseDueToWin ) { ResumeTimer(); m_bPauseDueToWin = false; } float flTime = GetTimeRemaining(); if ( flTime > 0 && ShowInHud() ) // is this the timer we're showing in the HUD? { TeamplayRoundBasedRules()->SetOvertime( false ); } if ( flTime <= 0.0f && m_bFireFinished ) { // Allow the gamerules to prevent timer expiration (i.e. while a control point is contested) if ( !TeamplayGameRules()->TimerMayExpire() ) { // we don't want the timer to keep going (negative time) m_flTimerEndTime = gpGlobals->curtime; // is this the timer we're showing in the HUD? if ( ShowInHud() ) { TeamplayRoundBasedRules()->SetOvertime( true ); } // Think slower SetContextThink( &CTeamRoundTimer::RoundTimerThink, gpGlobals->curtime + 1.0, ROUND_TIMER_THINK ); return; } m_OnFinished.FireOutput( this, this ); m_bFireFinished = false; } else if ( flTime <= 300.0 && m_bFire5MinRemain ) { m_On5MinRemain.FireOutput( this, this ); m_bFire5MinRemain = false; } else if ( flTime <= 240.0 && m_bFire4MinRemain ) { m_On4MinRemain.FireOutput( this, this ); m_bFire4MinRemain = false; } else if ( flTime <= 180.0 && m_bFire3MinRemain ) { m_On3MinRemain.FireOutput( this, this ); m_bFire3MinRemain = false; } else if ( flTime <= 120.0 && m_bFire2MinRemain ) { m_On2MinRemain.FireOutput( this, this ); m_bFire2MinRemain = false; } else if ( flTime <= 60.0 && m_bFire1MinRemain ) { m_On1MinRemain.FireOutput( this, this ); m_bFire1MinRemain = false; } else if ( flTime <= 30.0 && m_bFire30SecRemain ) { m_On30SecRemain.FireOutput( this, this ); m_bFire30SecRemain = false; } else if ( flTime <= 10.0 && m_bFire10SecRemain ) { m_On10SecRemain.FireOutput( this, this ); m_bFire10SecRemain = false; } else if ( flTime <= 5.0 && m_bFire5SecRemain ) { m_On5SecRemain.FireOutput( this, this ); m_bFire5SecRemain = false; } else if ( flTime <= 4.0 && m_bFire4SecRemain ) { m_On4SecRemain.FireOutput( this, this ); m_bFire4SecRemain = false; } else if ( flTime <= 3.0 && m_bFire3SecRemain ) { m_On3SecRemain.FireOutput( this, this ); m_bFire3SecRemain = false; } else if ( flTime <= 2.0 && m_bFire2SecRemain ) { m_On2SecRemain.FireOutput( this, this ); m_bFire2SecRemain = false; } else if ( flTime <= 1.0 && m_bFire1SecRemain ) { m_On1SecRemain.FireOutput( this, this ); m_bFire1SecRemain = false; } SetContextThink( &CTeamRoundTimer::RoundTimerThink, gpGlobals->curtime + 0.05, ROUND_TIMER_THINK ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTeamRoundTimer::RoundTimerSetupThink( void ) { if ( TeamplayRoundBasedRules()->IsInPreMatch() == true && IsDisabled() == false ) { inputdata_t data; InputDisable( data ); m_OnSetupFinished.FireOutput( this, this ); } if ( IsDisabled() || m_bTimerPaused ) { SetContextThink( &CTeamRoundTimer::RoundTimerSetupThink, gpGlobals->curtime + 0.05, ROUND_TIMER_SETUP_THINK ); return; } float flTime = GetTimeRemaining(); TeamplayRoundBasedRules()->SetOvertime( false ); if ( flTime <= 0.0f && m_bFireFinished ) { IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_setup_finished" ); if ( event ) { gameeventmanager->FireEvent( event ); } m_OnSetupFinished.FireOutput( this, this ); m_bFireFinished = false; SetTimeRemaining( m_nTimeToUseAfterSetupFinished ); SetState( RT_STATE_NORMAL ); if ( ShowInHud() && !TeamplayRoundBasedRules()->IsInWaitingForPlayers() ) { UTIL_LogPrintf( "World triggered \"Round_Setup_End\"\n" ); } return; } else if ( flTime <= 60.0 && m_bFire1MinRemain ) { m_On1MinRemain.FireOutput( this, this ); m_bFire1MinRemain = false; } else if ( flTime <= 30.0 && m_bFire30SecRemain ) { m_On30SecRemain.FireOutput( this, this ); m_bFire30SecRemain = false; } else if ( flTime <= 10.0 && m_bFire10SecRemain ) { m_On10SecRemain.FireOutput( this, this ); m_bFire10SecRemain = false; } else if ( flTime <= 5.0 && m_bFire5SecRemain ) { m_On5SecRemain.FireOutput( this, this ); m_bFire5SecRemain = false; } else if ( flTime <= 4.0 && m_bFire4SecRemain ) { m_On4SecRemain.FireOutput( this, this ); m_bFire4SecRemain = false; } else if ( flTime <= 3.0 && m_bFire3SecRemain ) { m_On3SecRemain.FireOutput( this, this ); m_bFire3SecRemain = false; } else if ( flTime <= 2.0 && m_bFire2SecRemain ) { m_On2SecRemain.FireOutput( this, this ); m_bFire2SecRemain = false; } else if ( flTime <= 1.0 && m_bFire1SecRemain ) { m_On1SecRemain.FireOutput( this, this ); m_bFire1SecRemain = false; } SetContextThink( &CTeamRoundTimer::RoundTimerSetupThink, gpGlobals->curtime + 0.05, ROUND_TIMER_SETUP_THINK ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTeamRoundTimer::SendTimeWarning( int nWarning ) { // don't play sounds if the level designer has turned them off or if it's during the WaitingForPlayers time if ( !m_bTimerPaused && m_bAutoCountdown && !TeamplayRoundBasedRules()->IsInWaitingForPlayers() ) { C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( pPlayer ) { if ( ObjectiveResource() ) { bool bShouldPlaySound = false; if ( TeamplayRoundBasedRules()->IsInTournamentMode() == true && TeamplayRoundBasedRules()->IsInStopWatch() == true ) { int iActiveTimer = ObjectiveResource()->GetTimerToShowInHUD(); int iStopWatchTimer = ObjectiveResource()->GetStopWatchTimer(); if ( IsStopWatchTimer() == true && IsWatchingTimeStamps() == false ) { CTeamRoundTimer *pTimer = dynamic_cast< CTeamRoundTimer* >( ClientEntityList().GetEnt( iActiveTimer ) ); if ( pTimer && pTimer->IsTimerPaused() == false && pTimer->GetTimeRemaining() > GetTimeRemaining() ) { bShouldPlaySound = true; } } else { CTeamRoundTimer *pStopWatch = dynamic_cast< CTeamRoundTimer* >( ClientEntityList().GetEnt( iStopWatchTimer ) ); if ( ObjectiveResource()->GetTimerToShowInHUD() == entindex() ) { if ( pStopWatch ) { if ( pStopWatch->IsTimerPaused() == true ) { bShouldPlaySound = true; } if ( pStopWatch->GetTimeRemaining() > GetTimeRemaining() && pStopWatch->IsWatchingTimeStamps() == false ) { bShouldPlaySound = true; } if ( pStopWatch->IsWatchingTimeStamps() == true ) { bShouldPlaySound = true; } } else { bShouldPlaySound = true; } } } } else { if( ObjectiveResource()->GetTimerToShowInHUD() == entindex()) { bShouldPlaySound = true; } } if ( bShouldPlaySound == true ) { pPlayer->EmitSound( GetTimeWarningSound( nWarning ) ); } } } } }