source-sdk-2013/mp/src/game/shared/teamplay_round_timer.cpp
Joe Ludwig beaae8ac45 Updated the SDK with the latest code from the TF and HL2 branches
* Adds support for Visual Studio 2012 and 2013
* VR Mode:
. Switches from headtrack.dll to sourcevr.dll
. Improved readability of the UI in VR
. Removed the IPD calibration tool. TF2 will now obey the Oculus
configuration file. Use the Oculus calibration tool in your SDK or
install and run "OpenVR" under Tools in Steam to calibrate your IPD.
. Added dropdown to enable VR mode in the Video options. Removed the -vr
command line option.
. Added the ability to switch in and out of VR mode without quitting the
game
. By default VR mode will run full screen. To switch back to a
borderless window set the vr_force_windowed convar.
. Added support for VR mode on Linux
* Many assorted bug fixes and other changes from Team Fortress in
various shared files
2013-12-03 08:54:16 -08:00

1436 lines
39 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Team gamerules round timer
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "teamplay_round_timer.h"
#include "teamplayroundbased_gamerules.h"
#ifdef CLIENT_DLL
#include "iclientmode.h"
#include "vgui_controls/AnimationController.h"
#include "c_playerresource.h"
#include "c_team_objectiveresource.h"
#if defined( TF_CLIENT_DLL )
#include "tf_gamerules.h"
#include "c_tf_player.h"
#endif // TF_CLIENT_DLL
#else
#include "team.h"
#include "team_objectiveresource.h"
#if defined( TF_DLL )
#include "tf_player.h"
#endif // TF_DLL
#endif
#define ROUND_TIMER_60SECS "Announcer.RoundEnds60seconds"
#define ROUND_TIMER_30SECS "Announcer.RoundEnds30seconds"
#define ROUND_TIMER_10SECS "Announcer.RoundEnds10seconds"
#define ROUND_TIMER_5SECS "Announcer.RoundEnds5seconds"
#define ROUND_TIMER_4SECS "Announcer.RoundEnds4seconds"
#define ROUND_TIMER_3SECS "Announcer.RoundEnds3seconds"
#define ROUND_TIMER_2SECS "Announcer.RoundEnds2seconds"
#define ROUND_TIMER_1SECS "Announcer.RoundEnds1seconds"
#define ROUND_SETUP_60SECS "Announcer.RoundBegins60Seconds"
#define ROUND_SETUP_30SECS "Announcer.RoundBegins30Seconds"
#define ROUND_SETUP_10SECS "Announcer.RoundBegins10Seconds"
#define ROUND_SETUP_5SECS "Announcer.RoundBegins5Seconds"
#define ROUND_SETUP_4SECS "Announcer.RoundBegins4Seconds"
#define ROUND_SETUP_3SECS "Announcer.RoundBegins3Seconds"
#define ROUND_SETUP_2SECS "Announcer.RoundBegins2Seconds"
#define ROUND_SETUP_1SECS "Announcer.RoundBegins1Seconds"
#define ROUND_START_BELL "Ambient.Siren"
#define ROUND_TIMER_TIME_ADDED "Announcer.TimeAdded"
#define ROUND_TIMER_TIME_ADDED_LOSER "Announcer.TimeAddedForEnemy"
#define ROUND_TIMER_TIME_ADDED_WINNER "Announcer.TimeAwardedForTeam"
enum
{
RT_THINK_SETUP,
RT_THINK_NORMAL,
};
enum
{
RT_WARNING_60SECS,
RT_WARNING_30SECS,
RT_WARNING_10SECS,
RT_WARNING_5SECS,
RT_WARNING_4SECS,
RT_WARNING_3SECS,
RT_WARNING_2SECS,
RT_WARNING_1SECS,
RT_WARNING_TIME_START,
};
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern bool IsInCommentaryMode();
#if defined( GAME_DLL ) && defined( TF_DLL )
ConVar tf_overtime_nag( "tf_overtime_nag", "0", FCVAR_NOTIFY, "Announcer overtime nag." );
#endif
#ifdef CLIENT_DLL
// Use this proxy to flash the round timer whenever the timer is restarted
// because trapping the round start event doesn't work ( the event also flushes
// all hud events and obliterates our TimerFlash event )
static void RecvProxy_TimerPaused( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
CTeamRoundTimer *pTimer = (CTeamRoundTimer *) pStruct;
bool bTimerPaused = ( pData->m_Value.m_Int > 0 );
if ( bTimerPaused == false )
{
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "TimerFlash" );
}
if ( pTimer )
{
pTimer->InternalSetPaused( bTimerPaused );
}
}
#endif
LINK_ENTITY_TO_CLASS( team_round_timer, CTeamRoundTimer );
PRECACHE_REGISTER( team_round_timer );
IMPLEMENT_NETWORKCLASS_ALIASED( TeamRoundTimer, DT_TeamRoundTimer )
BEGIN_NETWORK_TABLE_NOBASE( CTeamRoundTimer, DT_TeamRoundTimer )
#ifdef CLIENT_DLL
RecvPropInt( RECVINFO( m_bTimerPaused ), 0, RecvProxy_TimerPaused ),
RecvPropTime( RECVINFO( m_flTimeRemaining ) ),
RecvPropTime( RECVINFO( m_flTimerEndTime ) ),
RecvPropInt( RECVINFO( m_nTimerMaxLength ) ),
RecvPropBool( RECVINFO( m_bIsDisabled ) ),
RecvPropBool( RECVINFO( m_bShowInHUD ) ),
RecvPropInt( RECVINFO( m_nTimerLength ) ),
RecvPropInt( RECVINFO( m_nTimerInitialLength ) ),
RecvPropBool( RECVINFO( m_bAutoCountdown ) ),
RecvPropInt( RECVINFO( m_nSetupTimeLength ) ),
RecvPropInt( RECVINFO( m_nState ) ),
RecvPropBool( RECVINFO( m_bStartPaused ) ),
RecvPropBool( RECVINFO( m_bShowTimeRemaining ) ),
RecvPropBool( RECVINFO( m_bInCaptureWatchState ) ),
RecvPropBool( RECVINFO( m_bStopWatchTimer ) ),
RecvPropTime( RECVINFO( m_flTotalTime ) ),
#else
SendPropBool( SENDINFO( m_bTimerPaused ) ),
SendPropTime( SENDINFO( m_flTimeRemaining ) ),
SendPropTime( SENDINFO( m_flTimerEndTime ) ),
SendPropInt( SENDINFO( m_nTimerMaxLength ) ),
SendPropBool( SENDINFO( m_bIsDisabled ) ),
SendPropBool( SENDINFO( m_bShowInHUD ) ),
SendPropInt( SENDINFO( m_nTimerLength ) ),
SendPropInt( SENDINFO( m_nTimerInitialLength ) ),
SendPropBool( SENDINFO( m_bAutoCountdown ) ),
SendPropInt( SENDINFO( m_nSetupTimeLength ) ),
SendPropInt( SENDINFO( m_nState ) ),
SendPropBool( SENDINFO( m_bStartPaused ) ),
SendPropBool( SENDINFO( m_bShowTimeRemaining ) ),
SendPropBool( SENDINFO( m_bStopWatchTimer ) ),
SendPropBool( SENDINFO( m_bInCaptureWatchState ) ),
SendPropTime( SENDINFO( m_flTotalTime ) ),
#endif
END_NETWORK_TABLE()
#ifndef CLIENT_DLL
BEGIN_DATADESC(CTeamRoundTimer)
DEFINE_KEYFIELD( m_nTimerInitialLength, FIELD_INTEGER, "timer_length" ),
DEFINE_KEYFIELD( m_nTimerMaxLength, FIELD_INTEGER, "max_length" ),
DEFINE_KEYFIELD( m_bShowInHUD, FIELD_BOOLEAN, "show_in_hud" ),
DEFINE_KEYFIELD( m_bIsDisabled, FIELD_BOOLEAN, "StartDisabled" ),
DEFINE_KEYFIELD( m_bAutoCountdown, FIELD_BOOLEAN, "auto_countdown" ),
DEFINE_KEYFIELD( m_nSetupTimeLength, FIELD_INTEGER, "setup_length" ),
DEFINE_KEYFIELD( m_bResetTimeOnRoundStart, FIELD_BOOLEAN, "reset_time" ),
DEFINE_KEYFIELD( m_bStartPaused, FIELD_BOOLEAN, "start_paused" ),
DEFINE_KEYFIELD( m_bShowTimeRemaining, FIELD_BOOLEAN, "show_time_remaining" ),
DEFINE_FUNCTION( RoundTimerSetupThink ),
DEFINE_FUNCTION( RoundTimerThink ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Pause", InputPause ),
DEFINE_INPUTFUNC( FIELD_VOID, "Resume", InputResume ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetTime", InputSetTime ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "AddTime", InputAddTime ),
DEFINE_INPUTFUNC( FIELD_VOID, "Restart", InputRestart ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "ShowInHUD", InputShowInHUD ),
DEFINE_INPUTFUNC( FIELD_VOID, "RoundSpawn", InputRoundSpawn ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetMaxTime", InputSetMaxTime ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "AutoCountdown", InputAutoCountdown ),
DEFINE_INPUTFUNC( FIELD_STRING, "AddTeamTime", InputAddTeamTime ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetSetupTime", InputSetSetupTime ),
DEFINE_OUTPUT( m_OnRoundStart, "OnRoundStart" ),
DEFINE_OUTPUT( m_OnFinished, "OnFinished" ),
DEFINE_OUTPUT( m_On5MinRemain, "On5MinRemain" ),
DEFINE_OUTPUT( m_On4MinRemain, "On4MinRemain" ),
DEFINE_OUTPUT( m_On3MinRemain, "On3MinRemain" ),
DEFINE_OUTPUT( m_On2MinRemain, "On2MinRemain" ),
DEFINE_OUTPUT( m_On1MinRemain, "On1MinRemain" ),
DEFINE_OUTPUT( m_On30SecRemain, "On30SecRemain" ),
DEFINE_OUTPUT( m_On10SecRemain, "On10SecRemain" ),
DEFINE_OUTPUT( m_On5SecRemain, "On5SecRemain" ),
DEFINE_OUTPUT( m_On4SecRemain, "On4SecRemain" ),
DEFINE_OUTPUT( m_On3SecRemain, "On3SecRemain" ),
DEFINE_OUTPUT( m_On2SecRemain, "On2SecRemain" ),
DEFINE_OUTPUT( m_On1SecRemain, "On1SecRemain" ),
DEFINE_OUTPUT( m_OnSetupStart, "OnSetupStart" ),
DEFINE_OUTPUT( m_OnSetupFinished, "OnSetupFinished" ),
END_DATADESC();
#endif
#ifndef CLIENT_DLL
#define ROUND_TIMER_THINK "CTeamplayRoundTimerThink"
#define ROUND_TIMER_SETUP_THINK "CTeamplayRoundTimerSetupThink"
#endif
//-----------------------------------------------------------------------------
// Purpose: constructor
//-----------------------------------------------------------------------------
CTeamRoundTimer::CTeamRoundTimer( void )
{
m_bTimerPaused = false;
m_flTimeRemaining = 0;
m_nTimerLength = 0;
m_nTimerInitialLength = 0;
m_nTimerMaxLength = 0;
m_flTimerEndTime = 0;
m_bIsDisabled = false;
m_bAutoCountdown = true;
m_nState.Set( RT_STATE_NORMAL ); // we'll assume no setup time for now
m_bStartPaused = true;
m_bShowTimeRemaining = true;
m_bFireFinished = true;
m_bFire5MinRemain = true;
m_bFire4MinRemain = true;
m_bFire3MinRemain = true;
m_bFire2MinRemain = true;
m_bFire1MinRemain = true;
m_bFire30SecRemain = true;
m_bFire10SecRemain = true;
m_bFire5SecRemain = true;
m_bFire4SecRemain = true;
m_bFire3SecRemain = true;
m_bFire2SecRemain = true;
m_bFire1SecRemain = true;
m_bStopWatchTimer = false;
m_flTotalTime = 0.0f;
m_nSetupTimeLength = 0;
#ifndef CLIENT_DLL
m_bPauseDueToWin = false;
m_bResetTimeOnRoundStart = false;
m_nTimeToUseAfterSetupFinished = 0;
m_flNextOvertimeNag = 0;
#endif
}
//-----------------------------------------------------------------------------
// Purpose: destructor
//-----------------------------------------------------------------------------
CTeamRoundTimer::~CTeamRoundTimer( void )
{
}
//-----------------------------------------------------------------------------
// Purpose: destructor
//-----------------------------------------------------------------------------
void CTeamRoundTimer::Precache( void )
{
#if defined( TF_DLL ) || defined( TF_CLIENT_DLL )
PrecacheScriptSound( ROUND_TIMER_60SECS );
PrecacheScriptSound( ROUND_TIMER_30SECS );
PrecacheScriptSound( ROUND_TIMER_10SECS );
PrecacheScriptSound( ROUND_TIMER_5SECS );
PrecacheScriptSound( ROUND_TIMER_4SECS );
PrecacheScriptSound( ROUND_TIMER_3SECS );
PrecacheScriptSound( ROUND_TIMER_2SECS );
PrecacheScriptSound( ROUND_TIMER_1SECS );
PrecacheScriptSound( ROUND_SETUP_60SECS );
PrecacheScriptSound( ROUND_SETUP_30SECS );
PrecacheScriptSound( ROUND_SETUP_10SECS );
PrecacheScriptSound( ROUND_SETUP_5SECS );
PrecacheScriptSound( ROUND_SETUP_4SECS );
PrecacheScriptSound( ROUND_SETUP_3SECS );
PrecacheScriptSound( ROUND_SETUP_2SECS );
PrecacheScriptSound( ROUND_SETUP_1SECS );
PrecacheScriptSound( ROUND_TIMER_TIME_ADDED );
PrecacheScriptSound( ROUND_TIMER_TIME_ADDED_LOSER );
PrecacheScriptSound( ROUND_TIMER_TIME_ADDED_WINNER );
PrecacheScriptSound( ROUND_START_BELL );
#endif // TF_DLL || TF_CLIENT_DLL
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::Activate( void )
{
BaseClass::Activate();
#ifndef CLIENT_DLL
if ( m_bShowInHUD )
{
SetActiveTimer( this );
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::Spawn( void )
{
Precache();
#ifdef CLIENT_DLL
SetNextClientThink( CLIENT_THINK_ALWAYS );
#else
int nTimerTime = 0;
// do we have a setup time?
if ( m_nSetupTimeLength > 0 )
{
nTimerTime = m_nSetupTimeLength;
SetState( RT_STATE_SETUP );
}
else
{
nTimerTime = m_nTimerInitialLength;
SetState( RT_STATE_NORMAL );
}
m_nTimeToUseAfterSetupFinished = m_nTimerInitialLength;
if ( IsDisabled() ) // we need to get the data initialized before actually become disabled
{
m_bIsDisabled = false;
PauseTimer(); // start paused
SetTimeRemaining( nTimerTime );
m_bIsDisabled = true;
}
else
{
PauseTimer(); // start paused
SetTimeRemaining( nTimerTime );
}
m_nTimerLength = nTimerTime;
BaseClass::Spawn();
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTeamRoundTimer::ShowInHud( void )
{
return m_bShowInHUD;
}
//-----------------------------------------------------------------------------
// Purpose: Gets the seconds left on the timer, paused or not.
//-----------------------------------------------------------------------------
float CTeamRoundTimer::GetTimeRemaining( void )
{
float flSecondsRemaining;
if ( IsStopWatchTimer() == true && m_bInCaptureWatchState == true )
{
flSecondsRemaining = m_flTotalTime;
}
else
{
if ( m_bTimerPaused )
{
flSecondsRemaining = m_flTimeRemaining;
}
else
{
flSecondsRemaining = m_flTimerEndTime - gpGlobals->curtime;
}
}
if ( flSecondsRemaining < 0 )
{
flSecondsRemaining = 0.0f;
}
return flSecondsRemaining;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::SetCaptureWatchState( bool bCaptureWatch )
{
m_bInCaptureWatchState = bCaptureWatch;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CTeamRoundTimer::GetTimerMaxLength( void )
{
if ( m_nState == RT_STATE_SETUP )
{
return m_nSetupTimeLength;
}
else
{
if ( m_nTimerMaxLength )
return m_nTimerMaxLength;
return m_nTimerLength;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::CalculateOutputMessages( void )
{
float flTime = GetTimeRemaining();
#ifndef GAME_DLL
// We need to add a couple seconds to the time remaining because we've probably lost ~0.5 seconds from the timer while
// waiting for the update to arrive from the server and we don't want to miss any critical countdown messages. If the time
// remaining is over 10 seconds...adding 2 seconds to the total when calculating our output messages won't affect anything
if ( flTime > 10.0f )
{
flTime += 2.0f;
}
#endif
m_bFireFinished = ( flTime > 0.0f );
m_bFire5MinRemain = ( flTime >= 300.0f );
m_bFire4MinRemain = ( flTime >= 240.0f );
m_bFire3MinRemain = ( flTime >= 180.0f );
m_bFire2MinRemain = ( flTime >= 120.0f );
m_bFire1MinRemain = ( flTime >= 60.0f );
m_bFire30SecRemain = ( flTime >= 30.0f );
m_bFire10SecRemain = ( flTime >= 10.0f );
m_bFire5SecRemain = ( flTime >= 5.0f );
m_bFire4SecRemain = ( flTime >= 4.0f );
m_bFire3SecRemain = ( flTime >= 3.0f );
m_bFire2SecRemain = ( flTime >= 2.0f );
m_bFire1SecRemain = ( flTime >= 1.0f );
}
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::ClientThink()
{
if ( IsDisabled() || m_bTimerPaused || IsInCommentaryMode() )
return;
if ( IsStopWatchTimer() == true && IsWatchingTimeStamps() == true )
return;
float flTime = GetTimeRemaining();
if ( flTime <= 61.0 && m_bFire1MinRemain )
{
m_bFire1MinRemain = false;
SendTimeWarning( RT_WARNING_60SECS );
}
else if ( flTime <= 31.0 && m_bFire30SecRemain )
{
m_bFire30SecRemain = false;
SendTimeWarning( RT_WARNING_30SECS );
}
else if ( flTime <= 11.0 && m_bFire10SecRemain )
{
m_bFire10SecRemain = false;
SendTimeWarning( RT_WARNING_10SECS );
}
else if ( flTime <= 6.0 && m_bFire5SecRemain )
{
m_bFire5SecRemain = false;
SendTimeWarning( RT_WARNING_5SECS );
}
else if ( flTime <= 5.0 && m_bFire4SecRemain )
{
m_bFire4SecRemain = false;
SendTimeWarning( RT_WARNING_4SECS );
}
else if ( flTime <= 4.0 && m_bFire3SecRemain )
{
m_bFire3SecRemain = false;
SendTimeWarning( RT_WARNING_3SECS );
}
else if ( flTime <= 3.0 && m_bFire2SecRemain )
{
m_bFire2SecRemain = false;
SendTimeWarning( RT_WARNING_2SECS );
}
else if ( flTime <= 2.0 && m_bFire1SecRemain )
{
m_bFire1SecRemain = false;
SendTimeWarning( RT_WARNING_1SECS );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::OnPreDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnPreDataChanged( updateType );
m_nOldTimerLength = m_nTimerLength;
m_nOldTimerState = m_nState;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( m_nOldTimerLength != m_nTimerLength )
{
// recalculate our output messages because the timer length has changed
CalculateOutputMessages();
}
// if we were in state_setup and now we're in state_normal, play the bell sound
if ( ( m_nOldTimerState == RT_STATE_SETUP ) && ( m_nState == RT_STATE_NORMAL ) )
{
SendTimeWarning( RT_WARNING_TIME_START );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const char *CTeamRoundTimer::GetTimeWarningSound( int nWarning )
{
const char *pszRetVal;
switch( nWarning )
{
case RT_WARNING_60SECS:
if ( m_nState == RT_STATE_SETUP )
{
pszRetVal = ROUND_SETUP_60SECS;
}
else
{
pszRetVal = ROUND_TIMER_60SECS;
}
break;
case RT_WARNING_30SECS:
if ( m_nState == RT_STATE_SETUP )
{
pszRetVal = ROUND_SETUP_30SECS;
}
else
{
pszRetVal = ROUND_TIMER_30SECS;
}
break;
case RT_WARNING_10SECS:
if ( m_nState == RT_STATE_SETUP )
{
pszRetVal = ROUND_SETUP_10SECS;
}
else
{
pszRetVal = ROUND_TIMER_10SECS;
}
break;
case RT_WARNING_5SECS:
if ( m_nState == RT_STATE_SETUP )
{
pszRetVal = ROUND_SETUP_5SECS;
}
else
{
pszRetVal = ROUND_TIMER_5SECS;
}
break;
case RT_WARNING_4SECS:
if ( m_nState == RT_STATE_SETUP )
{
pszRetVal = ROUND_SETUP_4SECS;
}
else
{
pszRetVal = ROUND_TIMER_4SECS;
}
break;
case RT_WARNING_3SECS:
if ( m_nState == RT_STATE_SETUP )
{
pszRetVal = ROUND_SETUP_3SECS;
}
else
{
pszRetVal = ROUND_TIMER_3SECS;
}
break;
case RT_WARNING_2SECS:
if ( m_nState == RT_STATE_SETUP )
{
pszRetVal = ROUND_SETUP_2SECS;
}
else
{
pszRetVal = ROUND_TIMER_2SECS;
}
break;
case RT_WARNING_1SECS:
if ( m_nState == RT_STATE_SETUP )
{
pszRetVal = ROUND_SETUP_1SECS;
}
else
{
pszRetVal = ROUND_TIMER_1SECS;
}
break;
case RT_WARNING_TIME_START:
pszRetVal = ROUND_START_BELL;
break;
default:
pszRetVal = "";
}
return pszRetVal;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::SendTimeWarning( int nWarning )
{
#if defined( TF_CLIENT_DLL )
// don't play any time warnings for Helltower
if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_HIGHTOWER ) )
return;
#endif
// 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 ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->IsInKothMode() )
{
bShouldPlaySound = true;
}
}
#ifdef TF_CLIENT_DLL
if ( bShouldPlaySound == true )
{
pPlayer->EmitSound( GetTimeWarningSound( nWarning ) );
}
#endif // TF_CLIENT_DLL
}
}
}
}
#else
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::SetState( int nState, bool bFireOutput )
{
m_nState = nState;
if ( nState == RT_STATE_SETUP )
{
if ( IsStopWatchTimer() == false )
{
TeamplayRoundBasedRules()->SetSetup( true );
}
SetTimerThink( RT_THINK_SETUP );
if ( bFireOutput )
{
m_OnSetupStart.FireOutput( this, this );
}
}
else
{
if ( IsStopWatchTimer() == false )
{
TeamplayRoundBasedRules()->SetSetup( false );
}
SetTimerThink( RT_THINK_NORMAL );
if ( bFireOutput )
{
m_OnRoundStart.FireOutput( this, this );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::SetTimerThink( int nType )
{
if ( nType == RT_THINK_SETUP )
{
SetContextThink( &CTeamRoundTimer::RoundTimerSetupThink, gpGlobals->curtime + 0.05, ROUND_TIMER_SETUP_THINK );
SetContextThink( NULL, 0, ROUND_TIMER_THINK );
}
else
{
SetContextThink( &CTeamRoundTimer::RoundTimerThink, gpGlobals->curtime + 0.05, ROUND_TIMER_THINK );
SetContextThink( NULL, 0, ROUND_TIMER_SETUP_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::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() )
{
if ( !TeamplayRoundBasedRules()->InOvertime() )
{
TeamplayRoundBasedRules()->SetOvertime( true );
}
#if defined( TF_DLL )
else
{
if ( tf_overtime_nag.GetBool() && ( gpGlobals->curtime > m_flNextOvertimeNag ) )
{
m_flNextOvertimeNag = gpGlobals->curtime + 1.0f;
if ( RandomInt( 0, 1 ) > 0 )
{
IGameEvent *event = gameeventmanager->CreateEvent( "overtime_nag" );
if ( event )
{
gameeventmanager->FireEvent( event );
}
}
}
}
#endif
}
SetContextThink( &CTeamRoundTimer::RoundTimerThink, gpGlobals->curtime + 0.05, 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::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: To set the initial timer duration
//-----------------------------------------------------------------------------
void CTeamRoundTimer::SetTimeRemaining( int iTimerSeconds )
{
if ( IsDisabled() )
return;
// make sure we don't go over our max length
if ( m_nTimerMaxLength > 0 )
{
if ( iTimerSeconds > m_nTimerMaxLength )
{
iTimerSeconds = m_nTimerMaxLength;
}
}
m_flTimeRemaining = (float)iTimerSeconds;
m_flTimerEndTime = gpGlobals->curtime + m_flTimeRemaining;
m_nTimerLength = iTimerSeconds;
CalculateOutputMessages();
}
//-----------------------------------------------------------------------------
// Purpose: To set the initial timer duration
//-----------------------------------------------------------------------------
void CTeamRoundTimer::SetStopWatchTimeStamp( void )
{
if ( IsDisabled() )
return;
if ( IsWatchingTimeStamps() == false )
return;
m_flTotalTime = m_flTotalTime + (gpGlobals->curtime - m_flTimerEndTime);
m_flTimerEndTime = gpGlobals->curtime;
CalculateOutputMessages();
}
//-----------------------------------------------------------------------------
// Purpose: Timer is paused at round end, stops the countdown
//-----------------------------------------------------------------------------
void CTeamRoundTimer::PauseTimer( void )
{
if ( IsDisabled() )
return;
if ( m_bTimerPaused == false )
{
m_bTimerPaused = true;
m_flTimeRemaining = m_flTimerEndTime - gpGlobals->curtime;
}
// Clear pause on win flag, because we've been set by the mapmaker
m_bPauseDueToWin = false;
}
//-----------------------------------------------------------------------------
// Purpose: To start or re-start the timer after a pause
//-----------------------------------------------------------------------------
void CTeamRoundTimer::ResumeTimer( void )
{
if ( IsDisabled() )
return;
if ( m_bTimerPaused == true )
{
m_bTimerPaused = false;
if ( IsStopWatchTimer() == true && m_bInCaptureWatchState == true )
{
m_flTimerEndTime = gpGlobals->curtime;
}
else
{
m_flTimerEndTime = gpGlobals->curtime + m_flTimeRemaining;
}
}
}
//-----------------------------------------------------------------------------
// 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() ) || ( TeamplayRoundBasedRules()->IsInKothMode() ) )
{
if ( !TeamplayRoundBasedRules()->InStalemate() && !TeamplayRoundBasedRules()->RoundHasBeenWon() && !TeamplayRoundBasedRules()->IsInKothMode() )
{
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: The timer is always transmitted to clients
//-----------------------------------------------------------------------------
int CTeamRoundTimer::UpdateTransmitState()
{
// ALWAYS transmit to all clients.
return SetTransmitState( FL_EDICT_ALWAYS );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::InputPause( inputdata_t &input )
{
PauseTimer();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::InputResume( inputdata_t &input )
{
ResumeTimer();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::InputSetTime( inputdata_t &input )
{
if ( IsStopWatchTimer() == true && IsWatchingTimeStamps() == true )
{
SetStopWatchTimeStamp();
}
else
{
int nSeconds = input.value.Int();
SetTimeRemaining( nSeconds );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::InputSetMaxTime( inputdata_t &input )
{
int nSeconds = input.value.Int();
m_nTimerMaxLength = nSeconds;
if ( m_nTimerMaxLength > 0 )
{
// make sure our current time is not above the max length
if ( GetTimeRemaining() > m_nTimerMaxLength )
{
SetTimeRemaining( m_nTimerMaxLength );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::InputAddTime( inputdata_t &input )
{
int nSeconds = input.value.Int();
AddTimerSeconds( nSeconds );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::InputAddTeamTime( inputdata_t &input )
{
char token[128];
const char *p = STRING( input.value.StringID() );
int nTeam = TEAM_UNASSIGNED;
int nSeconds = 0;
// get the team
p = nexttoken( token, p, ' ' );
if ( token )
{
nTeam = Q_atoi( token );
}
// get the time
p = nexttoken( token, p, ' ' );
if ( token )
{
nSeconds = Q_atoi( token );
}
if ( nSeconds != 0 )
{
AddTimerSeconds( nSeconds, nTeam );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::InputRestart( inputdata_t &input )
{
SetTimeRemaining( m_nTimerInitialLength );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::InputEnable( inputdata_t &input )
{
m_bIsDisabled = false;
ResumeTimer();
if ( m_bShowInHUD )
{
SetActiveTimer( this );
}
if ( IsStopWatchTimer() == true && IsWatchingTimeStamps() == true )
{
m_flTimerEndTime = gpGlobals->curtime;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::InputDisable( inputdata_t &input )
{
PauseTimer();
m_bIsDisabled = true;
if ( m_bShowInHUD )
{
SetActiveTimer( NULL );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::InputShowInHUD( inputdata_t &input )
{
int nShow = input.value.Int();
if ( m_bShowInHUD && !nShow )
{
SetActiveTimer( NULL );
}
else if ( nShow == 1 )
{
SetActiveTimer( this );
SetState( m_nState, false ); // set our current state again so the gamerules are updated with our setup state
}
m_bShowInHUD = ( nShow == 1 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::InputAutoCountdown( inputdata_t &input )
{
int nAuto = input.value.Int();
SetAutoCountdown( nAuto == 1 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::InputSetSetupTime( inputdata_t &input )
{
int nSetupTime = input.value.Int();
if ( nSetupTime >= 0 )
{
m_nSetupTimeLength = nSetupTime;
}
if ( !IsDisabled() )
{
if ( m_nState == RT_STATE_SETUP )
{
SetTimeRemaining( m_nSetupTimeLength );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::SetActiveTimer( CTeamRoundTimer *pNewlyActive )
{
CBaseEntity *pChosenTimer = pNewlyActive;
// Ensure all other timers are off.
CBaseEntity *pEntity = NULL;
while ((pEntity = gEntList.FindEntityByClassname( pEntity, "team_round_timer" )) != NULL)
{
if ( pEntity == pNewlyActive )
continue;
CTeamRoundTimer *pTimer = assert_cast< CTeamRoundTimer* >( pEntity );
if ( !pTimer->IsDisabled() && pTimer->ShowInHud() )
{
if ( pChosenTimer )
{
// Turn off all other hud timers
pTimer->SetShowInHud( false );
}
else
{
// Found a timer. Use it.
pChosenTimer = pTimer;
}
}
}
ObjectiveResource()->SetTimerInHUD( pChosenTimer );
}
#endif