|
|
//========= Copyright © 1996-2006, 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"
#else
#include "team.h"
#include "team_objectiveresource.h"
#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();
#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 ) { FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) { ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); GetClientMode()->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_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_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_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_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_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;
#ifndef CLIENT_DLL
m_bPauseDueToWin = false; m_bResetTimeOnRoundStart = false; m_nTimeToUseAfterSetupFinished = 0; #endif
}
//-----------------------------------------------------------------------------
// Purpose: destructor
//-----------------------------------------------------------------------------
CTeamRoundTimer::~CTeamRoundTimer( void ) {
}
//-----------------------------------------------------------------------------
// Purpose: destructor
//-----------------------------------------------------------------------------
void CTeamRoundTimer::Precache( void ) { 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 ); }
//-----------------------------------------------------------------------------
// 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 ) { // 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() ) { HACK_GETLOCALPLAYER_GUARD( "CTeamRoundTimer::SendTimeWarning" );
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 ) ); } } } } }
#else
//-----------------------------------------------------------------------------
// 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 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() ) { 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::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() ) { 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: 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 ); }
m_bShowInHUD = ( nShow == 1 ); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTeamRoundTimer::InputAutoCountdown( inputdata_t &input ) { int nAuto = input.value.Int(); SetAutoCountdown( nAuto == 1 ); }
//-----------------------------------------------------------------------------
// 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
|