//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================
#include "cbase.h"
#include "EntityOutput.h"
#include "EntityList.h"
#include "tf_team.h"
#include "vstdlib/strtools.h"
#include "baseentity.h"
#include "tf_shareddefs.h"
#include "info_act.h"

// Global pointer to the current act
CHandle<CInfoAct>	g_hCurrentAct;

BEGIN_DATADESC( CInfoAct )

	// inputs
	DEFINE_INPUTFUNC( CInfoAct, FIELD_VOID, "Start", InputStart ),
	DEFINE_INPUTFUNC( CInfoAct, FIELD_VOID, "FinishWinNone", InputFinishWinNone ),
	DEFINE_INPUTFUNC( CInfoAct, FIELD_VOID, "FinishWin1", InputFinishWin1 ),
	DEFINE_INPUTFUNC( CInfoAct, FIELD_VOID, "FinishWin2", InputFinishWin2 ),
	DEFINE_INPUTFUNC( CInfoAct, FIELD_FLOAT, "AddTime", InputAddTime ),

	// outputs
	DEFINE_OUTPUT( CInfoAct, m_OnStarted, "OnStarted" ),
	DEFINE_OUTPUT( CInfoAct, m_OnFinishedTeamNone, "OnFinishedWinNone" ),
	DEFINE_OUTPUT( CInfoAct, m_OnFinishedTeam1, "OnFinishedWin1" ),
	DEFINE_OUTPUT( CInfoAct, m_OnFinishedTeam2, "OnFinishedWin2" ),
	DEFINE_OUTPUT( CInfoAct, m_OnTimerExpired, "OnTimerExpired" ),

	DEFINE_OUTPUT( CInfoAct, m_Respawn1Team1Events[CInfoAct::RESPAWN_TIMER_90_REMAINING], "OnRespawn1Team1_90sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn1Team1Events[CInfoAct::RESPAWN_TIMER_60_REMAINING], "OnRespawn1Team1_60sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn1Team1Events[CInfoAct::RESPAWN_TIMER_45_REMAINING], "OnRespawn1Team1_45sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn1Team1Events[CInfoAct::RESPAWN_TIMER_30_REMAINING], "OnRespawn1Team1_30sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn1Team1Events[CInfoAct::RESPAWN_TIMER_10_REMAINING], "OnRespawn1Team1_10sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn1Team1Events[CInfoAct::RESPAWN_TIMER_0_REMAINING], "OnRespawn1Team1" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn1Team1TimeRemaining, "Respawn1Team1TimeRemaining" ),

	DEFINE_OUTPUT( CInfoAct, m_Respawn2Team1Events[CInfoAct::RESPAWN_TIMER_90_REMAINING], "OnRespawn2Team1_90sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn2Team1Events[CInfoAct::RESPAWN_TIMER_60_REMAINING], "OnRespawn2Team1_60sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn2Team1Events[CInfoAct::RESPAWN_TIMER_45_REMAINING], "OnRespawn2Team1_45sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn2Team1Events[CInfoAct::RESPAWN_TIMER_30_REMAINING], "OnRespawn2Team1_30sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn2Team1Events[CInfoAct::RESPAWN_TIMER_10_REMAINING], "OnRespawn2Team1_10sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn2Team1Events[CInfoAct::RESPAWN_TIMER_0_REMAINING], "OnRespawn2Team1" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn2Team1TimeRemaining, "Respawn2Team1TimeRemaining" ),

	DEFINE_OUTPUT( CInfoAct, m_Respawn1Team2Events[CInfoAct::RESPAWN_TIMER_90_REMAINING], "OnRespawn1Team2_90sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn1Team2Events[CInfoAct::RESPAWN_TIMER_60_REMAINING], "OnRespawn1Team2_60sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn1Team2Events[CInfoAct::RESPAWN_TIMER_45_REMAINING], "OnRespawn1Team2_45sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn1Team2Events[CInfoAct::RESPAWN_TIMER_30_REMAINING], "OnRespawn1Team2_30sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn1Team2Events[CInfoAct::RESPAWN_TIMER_10_REMAINING], "OnRespawn1Team2_10sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn1Team2Events[CInfoAct::RESPAWN_TIMER_0_REMAINING], "OnRespawn1Team2" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn1Team2TimeRemaining, "Respawn1Team2TimeRemaining" ),

	DEFINE_OUTPUT( CInfoAct, m_Respawn2Team2Events[CInfoAct::RESPAWN_TIMER_90_REMAINING], "OnRespawn2Team2_90sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn2Team2Events[CInfoAct::RESPAWN_TIMER_60_REMAINING], "OnRespawn2Team2_60sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn2Team2Events[CInfoAct::RESPAWN_TIMER_45_REMAINING], "OnRespawn2Team2_45sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn2Team2Events[CInfoAct::RESPAWN_TIMER_30_REMAINING], "OnRespawn2Team2_30sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn2Team2Events[CInfoAct::RESPAWN_TIMER_10_REMAINING], "OnRespawn2Team2_10sec" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn2Team2Events[CInfoAct::RESPAWN_TIMER_0_REMAINING], "OnRespawn2Team2" ),
	DEFINE_OUTPUT( CInfoAct, m_Respawn2Team2TimeRemaining, "Respawn2Team2TimeRemaining" ),

	DEFINE_OUTPUT( CInfoAct, m_Team1RespawnDelayDone, "OnTeam1RespawnDelayDone" ),
	DEFINE_OUTPUT( CInfoAct, m_Team2RespawnDelayDone, "OnTeam2RespawnDelayDone" ),

	// keys 
	DEFINE_KEYFIELD_NOT_SAVED( CInfoAct, m_iActNumber, FIELD_INTEGER, "ActNumber" ),
	DEFINE_KEYFIELD_NOT_SAVED( CInfoAct, m_flActTimeLimit, FIELD_FLOAT, "ActTimeLimit" ),
	DEFINE_KEYFIELD_NOT_SAVED( CInfoAct, m_iszIntermissionCamera, FIELD_STRING, "IntermissionCamera" ),
	DEFINE_KEYFIELD_NOT_SAVED( CInfoAct, m_nRespawn1Team1Time, FIELD_INTEGER, "Respawn1Team1Time" ),
	DEFINE_KEYFIELD_NOT_SAVED( CInfoAct, m_nRespawn2Team1Time, FIELD_INTEGER, "Respawn2Team1Time" ),
	DEFINE_KEYFIELD_NOT_SAVED( CInfoAct, m_nRespawn1Team2Time, FIELD_INTEGER, "Respawn1Team2Time" ),
	DEFINE_KEYFIELD_NOT_SAVED( CInfoAct, m_nRespawn2Team2Time, FIELD_INTEGER, "Respawn2Team2Time" ),
	DEFINE_KEYFIELD_NOT_SAVED( CInfoAct, m_nRespawnTeam1Delay, FIELD_INTEGER, "RespawnTeam1InitialDelay" ),
	DEFINE_KEYFIELD_NOT_SAVED( CInfoAct, m_nRespawnTeam2Delay, FIELD_INTEGER, "RespawnTeam2InitialDelay" ),

	// functions
	DEFINE_FUNCTION( CInfoAct, ActThink ),
	DEFINE_FUNCTION( CInfoAct, ActThinkEndActOverlayTime ),
	DEFINE_FUNCTION( CInfoAct, RespawnTimerThink ),
	DEFINE_FUNCTION( CInfoAct, Team1RespawnDelayThink ),
	DEFINE_FUNCTION( CInfoAct, Team2RespawnDelayThink ),

END_DATADESC()

IMPLEMENT_SERVERCLASS_ST(CInfoAct, DT_InfoAct)
	SendPropInt(SENDINFO(m_iActNumber), 5 ),
	SendPropInt(SENDINFO(m_spawnflags), SF_ACT_BITS, SPROP_UNSIGNED ),
	SendPropFloat(SENDINFO(m_flActTimeLimit), 12 ),
	SendPropInt(SENDINFO(m_nRespawn1Team1Time), 8 ),
	SendPropInt(SENDINFO(m_nRespawn2Team1Time), 8 ),
	SendPropInt(SENDINFO(m_nRespawn1Team2Time), 8 ),
	SendPropInt(SENDINFO(m_nRespawn2Team2Time), 8 ),
	SendPropInt(SENDINFO(m_nRespawnTeam1Delay), 8 ),
	SendPropInt(SENDINFO(m_nRespawnTeam2Delay), 8 ),
END_SEND_TABLE();

LINK_ENTITY_TO_CLASS( info_act, CInfoAct );


#define RESPAWN_TIMER_CONTEXT			"RespawnTimerThink"
#define RESPAWN_TEAM_1_DELAY_CONTEXT	"RespawnTeam1DelayThink"
#define RESPAWN_TEAM_2_DELAY_CONTEXT	"RespawnTeam2DelayThink"

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CInfoAct::CInfoAct( void )
{
	// No act == -1
	m_iActNumber = -1;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CInfoAct::ShouldTransmit( const edict_t *recipient, const void *pvs, int clientArea )
{
	// Always transmit 
	return true;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CInfoAct::Spawn( void )
{
	NetworkStateManualMode( true );
	m_flActStartedAt = 0;
	m_iWinners = 0;
}


//-----------------------------------------------------------------------------
// Purpose: Set up respawn timers
//-----------------------------------------------------------------------------
void CInfoAct::SetUpRespawnTimers()
{
	// NOTE: Need to add the second there so the respawn timers don't immediately trigger
	SetContextThink( RespawnTimerThink, gpGlobals->curtime + 1.0f, RESPAWN_TIMER_CONTEXT );

	if (m_nRespawnTeam1Delay != 0)
	{
		SetContextThink( Team1RespawnDelayThink, gpGlobals->curtime + m_nRespawnTeam1Delay, RESPAWN_TEAM_1_DELAY_CONTEXT );
	}
	else
	{
		m_Team1RespawnDelayDone.FireOutput( this, this );
	}

	if (m_nRespawnTeam2Delay != 0)
	{
		SetContextThink( Team2RespawnDelayThink, gpGlobals->curtime + m_nRespawnTeam2Delay, RESPAWN_TEAM_2_DELAY_CONTEXT );
	}
	else
	{
		m_Team2RespawnDelayDone.FireOutput( this, this );
	}
}

void CInfoAct::ShutdownRespawnTimers()
{
	SetContextThink( NULL, 0, RESPAWN_TIMER_CONTEXT );
	SetContextThink( NULL, 0, RESPAWN_TEAM_1_DELAY_CONTEXT );
	SetContextThink( NULL, 0, RESPAWN_TEAM_2_DELAY_CONTEXT );
}


//-----------------------------------------------------------------------------
// Respawn delay
//-----------------------------------------------------------------------------
void CInfoAct::Team1RespawnDelayThink()
{
	m_Team1RespawnDelayDone.FireOutput( this, this );
	SetContextThink( NULL, 0, RESPAWN_TEAM_1_DELAY_CONTEXT );
}

void CInfoAct::Team2RespawnDelayThink()
{
	m_Team2RespawnDelayDone.FireOutput( this, this );
	SetContextThink( NULL, 0, RESPAWN_TEAM_2_DELAY_CONTEXT );
}


//-----------------------------------------------------------------------------
// Computes the time remaining
//-----------------------------------------------------------------------------
int CInfoAct::ComputeTimeRemaining( int nPeriod, int nDelay )
{
	if (nPeriod <= 0)
		return -1;

	int nTimeDelta = (int)(gpGlobals->curtime - m_flActStartedAt);
	Assert( nTimeDelta >= 0 );
	nTimeDelta -= nDelay;

	// This case takes care of the initial spawn delay time...
	if (nTimeDelta <= 0)
	{
		return nPeriod - nTimeDelta;
	}

	int nFactor = nTimeDelta / nPeriod;
	int nTimeRemainder = nTimeDelta - nFactor * nPeriod;
	if (nTimeRemainder == 0)
		return 0;

	return nPeriod - nTimeRemainder;
}


//-----------------------------------------------------------------------------
// Fires respawn events
//-----------------------------------------------------------------------------
void CInfoAct::FireRespawnEvents( int nTimeRemaining, COutputEvent *pRespawnEvents, COutputInt &respawnTime )
{
	if (nTimeRemaining < 0)
		return;

	switch (nTimeRemaining)
	{
	case 90:
		pRespawnEvents[RESPAWN_TIMER_90_REMAINING].FireOutput( this, this );
		break;
	case 60:
		pRespawnEvents[RESPAWN_TIMER_60_REMAINING].FireOutput( this, this );
		break;
	case 45:
		pRespawnEvents[RESPAWN_TIMER_45_REMAINING].FireOutput( this, this );
		break;
	case 30:
		pRespawnEvents[RESPAWN_TIMER_30_REMAINING].FireOutput( this, this );
		break;
	case 10:
		pRespawnEvents[RESPAWN_TIMER_10_REMAINING].FireOutput( this, this );
		break;
	case 0:
		pRespawnEvents[RESPAWN_TIMER_0_REMAINING].FireOutput( this, this );
		break;
	default:
		break;
	}

	respawnTime.Set( nTimeRemaining, this, this );
}


//-----------------------------------------------------------------------------
// Respawn timers
//-----------------------------------------------------------------------------
void CInfoAct::RespawnTimerThink()
{
	int nTimeRemaining = ComputeTimeRemaining( m_nRespawn1Team1Time, m_nRespawnTeam1Delay );
	FireRespawnEvents( nTimeRemaining, m_Respawn1Team1Events, m_Respawn1Team1TimeRemaining );

	nTimeRemaining = ComputeTimeRemaining( m_nRespawn2Team1Time, m_nRespawnTeam1Delay );
	FireRespawnEvents( nTimeRemaining, m_Respawn2Team1Events, m_Respawn2Team1TimeRemaining );

	nTimeRemaining = ComputeTimeRemaining( m_nRespawn1Team2Time, m_nRespawnTeam2Delay );
	FireRespawnEvents( nTimeRemaining, m_Respawn1Team2Events, m_Respawn1Team2TimeRemaining );

	nTimeRemaining = ComputeTimeRemaining( m_nRespawn2Team2Time, m_nRespawnTeam2Delay );
	FireRespawnEvents( nTimeRemaining, m_Respawn2Team2Events, m_Respawn2Team2TimeRemaining );

	SetNextThink( gpGlobals->curtime + 1.0f, RESPAWN_TIMER_CONTEXT );
}


//-----------------------------------------------------------------------------
// Purpose: The act has started
//-----------------------------------------------------------------------------
void CInfoAct::StartAct( void )
{
	// FIXME: Should this change?
	// Don't allow two simultaneous acts
	if (g_hCurrentAct)
	{
		g_hCurrentAct->FinishAct( );
	}

	// Set the global act to this
	g_hCurrentAct = this;

	m_flActStartedAt = gpGlobals->curtime;
	m_OnStarted.FireOutput( this, this );

	// Do we have a timelimit?
	if ( m_flActTimeLimit )
	{
		SetNextThink( gpGlobals->curtime + m_flActTimeLimit );
		SetThink( ActThink );
	}

	SetUpRespawnTimers();

	// Tell all the clients
	CRelieableBroadcastRecipientFilter filter;

	UserMessageBegin( filter, "ActBegin" );
		WRITE_BYTE( (byte)m_iActNumber );
		WRITE_FLOAT( m_flActStartedAt );
	MessageEnd();

	// If we're not an intermission, clean up
	if ( !HasSpawnFlags( SF_ACT_INTERMISSION ) )
	{
		CleanupOnActStart();
	}

	// Cycle through all players and start the act
	for ( int i = 1; i <= gpGlobals->maxClients; i++ )
	{
		CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)UTIL_PlayerByIndex( i );
		if ( pPlayer  )
		{
			// Am I an intermission?
			if ( HasSpawnFlags( SF_ACT_INTERMISSION ) )
			{
				StartIntermission( pPlayer );
			}
			else
			{
				StartActOverlayTime( pPlayer );
			}
		}
	}

	// Think again soon, to remove player locks
	if ( !HasSpawnFlags(SF_ACT_INTERMISSION) )
	{
		SetNextThink( gpGlobals->curtime + MIN_ACT_OVERLAY_TIME );
		SetThink( ActThinkEndActOverlayTime );
	}
}


//-----------------------------------------------------------------------------
// Purpose: Update a client who joined during the middle of an act
//-----------------------------------------------------------------------------
void CInfoAct::UpdateClient( CBaseTFPlayer *pPlayer )
{
	CSingleUserRecipientFilter user( pPlayer );
	user.MakeReliable();

	UserMessageBegin( user, "ActBegin" );
		WRITE_BYTE( (byte)m_iActNumber );
		WRITE_FLOAT( m_flActStartedAt );
	MessageEnd();
}

//-----------------------------------------------------------------------------
// Purpose: The act has finished
//-----------------------------------------------------------------------------
void CInfoAct::FinishAct( )
{
	if ( g_hCurrentAct.Get() != this )
	{
		DevWarning( 2, "Attempted to finish an act which wasn't started!\n" );
		return;
	}

	ShutdownRespawnTimers();

	switch( m_iWinners)
	{
	case 0:
		m_OnFinishedTeamNone.FireOutput( this, this );
		break;

	case 1:
		m_OnFinishedTeam1.FireOutput( this, this );
		break;

	case 2:
		m_OnFinishedTeam2.FireOutput( this, this );
		break;

	default:
		Assert(0);
		break;
	}

	g_hCurrentAct = NULL;

	// Tell all the clients
	CRelieableBroadcastRecipientFilter filter;
	UserMessageBegin( filter, "ActEnd" );
		WRITE_BYTE( m_iWinners );
	MessageEnd();

	// Am I an intermission?
	if ( HasSpawnFlags( SF_ACT_INTERMISSION ) )
	{
		// Cycle through all players and end the intermission for them
		for ( int i = 1; i <= gpGlobals->maxClients; i++ )
		{
			CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)UTIL_PlayerByIndex( i );
			if ( pPlayer  )
			{
				EndIntermission( pPlayer );
			}
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CInfoAct::ActThink( void )
{
	m_OnTimerExpired.FireOutput( this,this );
}

//-----------------------------------------------------------------------------
// Purpose: Force the players not to move to give them time to read the act overlays
//-----------------------------------------------------------------------------
void CInfoAct::StartActOverlayTime( CBaseTFPlayer *pPlayer )
{
	// Lock the player in place
	pPlayer->CleanupOnActStart();
	pPlayer->LockPlayerInPlace();
	pPlayer->m_Local.m_iHideHUD |= (HIDEHUD_WEAPONS | HIDEHUD_HEALTH);
	pPlayer->GetLocalData()->m_bForceMapOverview = true;
}

//-----------------------------------------------------------------------------
// Purpose: Release the players after overlay time has finished
//-----------------------------------------------------------------------------
void CInfoAct::EndActOverlayTime( CBaseTFPlayer *pPlayer )
{
	// Release the player
	pPlayer->UnlockPlayer();
	pPlayer->m_Local.m_iHideHUD &= ~(HIDEHUD_WEAPONS | HIDEHUD_HEALTH);
	pPlayer->GetLocalData()->m_bForceMapOverview = false;
}

//-----------------------------------------------------------------------------
// Purpose: Unlock the players after an act has started
//-----------------------------------------------------------------------------
void CInfoAct::ActThinkEndActOverlayTime( void )
{
	// Cycle through all players and end the intermission for them
	for ( int i = 1; i <= gpGlobals->maxClients; i++ )
	{
		CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)UTIL_PlayerByIndex( i );
		if ( pPlayer  )
		{
			EndActOverlayTime( pPlayer );
		}
	}

	// Think again when the act ends, if we have a timelimit
	if ( m_flActTimeLimit )
	{
		SetNextThink( gpGlobals->curtime + m_flActTimeLimit - MIN_ACT_OVERLAY_TIME );
		SetThink( ActThink );
	}
}

//-----------------------------------------------------------------------------
// Purpose: Clean up entities before a new act starts
//-----------------------------------------------------------------------------
void CInfoAct::CleanupOnActStart( void )
{
	// Remove all resource chunks
	CBaseEntity *pEntity = NULL;
	while ((pEntity = gEntList.FindEntityByClassname( pEntity, "resource_chunk" )) != NULL)
	{
		UTIL_Remove( pEntity );
	}
}

//-----------------------------------------------------------------------------
// Purpose: Intermission handling
//-----------------------------------------------------------------------------
void CInfoAct::StartIntermission( CBaseTFPlayer *pPlayer )
{
	// Do we have a camera point?
	if ( m_iszIntermissionCamera != NULL_STRING )
	{
		CBaseEntity *pCamera = gEntList.FindEntityByName( NULL, STRING(m_iszIntermissionCamera), NULL );
		if ( pCamera )
		{
			// Move the player to the camera point
			engine->SetView( pPlayer->edict(), pCamera->edict() );
			pPlayer->m_Local.m_iHideHUD |= (HIDEHUD_WEAPONS | HIDEHUD_HEALTH | HIDEHUD_MISCSTATUS);
		}
	}

	// Lock the player in place
	pPlayer->LockPlayerInPlace();
}

//-----------------------------------------------------------------------------
// Purpose: Intermission handling
//-----------------------------------------------------------------------------
void CInfoAct::EndIntermission( CBaseTFPlayer *pPlayer )
{
	// Force the player to respawn
	pPlayer->UnlockPlayer();
	engine->SetView( pPlayer->edict(), pPlayer->edict() );
	pPlayer->ForceRespawn();
	pPlayer->m_Local.m_iHideHUD &= ~(HIDEHUD_WEAPONS | HIDEHUD_HEALTH | HIDEHUD_MISCSTATUS);
}

//-----------------------------------------------------------------------------
// Purpose: Force the act to start
//-----------------------------------------------------------------------------
void CInfoAct::InputStart( inputdata_t &inputdata )
{
	StartAct();
}

//-----------------------------------------------------------------------------
// Purpose: Force the act to finish, with team 1 as the winners
//-----------------------------------------------------------------------------
void CInfoAct::InputFinishWinNone( inputdata_t &inputdata )
{
	m_iWinners = 0;
	FinishAct();
}

//-----------------------------------------------------------------------------
// Purpose: Force the act to finish, with team 1 as the winners
//-----------------------------------------------------------------------------
void CInfoAct::InputFinishWin1( inputdata_t &inputdata )
{
	m_iWinners = 1;
	FinishAct();
}

//-----------------------------------------------------------------------------
// Purpose: Force the act to finish, with team 2 as the winners
//-----------------------------------------------------------------------------
void CInfoAct::InputFinishWin2( inputdata_t &inputdata )
{
	m_iWinners = 2;
	FinishAct();
}

//-----------------------------------------------------------------------------
// Purpose: Add time to the act's time
//-----------------------------------------------------------------------------
void CInfoAct::InputAddTime( inputdata_t &inputdata )
{
	float flNewTime = inputdata.value.Float();

	// Think again when the act ends, if we have a timelimit
	if ( flNewTime )
	{
		m_flActTimeLimit += flNewTime;
		SetNextThink( GetNextThink() + flNewTime );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CInfoAct::IsAWaitingAct( void )
{ 
	return HasSpawnFlags(SF_ACT_WAITINGFORGAMESTART);
}

//-----------------------------------------------------------------------------
// Purpose: Return true if the current act (if any) is a waiting act.
//-----------------------------------------------------------------------------
bool CurrentActIsAWaitingAct( void )
{
	if ( g_hCurrentAct )
		return g_hCurrentAct->IsAWaitingAct();

	return false;
}