Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1543 lines
43 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Team gamerules round timer
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "teamplay_round_timer.h"
  9. #include "teamplayroundbased_gamerules.h"
  10. #ifdef CLIENT_DLL
  11. #include "iclientmode.h"
  12. #include "vgui_controls/AnimationController.h"
  13. #include "c_playerresource.h"
  14. #include "c_team_objectiveresource.h"
  15. #if defined( TF_CLIENT_DLL )
  16. #include "tf_gamerules.h"
  17. #include "c_tf_player.h"
  18. #endif // TF_CLIENT_DLL
  19. #else
  20. #include "team.h"
  21. #include "team_objectiveresource.h"
  22. #if defined( TF_DLL )
  23. #include "tf_player.h"
  24. #endif // TF_DLL
  25. #endif
  26. #define ROUND_TIMER_60SECS "Announcer.RoundEnds60seconds"
  27. #define ROUND_TIMER_30SECS "Announcer.RoundEnds30seconds"
  28. #define ROUND_TIMER_10SECS "Announcer.RoundEnds10seconds"
  29. #define ROUND_TIMER_5SECS "Announcer.RoundEnds5seconds"
  30. #define ROUND_TIMER_4SECS "Announcer.RoundEnds4seconds"
  31. #define ROUND_TIMER_3SECS "Announcer.RoundEnds3seconds"
  32. #define ROUND_TIMER_2SECS "Announcer.RoundEnds2seconds"
  33. #define ROUND_TIMER_1SECS "Announcer.RoundEnds1seconds"
  34. #define ROUND_SETUP_60SECS "Announcer.RoundBegins60Seconds"
  35. #define ROUND_SETUP_30SECS "Announcer.RoundBegins30Seconds"
  36. #define ROUND_SETUP_10SECS "Announcer.RoundBegins10Seconds"
  37. #define ROUND_SETUP_5SECS "Announcer.RoundBegins5Seconds"
  38. #define ROUND_SETUP_4SECS "Announcer.RoundBegins4Seconds"
  39. #define ROUND_SETUP_3SECS "Announcer.RoundBegins3Seconds"
  40. #define ROUND_SETUP_2SECS "Announcer.RoundBegins2Seconds"
  41. #define ROUND_SETUP_1SECS "Announcer.RoundBegins1Seconds"
  42. #ifdef TF_CLIENT_DLL
  43. #define MERASMUS_SETUP_5SECS "Merasmus.RoundBegins5Seconds"
  44. #define MERASMUS_SETUP_4SECS "Merasmus.RoundBegins4Seconds"
  45. #define MERASMUS_SETUP_3SECS "Merasmus.RoundBegins3Seconds"
  46. #define MERASMUS_SETUP_2SECS "Merasmus.RoundBegins2Seconds"
  47. #define MERASMUS_SETUP_1SECS "Merasmus.RoundBegins1Seconds"
  48. #endif
  49. #define ROUND_START_BELL "Ambient.Siren"
  50. #define ROUND_TIMER_TIME_ADDED "Announcer.TimeAdded"
  51. #define ROUND_TIMER_TIME_ADDED_LOSER "Announcer.TimeAddedForEnemy"
  52. #define ROUND_TIMER_TIME_ADDED_WINNER "Announcer.TimeAwardedForTeam"
  53. enum
  54. {
  55. RT_THINK_SETUP,
  56. RT_THINK_NORMAL,
  57. };
  58. enum
  59. {
  60. RT_WARNING_60SECS,
  61. RT_WARNING_30SECS,
  62. RT_WARNING_10SECS,
  63. RT_WARNING_5SECS,
  64. RT_WARNING_4SECS,
  65. RT_WARNING_3SECS,
  66. RT_WARNING_2SECS,
  67. RT_WARNING_1SECS,
  68. RT_WARNING_TIME_START,
  69. };
  70. // memdbgon must be the last include file in a .cpp file!!!
  71. #include "tier0/memdbgon.h"
  72. extern bool IsInCommentaryMode();
  73. #if defined( GAME_DLL ) && defined( TF_DLL )
  74. ConVar tf_overtime_nag( "tf_overtime_nag", "0", FCVAR_NOTIFY, "Announcer overtime nag." );
  75. #endif
  76. #ifdef CLIENT_DLL
  77. // Use this proxy to flash the round timer whenever the timer is restarted
  78. // because trapping the round start event doesn't work ( the event also flushes
  79. // all hud events and obliterates our TimerFlash event )
  80. static void RecvProxy_TimerPaused( const CRecvProxyData *pData, void *pStruct, void *pOut )
  81. {
  82. CTeamRoundTimer *pTimer = (CTeamRoundTimer *) pStruct;
  83. bool bTimerPaused = ( pData->m_Value.m_Int > 0 );
  84. if ( bTimerPaused == false )
  85. {
  86. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "TimerFlash" );
  87. }
  88. if ( pTimer )
  89. {
  90. pTimer->InternalSetPaused( bTimerPaused );
  91. }
  92. }
  93. #endif
  94. LINK_ENTITY_TO_CLASS( team_round_timer, CTeamRoundTimer );
  95. PRECACHE_REGISTER( team_round_timer );
  96. IMPLEMENT_NETWORKCLASS_ALIASED( TeamRoundTimer, DT_TeamRoundTimer )
  97. BEGIN_NETWORK_TABLE_NOBASE( CTeamRoundTimer, DT_TeamRoundTimer )
  98. #ifdef CLIENT_DLL
  99. RecvPropInt( RECVINFO( m_bTimerPaused ), 0, RecvProxy_TimerPaused ),
  100. RecvPropTime( RECVINFO( m_flTimeRemaining ) ),
  101. RecvPropTime( RECVINFO( m_flTimerEndTime ) ),
  102. RecvPropInt( RECVINFO( m_nTimerMaxLength ) ),
  103. RecvPropBool( RECVINFO( m_bIsDisabled ) ),
  104. RecvPropBool( RECVINFO( m_bShowInHUD ) ),
  105. RecvPropInt( RECVINFO( m_nTimerLength ) ),
  106. RecvPropInt( RECVINFO( m_nTimerInitialLength ) ),
  107. RecvPropBool( RECVINFO( m_bAutoCountdown ) ),
  108. RecvPropInt( RECVINFO( m_nSetupTimeLength ) ),
  109. RecvPropInt( RECVINFO( m_nState ) ),
  110. RecvPropBool( RECVINFO( m_bStartPaused ) ),
  111. RecvPropBool( RECVINFO( m_bShowTimeRemaining ) ),
  112. RecvPropBool( RECVINFO( m_bInCaptureWatchState ) ),
  113. RecvPropBool( RECVINFO( m_bStopWatchTimer ) ),
  114. RecvPropTime( RECVINFO( m_flTotalTime ) ),
  115. #else
  116. SendPropBool( SENDINFO( m_bTimerPaused ) ),
  117. SendPropTime( SENDINFO( m_flTimeRemaining ) ),
  118. SendPropTime( SENDINFO( m_flTimerEndTime ) ),
  119. SendPropInt( SENDINFO( m_nTimerMaxLength ) ),
  120. SendPropBool( SENDINFO( m_bIsDisabled ) ),
  121. SendPropBool( SENDINFO( m_bShowInHUD ) ),
  122. SendPropInt( SENDINFO( m_nTimerLength ) ),
  123. SendPropInt( SENDINFO( m_nTimerInitialLength ) ),
  124. SendPropBool( SENDINFO( m_bAutoCountdown ) ),
  125. SendPropInt( SENDINFO( m_nSetupTimeLength ) ),
  126. SendPropInt( SENDINFO( m_nState ) ),
  127. SendPropBool( SENDINFO( m_bStartPaused ) ),
  128. SendPropBool( SENDINFO( m_bShowTimeRemaining ) ),
  129. SendPropBool( SENDINFO( m_bStopWatchTimer ) ),
  130. SendPropBool( SENDINFO( m_bInCaptureWatchState ) ),
  131. SendPropTime( SENDINFO( m_flTotalTime ) ),
  132. #endif
  133. END_NETWORK_TABLE()
  134. #ifndef CLIENT_DLL
  135. BEGIN_DATADESC(CTeamRoundTimer)
  136. DEFINE_KEYFIELD( m_nTimerInitialLength, FIELD_INTEGER, "timer_length" ),
  137. DEFINE_KEYFIELD( m_nTimerMaxLength, FIELD_INTEGER, "max_length" ),
  138. DEFINE_KEYFIELD( m_bShowInHUD, FIELD_BOOLEAN, "show_in_hud" ),
  139. DEFINE_KEYFIELD( m_bIsDisabled, FIELD_BOOLEAN, "StartDisabled" ),
  140. DEFINE_KEYFIELD( m_bAutoCountdown, FIELD_BOOLEAN, "auto_countdown" ),
  141. DEFINE_KEYFIELD( m_nSetupTimeLength, FIELD_INTEGER, "setup_length" ),
  142. DEFINE_KEYFIELD( m_bResetTimeOnRoundStart, FIELD_BOOLEAN, "reset_time" ),
  143. DEFINE_KEYFIELD( m_bStartPaused, FIELD_BOOLEAN, "start_paused" ),
  144. DEFINE_KEYFIELD( m_bShowTimeRemaining, FIELD_BOOLEAN, "show_time_remaining" ),
  145. DEFINE_FUNCTION( RoundTimerSetupThink ),
  146. DEFINE_FUNCTION( RoundTimerThink ),
  147. DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
  148. DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
  149. DEFINE_INPUTFUNC( FIELD_VOID, "Pause", InputPause ),
  150. DEFINE_INPUTFUNC( FIELD_VOID, "Resume", InputResume ),
  151. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetTime", InputSetTime ),
  152. DEFINE_INPUTFUNC( FIELD_INTEGER, "AddTime", InputAddTime ),
  153. DEFINE_INPUTFUNC( FIELD_VOID, "Restart", InputRestart ),
  154. DEFINE_INPUTFUNC( FIELD_INTEGER, "ShowInHUD", InputShowInHUD ),
  155. DEFINE_INPUTFUNC( FIELD_VOID, "RoundSpawn", InputRoundSpawn ),
  156. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetMaxTime", InputSetMaxTime ),
  157. DEFINE_INPUTFUNC( FIELD_INTEGER, "AutoCountdown", InputAutoCountdown ),
  158. DEFINE_INPUTFUNC( FIELD_STRING, "AddTeamTime", InputAddTeamTime ),
  159. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetSetupTime", InputSetSetupTime ),
  160. DEFINE_OUTPUT( m_OnRoundStart, "OnRoundStart" ),
  161. DEFINE_OUTPUT( m_OnFinished, "OnFinished" ),
  162. DEFINE_OUTPUT( m_On5MinRemain, "On5MinRemain" ),
  163. DEFINE_OUTPUT( m_On4MinRemain, "On4MinRemain" ),
  164. DEFINE_OUTPUT( m_On3MinRemain, "On3MinRemain" ),
  165. DEFINE_OUTPUT( m_On2MinRemain, "On2MinRemain" ),
  166. DEFINE_OUTPUT( m_On1MinRemain, "On1MinRemain" ),
  167. DEFINE_OUTPUT( m_On30SecRemain, "On30SecRemain" ),
  168. DEFINE_OUTPUT( m_On10SecRemain, "On10SecRemain" ),
  169. DEFINE_OUTPUT( m_On5SecRemain, "On5SecRemain" ),
  170. DEFINE_OUTPUT( m_On4SecRemain, "On4SecRemain" ),
  171. DEFINE_OUTPUT( m_On3SecRemain, "On3SecRemain" ),
  172. DEFINE_OUTPUT( m_On2SecRemain, "On2SecRemain" ),
  173. DEFINE_OUTPUT( m_On1SecRemain, "On1SecRemain" ),
  174. DEFINE_OUTPUT( m_OnSetupStart, "OnSetupStart" ),
  175. DEFINE_OUTPUT( m_OnSetupFinished, "OnSetupFinished" ),
  176. END_DATADESC();
  177. #endif
  178. #ifndef CLIENT_DLL
  179. #define ROUND_TIMER_THINK "CTeamplayRoundTimerThink"
  180. #define ROUND_TIMER_SETUP_THINK "CTeamplayRoundTimerSetupThink"
  181. #endif
  182. //-----------------------------------------------------------------------------
  183. // Purpose: constructor
  184. //-----------------------------------------------------------------------------
  185. CTeamRoundTimer::CTeamRoundTimer( void )
  186. {
  187. m_bTimerPaused = false;
  188. m_flTimeRemaining = 0;
  189. m_nTimerLength = 0;
  190. m_nTimerInitialLength = 0;
  191. m_nTimerMaxLength = 0;
  192. m_flTimerEndTime = 0;
  193. m_bIsDisabled = false;
  194. m_bAutoCountdown = true;
  195. m_nState.Set( RT_STATE_NORMAL ); // we'll assume no setup time for now
  196. m_bStartPaused = true;
  197. m_bShowTimeRemaining = true;
  198. m_bFireFinished = true;
  199. m_bFire5MinRemain = true;
  200. m_bFire4MinRemain = true;
  201. m_bFire3MinRemain = true;
  202. m_bFire2MinRemain = true;
  203. m_bFire1MinRemain = true;
  204. m_bFire30SecRemain = true;
  205. m_bFire10SecRemain = true;
  206. m_bFire5SecRemain = true;
  207. m_bFire4SecRemain = true;
  208. m_bFire3SecRemain = true;
  209. m_bFire2SecRemain = true;
  210. m_bFire1SecRemain = true;
  211. m_bStopWatchTimer = false;
  212. m_flTotalTime = 0.0f;
  213. m_nSetupTimeLength = 0;
  214. #ifndef CLIENT_DLL
  215. m_bPauseDueToWin = false;
  216. m_bResetTimeOnRoundStart = false;
  217. m_nTimeToUseAfterSetupFinished = 0;
  218. m_flNextOvertimeNag = 0;
  219. m_flLastTime = 0.f;
  220. #endif
  221. }
  222. //-----------------------------------------------------------------------------
  223. // Purpose: destructor
  224. //-----------------------------------------------------------------------------
  225. CTeamRoundTimer::~CTeamRoundTimer( void )
  226. {
  227. }
  228. //-----------------------------------------------------------------------------
  229. // Purpose: destructor
  230. //-----------------------------------------------------------------------------
  231. void CTeamRoundTimer::Precache( void )
  232. {
  233. #if defined( TF_DLL ) || defined( TF_CLIENT_DLL )
  234. PrecacheScriptSound( ROUND_TIMER_60SECS );
  235. PrecacheScriptSound( ROUND_TIMER_30SECS );
  236. PrecacheScriptSound( ROUND_TIMER_10SECS );
  237. PrecacheScriptSound( ROUND_TIMER_5SECS );
  238. PrecacheScriptSound( ROUND_TIMER_4SECS );
  239. PrecacheScriptSound( ROUND_TIMER_3SECS );
  240. PrecacheScriptSound( ROUND_TIMER_2SECS );
  241. PrecacheScriptSound( ROUND_TIMER_1SECS );
  242. PrecacheScriptSound( ROUND_SETUP_60SECS );
  243. PrecacheScriptSound( ROUND_SETUP_30SECS );
  244. PrecacheScriptSound( ROUND_SETUP_10SECS );
  245. PrecacheScriptSound( ROUND_SETUP_5SECS );
  246. PrecacheScriptSound( ROUND_SETUP_4SECS );
  247. PrecacheScriptSound( ROUND_SETUP_3SECS );
  248. PrecacheScriptSound( ROUND_SETUP_2SECS );
  249. PrecacheScriptSound( ROUND_SETUP_1SECS );
  250. PrecacheScriptSound( ROUND_TIMER_TIME_ADDED );
  251. PrecacheScriptSound( ROUND_TIMER_TIME_ADDED_LOSER );
  252. PrecacheScriptSound( ROUND_TIMER_TIME_ADDED_WINNER );
  253. PrecacheScriptSound( ROUND_START_BELL );
  254. #ifdef TF_CLIENT_DLL
  255. PrecacheScriptSound( MERASMUS_SETUP_5SECS );
  256. PrecacheScriptSound( MERASMUS_SETUP_4SECS );
  257. PrecacheScriptSound( MERASMUS_SETUP_3SECS );
  258. PrecacheScriptSound( MERASMUS_SETUP_2SECS );
  259. PrecacheScriptSound( MERASMUS_SETUP_1SECS );
  260. #endif // TF_CLIENT_DLL
  261. #endif // TF_DLL || TF_CLIENT_DLL
  262. }
  263. //-----------------------------------------------------------------------------
  264. // Purpose:
  265. //-----------------------------------------------------------------------------
  266. void CTeamRoundTimer::Activate( void )
  267. {
  268. BaseClass::Activate();
  269. #ifndef CLIENT_DLL
  270. if ( m_bShowInHUD )
  271. {
  272. SetActiveTimer( this );
  273. }
  274. #endif
  275. }
  276. //-----------------------------------------------------------------------------
  277. // Purpose:
  278. //-----------------------------------------------------------------------------
  279. void CTeamRoundTimer::Spawn( void )
  280. {
  281. Precache();
  282. #ifdef CLIENT_DLL
  283. SetNextClientThink( CLIENT_THINK_ALWAYS );
  284. #else
  285. int nTimerTime = 0;
  286. // do we have a setup time?
  287. if ( m_nSetupTimeLength > 0 )
  288. {
  289. nTimerTime = m_nSetupTimeLength;
  290. SetState( RT_STATE_SETUP );
  291. }
  292. else
  293. {
  294. nTimerTime = m_nTimerInitialLength;
  295. SetState( RT_STATE_NORMAL );
  296. }
  297. m_nTimeToUseAfterSetupFinished = m_nTimerInitialLength;
  298. if ( IsDisabled() ) // we need to get the data initialized before actually become disabled
  299. {
  300. m_bIsDisabled = false;
  301. PauseTimer(); // start paused
  302. SetTimeRemaining( nTimerTime );
  303. m_bIsDisabled = true;
  304. }
  305. else
  306. {
  307. PauseTimer(); // start paused
  308. SetTimeRemaining( nTimerTime );
  309. }
  310. m_nTimerLength = nTimerTime;
  311. BaseClass::Spawn();
  312. #endif
  313. }
  314. //-----------------------------------------------------------------------------
  315. // Purpose:
  316. //-----------------------------------------------------------------------------
  317. bool CTeamRoundTimer::ShowInHud( void )
  318. {
  319. return m_bShowInHUD;
  320. }
  321. //-----------------------------------------------------------------------------
  322. // Purpose: Gets the seconds left on the timer, paused or not.
  323. //-----------------------------------------------------------------------------
  324. float CTeamRoundTimer::GetTimeRemaining( void )
  325. {
  326. float flSecondsRemaining;
  327. if ( IsStopWatchTimer() == true && m_bInCaptureWatchState == true )
  328. {
  329. flSecondsRemaining = m_flTotalTime;
  330. }
  331. else
  332. {
  333. if ( m_bTimerPaused )
  334. {
  335. flSecondsRemaining = m_flTimeRemaining;
  336. }
  337. else
  338. {
  339. flSecondsRemaining = m_flTimerEndTime - gpGlobals->curtime;
  340. }
  341. }
  342. if ( flSecondsRemaining < 0 )
  343. {
  344. flSecondsRemaining = 0.0f;
  345. }
  346. return flSecondsRemaining;
  347. }
  348. //-----------------------------------------------------------------------------
  349. // Purpose:
  350. //-----------------------------------------------------------------------------
  351. void CTeamRoundTimer::SetCaptureWatchState( bool bCaptureWatch )
  352. {
  353. m_bInCaptureWatchState = bCaptureWatch;
  354. }
  355. //-----------------------------------------------------------------------------
  356. // Purpose:
  357. //-----------------------------------------------------------------------------
  358. int CTeamRoundTimer::GetTimerMaxLength( void )
  359. {
  360. if ( m_nState == RT_STATE_SETUP )
  361. {
  362. return m_nSetupTimeLength;
  363. }
  364. else
  365. {
  366. if ( m_nTimerMaxLength )
  367. return m_nTimerMaxLength;
  368. return m_nTimerLength;
  369. }
  370. }
  371. //-----------------------------------------------------------------------------
  372. // Purpose:
  373. //-----------------------------------------------------------------------------
  374. void CTeamRoundTimer::CalculateOutputMessages( void )
  375. {
  376. float flTime = GetTimeRemaining();
  377. #ifndef GAME_DLL
  378. // We need to add a couple seconds to the time remaining because we've probably lost ~0.5 seconds from the timer while
  379. // waiting for the update to arrive from the server and we don't want to miss any critical countdown messages. If the time
  380. // remaining is over 10 seconds...adding 2 seconds to the total when calculating our output messages won't affect anything
  381. if ( flTime > 10.0f )
  382. {
  383. flTime += 2.0f;
  384. }
  385. #endif
  386. m_bFireFinished = ( flTime > 0.0f );
  387. m_bFire5MinRemain = ( flTime >= 300.0f );
  388. m_bFire4MinRemain = ( flTime >= 240.0f );
  389. m_bFire3MinRemain = ( flTime >= 180.0f );
  390. m_bFire2MinRemain = ( flTime >= 120.0f );
  391. m_bFire1MinRemain = ( flTime >= 60.0f );
  392. m_bFire30SecRemain = ( flTime >= 30.0f );
  393. m_bFire10SecRemain = ( flTime >= 10.0f );
  394. m_bFire5SecRemain = ( flTime >= 5.0f );
  395. m_bFire4SecRemain = ( flTime >= 4.0f );
  396. m_bFire3SecRemain = ( flTime >= 3.0f );
  397. m_bFire2SecRemain = ( flTime >= 2.0f );
  398. m_bFire1SecRemain = ( flTime >= 1.0f );
  399. }
  400. #ifdef CLIENT_DLL
  401. //-----------------------------------------------------------------------------
  402. // Purpose:
  403. //-----------------------------------------------------------------------------
  404. void CTeamRoundTimer::ClientThink()
  405. {
  406. if ( IsDisabled() || m_bTimerPaused || IsInCommentaryMode() )
  407. return;
  408. if ( IsStopWatchTimer() == true && IsWatchingTimeStamps() == true )
  409. return;
  410. float flTime = GetTimeRemaining();
  411. if ( flTime <= 61.0 && m_bFire1MinRemain )
  412. {
  413. m_bFire1MinRemain = false;
  414. SendTimeWarning( RT_WARNING_60SECS );
  415. }
  416. else if ( flTime <= 31.0 && m_bFire30SecRemain )
  417. {
  418. m_bFire30SecRemain = false;
  419. SendTimeWarning( RT_WARNING_30SECS );
  420. }
  421. else if ( flTime <= 11.0 && m_bFire10SecRemain )
  422. {
  423. m_bFire10SecRemain = false;
  424. SendTimeWarning( RT_WARNING_10SECS );
  425. }
  426. else if ( flTime <= 6.0 && m_bFire5SecRemain )
  427. {
  428. m_bFire5SecRemain = false;
  429. SendTimeWarning( RT_WARNING_5SECS );
  430. }
  431. else if ( flTime <= 5.0 && m_bFire4SecRemain )
  432. {
  433. m_bFire4SecRemain = false;
  434. SendTimeWarning( RT_WARNING_4SECS );
  435. }
  436. else if ( flTime <= 4.0 && m_bFire3SecRemain )
  437. {
  438. m_bFire3SecRemain = false;
  439. SendTimeWarning( RT_WARNING_3SECS );
  440. }
  441. else if ( flTime <= 3.0 && m_bFire2SecRemain )
  442. {
  443. m_bFire2SecRemain = false;
  444. SendTimeWarning( RT_WARNING_2SECS );
  445. }
  446. else if ( flTime <= 2.0 && m_bFire1SecRemain )
  447. {
  448. m_bFire1SecRemain = false;
  449. SendTimeWarning( RT_WARNING_1SECS );
  450. }
  451. }
  452. //-----------------------------------------------------------------------------
  453. // Purpose:
  454. //-----------------------------------------------------------------------------
  455. void CTeamRoundTimer::OnPreDataChanged( DataUpdateType_t updateType )
  456. {
  457. BaseClass::OnPreDataChanged( updateType );
  458. m_nOldTimerLength = m_nTimerLength;
  459. m_nOldTimerState = m_nState;
  460. }
  461. //-----------------------------------------------------------------------------
  462. // Purpose:
  463. //-----------------------------------------------------------------------------
  464. void CTeamRoundTimer::OnDataChanged( DataUpdateType_t updateType )
  465. {
  466. BaseClass::OnDataChanged( updateType );
  467. if ( m_nOldTimerLength != m_nTimerLength )
  468. {
  469. // recalculate our output messages because the timer length has changed
  470. CalculateOutputMessages();
  471. }
  472. // if we were in state_setup and now we're in state_normal, play the bell sound
  473. if ( ( m_nOldTimerState == RT_STATE_SETUP ) && ( m_nState == RT_STATE_NORMAL ) )
  474. {
  475. SendTimeWarning( RT_WARNING_TIME_START );
  476. }
  477. }
  478. //-----------------------------------------------------------------------------
  479. // Purpose:
  480. //-----------------------------------------------------------------------------
  481. const char *CTeamRoundTimer::GetTimeWarningSound( int nWarning )
  482. {
  483. const char *pszRetVal;
  484. switch( nWarning )
  485. {
  486. case RT_WARNING_60SECS:
  487. if ( m_nState == RT_STATE_SETUP )
  488. {
  489. pszRetVal = ROUND_SETUP_60SECS;
  490. }
  491. else
  492. {
  493. pszRetVal = ROUND_TIMER_60SECS;
  494. }
  495. break;
  496. case RT_WARNING_30SECS:
  497. if ( m_nState == RT_STATE_SETUP )
  498. {
  499. pszRetVal = ROUND_SETUP_30SECS;
  500. }
  501. else
  502. {
  503. pszRetVal = ROUND_TIMER_30SECS;
  504. }
  505. break;
  506. case RT_WARNING_10SECS:
  507. if ( m_nState == RT_STATE_SETUP )
  508. {
  509. pszRetVal = ROUND_SETUP_10SECS;
  510. }
  511. else
  512. {
  513. pszRetVal = ROUND_TIMER_10SECS;
  514. }
  515. break;
  516. case RT_WARNING_5SECS:
  517. if ( m_nState == RT_STATE_SETUP )
  518. {
  519. #ifdef TF_CLIENT_DLL
  520. if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ) )
  521. {
  522. pszRetVal = MERASMUS_SETUP_5SECS;
  523. }
  524. else
  525. #endif
  526. {
  527. pszRetVal = ROUND_SETUP_5SECS;
  528. }
  529. }
  530. else
  531. {
  532. pszRetVal = ROUND_TIMER_5SECS;
  533. }
  534. break;
  535. case RT_WARNING_4SECS:
  536. if ( m_nState == RT_STATE_SETUP )
  537. {
  538. #ifdef TF_CLIENT_DLL
  539. if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ) )
  540. {
  541. pszRetVal = MERASMUS_SETUP_4SECS;
  542. }
  543. else
  544. #endif
  545. {
  546. pszRetVal = ROUND_SETUP_4SECS;
  547. }
  548. }
  549. else
  550. {
  551. pszRetVal = ROUND_TIMER_4SECS;
  552. }
  553. break;
  554. case RT_WARNING_3SECS:
  555. if ( m_nState == RT_STATE_SETUP )
  556. {
  557. #ifdef TF_CLIENT_DLL
  558. if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ) )
  559. {
  560. pszRetVal = MERASMUS_SETUP_3SECS;
  561. }
  562. else
  563. #endif
  564. {
  565. pszRetVal = ROUND_SETUP_3SECS;
  566. }
  567. }
  568. else
  569. {
  570. pszRetVal = ROUND_TIMER_3SECS;
  571. }
  572. break;
  573. case RT_WARNING_2SECS:
  574. if ( m_nState == RT_STATE_SETUP )
  575. {
  576. #ifdef TF_CLIENT_DLL
  577. if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ) )
  578. {
  579. pszRetVal = MERASMUS_SETUP_2SECS;
  580. }
  581. else
  582. #endif
  583. {
  584. pszRetVal = ROUND_SETUP_2SECS;
  585. }
  586. }
  587. else
  588. {
  589. pszRetVal = ROUND_TIMER_2SECS;
  590. }
  591. break;
  592. case RT_WARNING_1SECS:
  593. if ( m_nState == RT_STATE_SETUP )
  594. {
  595. #ifdef TF_CLIENT_DLL
  596. if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ) )
  597. {
  598. pszRetVal = MERASMUS_SETUP_1SECS;
  599. }
  600. else
  601. #endif
  602. {
  603. pszRetVal = ROUND_SETUP_1SECS;
  604. }
  605. }
  606. else
  607. {
  608. pszRetVal = ROUND_TIMER_1SECS;
  609. }
  610. break;
  611. case RT_WARNING_TIME_START:
  612. pszRetVal = ROUND_START_BELL;
  613. break;
  614. default:
  615. pszRetVal = "";
  616. }
  617. return pszRetVal;
  618. }
  619. //-----------------------------------------------------------------------------
  620. // Purpose:
  621. //-----------------------------------------------------------------------------
  622. void CTeamRoundTimer::SendTimeWarning( int nWarning )
  623. {
  624. #if defined( TF_CLIENT_DLL )
  625. // don't play any time warnings for Helltower
  626. if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_HIGHTOWER ) )
  627. return;
  628. #endif
  629. // don't play sounds if the level designer has turned them off or if it's during the WaitingForPlayers time
  630. if ( !m_bTimerPaused && m_bAutoCountdown && !TeamplayRoundBasedRules()->IsInWaitingForPlayers() )
  631. {
  632. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  633. if ( pPlayer )
  634. {
  635. if ( ObjectiveResource() )
  636. {
  637. bool bShouldPlaySound = false;
  638. if ( TeamplayRoundBasedRules()->IsInTournamentMode() == true && TeamplayRoundBasedRules()->IsInStopWatch() == true )
  639. {
  640. int iActiveTimer = ObjectiveResource()->GetTimerToShowInHUD();
  641. int iStopWatchTimer = ObjectiveResource()->GetStopWatchTimer();
  642. if ( IsStopWatchTimer() == true && IsWatchingTimeStamps() == false )
  643. {
  644. CTeamRoundTimer *pTimer = dynamic_cast< CTeamRoundTimer* >( ClientEntityList().GetEnt( iActiveTimer ) );
  645. if ( pTimer && pTimer->IsTimerPaused() == false && pTimer->GetTimeRemaining() > GetTimeRemaining() )
  646. {
  647. bShouldPlaySound = true;
  648. }
  649. }
  650. else
  651. {
  652. CTeamRoundTimer *pStopWatch = dynamic_cast< CTeamRoundTimer* >( ClientEntityList().GetEnt( iStopWatchTimer ) );
  653. if ( ObjectiveResource()->GetTimerToShowInHUD() == entindex() )
  654. {
  655. if ( pStopWatch )
  656. {
  657. if ( pStopWatch->IsTimerPaused() == true )
  658. {
  659. bShouldPlaySound = true;
  660. }
  661. if ( pStopWatch->GetTimeRemaining() > GetTimeRemaining() && pStopWatch->IsWatchingTimeStamps() == false )
  662. {
  663. bShouldPlaySound = true;
  664. }
  665. if ( pStopWatch->IsWatchingTimeStamps() == true )
  666. {
  667. bShouldPlaySound = true;
  668. }
  669. }
  670. else
  671. {
  672. bShouldPlaySound = true;
  673. }
  674. }
  675. }
  676. }
  677. else
  678. {
  679. if( ObjectiveResource()->GetTimerToShowInHUD() == entindex() )
  680. {
  681. bShouldPlaySound = true;
  682. }
  683. if ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->IsInKothMode() )
  684. {
  685. bShouldPlaySound = true;
  686. }
  687. }
  688. #ifdef TF_CLIENT_DLL
  689. if ( bShouldPlaySound == true )
  690. {
  691. pPlayer->EmitSound( GetTimeWarningSound( nWarning ) );
  692. }
  693. #endif // TF_CLIENT_DLL
  694. }
  695. }
  696. }
  697. }
  698. #else
  699. //-----------------------------------------------------------------------------
  700. // Purpose:
  701. //-----------------------------------------------------------------------------
  702. void CTeamRoundTimer::SetState( int nState, bool bFireOutput )
  703. {
  704. m_nState = nState;
  705. if ( nState == RT_STATE_SETUP )
  706. {
  707. if ( IsStopWatchTimer() == false )
  708. {
  709. TeamplayRoundBasedRules()->SetSetup( true );
  710. }
  711. SetTimerThink( RT_THINK_SETUP );
  712. if ( bFireOutput )
  713. {
  714. m_OnSetupStart.FireOutput( this, this );
  715. }
  716. }
  717. else
  718. {
  719. if ( IsStopWatchTimer() == false )
  720. {
  721. TeamplayRoundBasedRules()->SetSetup( false );
  722. }
  723. SetTimerThink( RT_THINK_NORMAL );
  724. if ( bFireOutput )
  725. {
  726. m_OnRoundStart.FireOutput( this, this );
  727. }
  728. }
  729. }
  730. //-----------------------------------------------------------------------------
  731. // Purpose:
  732. //-----------------------------------------------------------------------------
  733. void CTeamRoundTimer::SetTimerThink( int nType )
  734. {
  735. if ( nType == RT_THINK_SETUP )
  736. {
  737. SetContextThink( &CTeamRoundTimer::RoundTimerSetupThink, gpGlobals->curtime + 0.05, ROUND_TIMER_SETUP_THINK );
  738. SetContextThink( NULL, 0, ROUND_TIMER_THINK );
  739. }
  740. else
  741. {
  742. SetContextThink( &CTeamRoundTimer::RoundTimerThink, gpGlobals->curtime + 0.05, ROUND_TIMER_THINK );
  743. SetContextThink( NULL, 0, ROUND_TIMER_SETUP_THINK );
  744. }
  745. }
  746. //-----------------------------------------------------------------------------
  747. // Purpose:
  748. //-----------------------------------------------------------------------------
  749. void CTeamRoundTimer::RoundTimerSetupThink( void )
  750. {
  751. float flLastTime = m_flLastTime;
  752. m_flLastTime = GetTimeRemaining();
  753. if ( TeamplayRoundBasedRules()->IsInPreMatch() == true && IsDisabled() == false )
  754. {
  755. inputdata_t data;
  756. InputDisable( data );
  757. m_OnSetupFinished.FireOutput( this, this );
  758. }
  759. if ( IsDisabled() || m_bTimerPaused )
  760. {
  761. SetContextThink( &CTeamRoundTimer::RoundTimerSetupThink, gpGlobals->curtime + 0.05, ROUND_TIMER_SETUP_THINK );
  762. return;
  763. }
  764. float flTime = GetTimeRemaining();
  765. TeamplayRoundBasedRules()->SetOvertime( false );
  766. if ( m_flLastTime > 0.f )
  767. {
  768. int nLastSecond = floor( flLastTime );
  769. int nThisSecond = floor( flTime );
  770. if ( nLastSecond != nThisSecond )
  771. {
  772. IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_pre_round_time_left" );
  773. if ( event )
  774. {
  775. event->SetInt( "time", nThisSecond );
  776. gameeventmanager->FireEvent( event );
  777. }
  778. }
  779. }
  780. if ( flTime <= 0.0f && m_bFireFinished )
  781. {
  782. IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_setup_finished" );
  783. if ( event )
  784. {
  785. gameeventmanager->FireEvent( event );
  786. }
  787. m_OnSetupFinished.FireOutput( this, this );
  788. m_bFireFinished = false;
  789. SetState( RT_STATE_NORMAL );
  790. SetTimeRemaining( m_nTimeToUseAfterSetupFinished );
  791. if ( ShowInHud() && !TeamplayRoundBasedRules()->IsInWaitingForPlayers() )
  792. {
  793. UTIL_LogPrintf( "World triggered \"Round_Setup_End\"\n" );
  794. }
  795. return;
  796. }
  797. else if ( flTime <= 60.0 && m_bFire1MinRemain )
  798. {
  799. m_On1MinRemain.FireOutput( this, this );
  800. m_bFire1MinRemain = false;
  801. }
  802. else if ( flTime <= 30.0 && m_bFire30SecRemain )
  803. {
  804. m_On30SecRemain.FireOutput( this, this );
  805. m_bFire30SecRemain = false;
  806. }
  807. else if ( flTime <= 10.0 && m_bFire10SecRemain )
  808. {
  809. m_On10SecRemain.FireOutput( this, this );
  810. m_bFire10SecRemain = false;
  811. }
  812. else if ( flTime <= 5.0 && m_bFire5SecRemain )
  813. {
  814. m_On5SecRemain.FireOutput( this, this );
  815. m_bFire5SecRemain = false;
  816. }
  817. else if ( flTime <= 4.0 && m_bFire4SecRemain )
  818. {
  819. m_On4SecRemain.FireOutput( this, this );
  820. m_bFire4SecRemain = false;
  821. }
  822. else if ( flTime <= 3.0 && m_bFire3SecRemain )
  823. {
  824. m_On3SecRemain.FireOutput( this, this );
  825. m_bFire3SecRemain = false;
  826. }
  827. else if ( flTime <= 2.0 && m_bFire2SecRemain )
  828. {
  829. m_On2SecRemain.FireOutput( this, this );
  830. m_bFire2SecRemain = false;
  831. }
  832. else if ( flTime <= 1.0 && m_bFire1SecRemain )
  833. {
  834. m_On1SecRemain.FireOutput( this, this );
  835. m_bFire1SecRemain = false;
  836. }
  837. SetContextThink( &CTeamRoundTimer::RoundTimerSetupThink, gpGlobals->curtime + 0.05, ROUND_TIMER_SETUP_THINK );
  838. }
  839. //-----------------------------------------------------------------------------
  840. // Purpose:
  841. //-----------------------------------------------------------------------------
  842. void CTeamRoundTimer::RoundTimerThink( void )
  843. {
  844. if ( TeamplayRoundBasedRules()->IsInPreMatch() == true && IsDisabled() == false )
  845. {
  846. inputdata_t data;
  847. InputDisable( data );
  848. }
  849. if ( IsDisabled() || m_bTimerPaused || IsInCommentaryMode() || gpGlobals->eLoadType == MapLoad_Background )
  850. {
  851. SetContextThink( &CTeamRoundTimer::RoundTimerThink, gpGlobals->curtime + 0.05, ROUND_TIMER_THINK );
  852. return;
  853. }
  854. // Don't do anything when the game has been won or if we're loading a bugbait report
  855. if ( TeamplayRoundBasedRules()->RoundHasBeenWon() ||
  856. TeamplayRoundBasedRules()->IsLoadingBugBaitReport() )
  857. {
  858. // We want to stop timers when the round has been won, but we don't want to
  859. // force mapmakers to deal with having to unpause it. This little hack works around that.
  860. if ( !m_bTimerPaused )
  861. {
  862. PauseTimer();
  863. m_bPauseDueToWin = true;
  864. }
  865. SetContextThink( &CTeamRoundTimer::RoundTimerThink, gpGlobals->curtime + 0.05, ROUND_TIMER_THINK );
  866. return;
  867. }
  868. else if ( m_bPauseDueToWin )
  869. {
  870. ResumeTimer();
  871. m_bPauseDueToWin = false;
  872. }
  873. float flTime = GetTimeRemaining();
  874. if ( flTime > 0 && ShowInHud() ) // is this the timer we're showing in the HUD?
  875. {
  876. TeamplayRoundBasedRules()->SetOvertime( false );
  877. }
  878. if ( flTime <= 0.0f && m_bFireFinished )
  879. {
  880. // Allow the gamerules to prevent timer expiration (i.e. while a control point is contested)
  881. if ( !TeamplayGameRules()->TimerMayExpire() )
  882. {
  883. // we don't want the timer to keep going (negative time)
  884. m_flTimerEndTime = gpGlobals->curtime;
  885. // is this the timer we're showing in the HUD?
  886. if ( ShowInHud() )
  887. {
  888. if ( !TeamplayRoundBasedRules()->InOvertime() )
  889. {
  890. TeamplayRoundBasedRules()->SetOvertime( true );
  891. }
  892. #if defined( TF_DLL )
  893. else
  894. {
  895. if ( tf_overtime_nag.GetBool() && ( gpGlobals->curtime > m_flNextOvertimeNag ) )
  896. {
  897. m_flNextOvertimeNag = gpGlobals->curtime + 1.0f;
  898. if ( RandomInt( 0, 1 ) > 0 )
  899. {
  900. IGameEvent *event = gameeventmanager->CreateEvent( "overtime_nag" );
  901. if ( event )
  902. {
  903. gameeventmanager->FireEvent( event );
  904. }
  905. }
  906. }
  907. }
  908. #endif
  909. }
  910. SetContextThink( &CTeamRoundTimer::RoundTimerThink, gpGlobals->curtime + 0.05, ROUND_TIMER_THINK );
  911. return;
  912. }
  913. m_OnFinished.FireOutput( this, this );
  914. m_bFireFinished = false;
  915. }
  916. else if ( flTime <= 300.0 && m_bFire5MinRemain )
  917. {
  918. m_On5MinRemain.FireOutput( this, this );
  919. m_bFire5MinRemain = false;
  920. }
  921. else if ( flTime <= 240.0 && m_bFire4MinRemain )
  922. {
  923. m_On4MinRemain.FireOutput( this, this );
  924. m_bFire4MinRemain = false;
  925. }
  926. else if ( flTime <= 180.0 && m_bFire3MinRemain )
  927. {
  928. m_On3MinRemain.FireOutput( this, this );
  929. m_bFire3MinRemain = false;
  930. }
  931. else if ( flTime <= 120.0 && m_bFire2MinRemain )
  932. {
  933. m_On2MinRemain.FireOutput( this, this );
  934. m_bFire2MinRemain = false;
  935. }
  936. else if ( flTime <= 60.0 && m_bFire1MinRemain )
  937. {
  938. m_On1MinRemain.FireOutput( this, this );
  939. m_bFire1MinRemain = false;
  940. }
  941. else if ( flTime <= 30.0 && m_bFire30SecRemain )
  942. {
  943. m_On30SecRemain.FireOutput( this, this );
  944. m_bFire30SecRemain = false;
  945. }
  946. else if ( flTime <= 10.0 && m_bFire10SecRemain )
  947. {
  948. m_On10SecRemain.FireOutput( this, this );
  949. m_bFire10SecRemain = false;
  950. }
  951. else if ( flTime <= 5.0 && m_bFire5SecRemain )
  952. {
  953. m_On5SecRemain.FireOutput( this, this );
  954. m_bFire5SecRemain = false;
  955. }
  956. else if ( flTime <= 4.0 && m_bFire4SecRemain )
  957. {
  958. m_On4SecRemain.FireOutput( this, this );
  959. m_bFire4SecRemain = false;
  960. }
  961. else if ( flTime <= 3.0 && m_bFire3SecRemain )
  962. {
  963. m_On3SecRemain.FireOutput( this, this );
  964. m_bFire3SecRemain = false;
  965. }
  966. else if ( flTime <= 2.0 && m_bFire2SecRemain )
  967. {
  968. m_On2SecRemain.FireOutput( this, this );
  969. m_bFire2SecRemain = false;
  970. }
  971. else if ( flTime <= 1.0 && m_bFire1SecRemain )
  972. {
  973. m_On1SecRemain.FireOutput( this, this );
  974. m_bFire1SecRemain = false;
  975. }
  976. SetContextThink( &CTeamRoundTimer::RoundTimerThink, gpGlobals->curtime + 0.05, ROUND_TIMER_THINK );
  977. }
  978. //-----------------------------------------------------------------------------
  979. // Purpose:
  980. //-----------------------------------------------------------------------------
  981. void CTeamRoundTimer::InputRoundSpawn( inputdata_t &input )
  982. {
  983. if ( !m_bResetTimeOnRoundStart && ( m_nState == RT_STATE_NORMAL ) )
  984. {
  985. m_nTimeToUseAfterSetupFinished = GetTimeRemaining();
  986. }
  987. else
  988. {
  989. m_nTimeToUseAfterSetupFinished = m_nTimerInitialLength;
  990. }
  991. if ( m_nSetupTimeLength > 0 )
  992. {
  993. SetState( RT_STATE_SETUP );
  994. SetTimeRemaining( m_nSetupTimeLength );
  995. if ( ShowInHud() && !TeamplayRoundBasedRules()->IsInWaitingForPlayers() )
  996. {
  997. UTIL_LogPrintf( "World triggered \"Round_Setup_Begin\"\n" );
  998. }
  999. }
  1000. else
  1001. {
  1002. SetState( RT_STATE_NORMAL );
  1003. SetTimeRemaining( m_nTimeToUseAfterSetupFinished );
  1004. }
  1005. if ( !m_bStartPaused && !TeamplayRoundBasedRules()->IsInWaitingForPlayers() )
  1006. {
  1007. ResumeTimer();
  1008. }
  1009. }
  1010. //-----------------------------------------------------------------------------
  1011. // Purpose: To set the initial timer duration
  1012. //-----------------------------------------------------------------------------
  1013. void CTeamRoundTimer::SetTimeRemaining( int iTimerSeconds )
  1014. {
  1015. if ( IsDisabled() )
  1016. return;
  1017. // make sure we don't go over our max length
  1018. iTimerSeconds = m_nTimerMaxLength > 0 ? MIN( iTimerSeconds, m_nTimerMaxLength ) : iTimerSeconds;
  1019. float flTimerSeconds = (float)iTimerSeconds;
  1020. if ( TeamplayRoundBasedRules()->IsInTournamentMode() && TeamplayRoundBasedRules()->IsInStopWatch() && ObjectiveResource() && !IsStopWatchTimer() && !TeamplayRoundBasedRules()->InSetup() )
  1021. {
  1022. // make sure we don't go over our stop watch timer
  1023. int iStopWatchTimer = ObjectiveResource()->GetStopWatchTimer();
  1024. CTeamRoundTimer *pStopWatch = dynamic_cast< CTeamRoundTimer* >( UTIL_EntityByIndex( iStopWatchTimer ) );
  1025. if ( pStopWatch && !pStopWatch->IsWatchingTimeStamps() && TeamplayRoundBasedRules()->StopWatchShouldBeTimedWin() )
  1026. {
  1027. float flStopWatchRemainingTime = pStopWatch->GetTimeRemaining();
  1028. flTimerSeconds = flStopWatchRemainingTime > 0 ? MIN( flTimerSeconds, flStopWatchRemainingTime ) : flTimerSeconds;
  1029. iTimerSeconds = (int)ceil( flTimerSeconds );
  1030. }
  1031. }
  1032. m_flTimeRemaining = flTimerSeconds;
  1033. m_flTimerEndTime = gpGlobals->curtime + m_flTimeRemaining;
  1034. m_nTimerLength = iTimerSeconds;
  1035. CalculateOutputMessages();
  1036. }
  1037. //-----------------------------------------------------------------------------
  1038. // Purpose: To set the initial timer duration
  1039. //-----------------------------------------------------------------------------
  1040. void CTeamRoundTimer::SetStopWatchTimeStamp( void )
  1041. {
  1042. if ( IsDisabled() )
  1043. return;
  1044. if ( IsWatchingTimeStamps() == false )
  1045. return;
  1046. m_flTotalTime = m_flTotalTime + (gpGlobals->curtime - m_flTimerEndTime);
  1047. m_flTimerEndTime = gpGlobals->curtime;
  1048. CalculateOutputMessages();
  1049. }
  1050. //-----------------------------------------------------------------------------
  1051. // Purpose: Timer is paused at round end, stops the countdown
  1052. //-----------------------------------------------------------------------------
  1053. void CTeamRoundTimer::PauseTimer( void )
  1054. {
  1055. if ( IsDisabled() )
  1056. return;
  1057. if ( m_bTimerPaused == false )
  1058. {
  1059. m_bTimerPaused = true;
  1060. m_flTimeRemaining = m_flTimerEndTime - gpGlobals->curtime;
  1061. }
  1062. // Clear pause on win flag, because we've been set by the mapmaker
  1063. m_bPauseDueToWin = false;
  1064. }
  1065. //-----------------------------------------------------------------------------
  1066. // Purpose: To start or re-start the timer after a pause
  1067. //-----------------------------------------------------------------------------
  1068. void CTeamRoundTimer::ResumeTimer( void )
  1069. {
  1070. if ( IsDisabled() )
  1071. return;
  1072. if ( m_bTimerPaused == true )
  1073. {
  1074. m_bTimerPaused = false;
  1075. if ( IsStopWatchTimer() == true && m_bInCaptureWatchState == true )
  1076. {
  1077. m_flTimerEndTime = gpGlobals->curtime;
  1078. }
  1079. else
  1080. {
  1081. m_flTimerEndTime = gpGlobals->curtime + m_flTimeRemaining;
  1082. }
  1083. }
  1084. }
  1085. //-----------------------------------------------------------------------------
  1086. // Purpose: Add seconds to the timer while it is running or paused
  1087. //-----------------------------------------------------------------------------
  1088. void CTeamRoundTimer::AddTimerSeconds( int iSecondsToAdd, int iTeamResponsible /* = TEAM_UNASSIGNED*/ )
  1089. {
  1090. if ( IsDisabled() )
  1091. return;
  1092. if ( TeamplayRoundBasedRules()->InStalemate() )
  1093. return;
  1094. // we only want to add time if we're round_running or team_win so the control points
  1095. // don't add time when they try to set their default owner when the map is first loading
  1096. if ( TeamplayRoundBasedRules()->State_Get() != GR_STATE_RND_RUNNING && TeamplayRoundBasedRules()->State_Get() != GR_STATE_TEAM_WIN )
  1097. return;
  1098. if ( m_nTimerMaxLength > 0 )
  1099. {
  1100. // will adding this many seconds push us over our max length?
  1101. if ( GetTimeRemaining() + iSecondsToAdd > m_nTimerMaxLength )
  1102. {
  1103. // adjust to only add up to our max length
  1104. iSecondsToAdd = m_nTimerMaxLength - GetTimeRemaining();
  1105. }
  1106. }
  1107. float flSecondsToAdd = (float)iSecondsToAdd;
  1108. if ( TeamplayRoundBasedRules()->IsInTournamentMode() && TeamplayRoundBasedRules()->IsInStopWatch() && ObjectiveResource() && !IsStopWatchTimer() && !TeamplayRoundBasedRules()->InSetup() )
  1109. {
  1110. int iStopWatchTimer = ObjectiveResource()->GetStopWatchTimer();
  1111. CTeamRoundTimer *pStopWatch = dynamic_cast< CTeamRoundTimer* >( UTIL_EntityByIndex( iStopWatchTimer ) );
  1112. if ( pStopWatch && !pStopWatch->IsWatchingTimeStamps() && TeamplayRoundBasedRules()->StopWatchShouldBeTimedWin() )
  1113. {
  1114. float flStopWatchRemainingTime = pStopWatch->GetTimeRemaining();
  1115. float flRemainingTime = GetTimeRemaining();
  1116. // will adding this many seconds push us over our stop watch timer?
  1117. if ( flRemainingTime + flSecondsToAdd > flStopWatchRemainingTime )
  1118. {
  1119. // adjust to only add up to our stop watch timer
  1120. flSecondsToAdd = flStopWatchRemainingTime - flRemainingTime;
  1121. iSecondsToAdd = ( int )ceil( flSecondsToAdd );
  1122. }
  1123. }
  1124. }
  1125. if ( m_bTimerPaused )
  1126. {
  1127. m_flTimeRemaining += flSecondsToAdd;
  1128. }
  1129. else
  1130. {
  1131. m_flTimerEndTime += flSecondsToAdd;
  1132. }
  1133. m_nTimerLength += iSecondsToAdd;
  1134. CalculateOutputMessages();
  1135. if ( ( ObjectiveResource() && ObjectiveResource()->GetTimerInHUD() == entindex() ) || ( TeamplayRoundBasedRules()->IsInKothMode() ) )
  1136. {
  1137. if ( !TeamplayRoundBasedRules()->InStalemate() && !TeamplayRoundBasedRules()->RoundHasBeenWon() && !TeamplayRoundBasedRules()->IsInKothMode() )
  1138. {
  1139. if ( iTeamResponsible >= LAST_SHARED_TEAM+1 )
  1140. {
  1141. for ( int iTeam = LAST_SHARED_TEAM+1 ; iTeam < GetNumberOfTeams(); iTeam++ )
  1142. {
  1143. if ( iTeam == iTeamResponsible )
  1144. {
  1145. CTeamRecipientFilter filter( iTeam, true );
  1146. EmitSound( filter, entindex(), ROUND_TIMER_TIME_ADDED_WINNER );
  1147. }
  1148. else
  1149. {
  1150. CTeamRecipientFilter filter( iTeam, true );
  1151. EmitSound( filter, entindex(), ROUND_TIMER_TIME_ADDED_LOSER );
  1152. }
  1153. }
  1154. }
  1155. else
  1156. {
  1157. CReliableBroadcastRecipientFilter filter;
  1158. EmitSound( filter, entindex(), ROUND_TIMER_TIME_ADDED );
  1159. }
  1160. }
  1161. // is this the timer we're showing in the HUD?
  1162. if ( m_bShowInHUD )
  1163. {
  1164. IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_timer_time_added" );
  1165. if ( event )
  1166. {
  1167. event->SetInt( "timer", entindex() );
  1168. event->SetInt( "seconds_added", iSecondsToAdd );
  1169. gameeventmanager->FireEvent( event );
  1170. }
  1171. }
  1172. }
  1173. }
  1174. //-----------------------------------------------------------------------------
  1175. // Purpose: The timer is always transmitted to clients
  1176. //-----------------------------------------------------------------------------
  1177. int CTeamRoundTimer::UpdateTransmitState()
  1178. {
  1179. // ALWAYS transmit to all clients.
  1180. return SetTransmitState( FL_EDICT_ALWAYS );
  1181. }
  1182. //-----------------------------------------------------------------------------
  1183. // Purpose:
  1184. //-----------------------------------------------------------------------------
  1185. void CTeamRoundTimer::InputPause( inputdata_t &input )
  1186. {
  1187. PauseTimer();
  1188. }
  1189. //-----------------------------------------------------------------------------
  1190. // Purpose:
  1191. //-----------------------------------------------------------------------------
  1192. void CTeamRoundTimer::InputResume( inputdata_t &input )
  1193. {
  1194. ResumeTimer();
  1195. }
  1196. //-----------------------------------------------------------------------------
  1197. // Purpose:
  1198. //-----------------------------------------------------------------------------
  1199. void CTeamRoundTimer::InputSetTime( inputdata_t &input )
  1200. {
  1201. if ( IsStopWatchTimer() == true && IsWatchingTimeStamps() == true )
  1202. {
  1203. SetStopWatchTimeStamp();
  1204. }
  1205. else
  1206. {
  1207. int nSeconds = input.value.Int();
  1208. SetTimeRemaining( nSeconds );
  1209. }
  1210. }
  1211. //-----------------------------------------------------------------------------
  1212. // Purpose:
  1213. //-----------------------------------------------------------------------------
  1214. void CTeamRoundTimer::InputSetMaxTime( inputdata_t &input )
  1215. {
  1216. int nSeconds = input.value.Int();
  1217. m_nTimerMaxLength = nSeconds;
  1218. if ( m_nTimerMaxLength > 0 )
  1219. {
  1220. // make sure our current time is not above the max length
  1221. if ( GetTimeRemaining() > m_nTimerMaxLength )
  1222. {
  1223. SetTimeRemaining( m_nTimerMaxLength );
  1224. }
  1225. }
  1226. }
  1227. //-----------------------------------------------------------------------------
  1228. // Purpose:
  1229. //-----------------------------------------------------------------------------
  1230. void CTeamRoundTimer::InputAddTime( inputdata_t &input )
  1231. {
  1232. int nSeconds = input.value.Int();
  1233. AddTimerSeconds( nSeconds );
  1234. }
  1235. //-----------------------------------------------------------------------------
  1236. // Purpose:
  1237. //-----------------------------------------------------------------------------
  1238. void CTeamRoundTimer::InputAddTeamTime( inputdata_t &input )
  1239. {
  1240. char token[128];
  1241. const char *p = STRING( input.value.StringID() );
  1242. int nTeam = TEAM_UNASSIGNED;
  1243. int nSeconds = 0;
  1244. // get the team
  1245. p = nexttoken( token, p, ' ' );
  1246. if ( token[0] )
  1247. {
  1248. nTeam = Q_atoi( token );
  1249. }
  1250. // get the time
  1251. p = nexttoken( token, p, ' ' );
  1252. if ( token[0] )
  1253. {
  1254. nSeconds = Q_atoi( token );
  1255. }
  1256. if ( nSeconds != 0 )
  1257. {
  1258. AddTimerSeconds( nSeconds, nTeam );
  1259. }
  1260. }
  1261. //-----------------------------------------------------------------------------
  1262. // Purpose:
  1263. //-----------------------------------------------------------------------------
  1264. void CTeamRoundTimer::InputRestart( inputdata_t &input )
  1265. {
  1266. SetTimeRemaining( m_nTimerInitialLength );
  1267. }
  1268. //-----------------------------------------------------------------------------
  1269. // Purpose:
  1270. //-----------------------------------------------------------------------------
  1271. void CTeamRoundTimer::InputEnable( inputdata_t &input )
  1272. {
  1273. m_bIsDisabled = false;
  1274. ResumeTimer();
  1275. if ( m_bShowInHUD )
  1276. {
  1277. SetActiveTimer( this );
  1278. }
  1279. if ( IsStopWatchTimer() == true && IsWatchingTimeStamps() == true )
  1280. {
  1281. m_flTimerEndTime = gpGlobals->curtime;
  1282. }
  1283. }
  1284. //-----------------------------------------------------------------------------
  1285. // Purpose:
  1286. //-----------------------------------------------------------------------------
  1287. void CTeamRoundTimer::InputDisable( inputdata_t &input )
  1288. {
  1289. PauseTimer();
  1290. m_bIsDisabled = true;
  1291. if ( m_bShowInHUD )
  1292. {
  1293. SetActiveTimer( NULL );
  1294. }
  1295. }
  1296. //-----------------------------------------------------------------------------
  1297. // Purpose:
  1298. //-----------------------------------------------------------------------------
  1299. void CTeamRoundTimer::InputShowInHUD( inputdata_t &input )
  1300. {
  1301. int nShow = input.value.Int();
  1302. if ( m_bShowInHUD && !nShow )
  1303. {
  1304. SetActiveTimer( NULL );
  1305. }
  1306. else if ( nShow == 1 )
  1307. {
  1308. SetActiveTimer( this );
  1309. SetState( m_nState, false ); // set our current state again so the gamerules are updated with our setup state
  1310. }
  1311. m_bShowInHUD = ( nShow == 1 );
  1312. }
  1313. //-----------------------------------------------------------------------------
  1314. // Purpose:
  1315. //-----------------------------------------------------------------------------
  1316. void CTeamRoundTimer::InputAutoCountdown( inputdata_t &input )
  1317. {
  1318. int nAuto = input.value.Int();
  1319. SetAutoCountdown( nAuto == 1 );
  1320. }
  1321. //-----------------------------------------------------------------------------
  1322. // Purpose:
  1323. //-----------------------------------------------------------------------------
  1324. void CTeamRoundTimer::InputSetSetupTime( inputdata_t &input )
  1325. {
  1326. int nSetupTime = input.value.Int();
  1327. if ( nSetupTime >= 0 )
  1328. {
  1329. m_nSetupTimeLength = nSetupTime;
  1330. }
  1331. if ( !IsDisabled() )
  1332. {
  1333. if ( m_nState == RT_STATE_SETUP )
  1334. {
  1335. SetTimeRemaining( m_nSetupTimeLength );
  1336. }
  1337. }
  1338. }
  1339. //-----------------------------------------------------------------------------
  1340. // Purpose:
  1341. //-----------------------------------------------------------------------------
  1342. void CTeamRoundTimer::SetActiveTimer( CTeamRoundTimer *pNewlyActive )
  1343. {
  1344. CBaseEntity *pChosenTimer = pNewlyActive;
  1345. // Ensure all other timers are off.
  1346. CBaseEntity *pEntity = NULL;
  1347. while ((pEntity = gEntList.FindEntityByClassname( pEntity, "team_round_timer" )) != NULL)
  1348. {
  1349. if ( pEntity == pNewlyActive )
  1350. continue;
  1351. CTeamRoundTimer *pTimer = assert_cast< CTeamRoundTimer* >( pEntity );
  1352. if ( !pTimer->IsDisabled() && pTimer->ShowInHud() )
  1353. {
  1354. if ( pChosenTimer )
  1355. {
  1356. // Turn off all other hud timers
  1357. pTimer->SetShowInHud( false );
  1358. }
  1359. else
  1360. {
  1361. // Found a timer. Use it.
  1362. pChosenTimer = pTimer;
  1363. }
  1364. }
  1365. }
  1366. ObjectiveResource()->SetTimerInHUD( pChosenTimer );
  1367. }
  1368. #endif