//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//

#include "cbase.h"
#include "ai_sentence.h"
#include "ai_squad.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

ConVar npc_sentences( "npc_sentences", "0" );


//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_SIMPLE_DATADESC(CAI_SentenceBase)
	DEFINE_FIELD( m_voicePitch, FIELD_INTEGER ),
	DEFINE_FIELD( m_nQueuedSentenceIndex, FIELD_INTEGER ),
	DEFINE_FIELD( m_flQueueTimeout, FIELD_TIME ),
	DEFINE_FIELD( m_nQueueSoundPriority, FIELD_INTEGER ),
END_DATADESC();


//-----------------------------------------------------------------------------
// Speech
//-----------------------------------------------------------------------------
CAI_SentenceBase::CAI_SentenceBase()
{
	ClearQueue();
}


//-----------------------------------------------------------------------------
// Debug output
//-----------------------------------------------------------------------------
void CAI_SentenceBase::SentenceMsg( const char *pStatus, const char *pSentence )
{
	int nMode = npc_sentences.GetInt();
	switch( nMode )
	{
	case 0:
		return;

	case 1:
		DevMsg( "SENTENCE [%d %.2f] %s: %s\n", GetOuter()->entindex(), gpGlobals->curtime, pStatus, pSentence );
		break;

	case 2:
		DevMsg( GetOuter(), "SENTENCE [%d %.2f] %s: %s\n", GetOuter()->entindex(), gpGlobals->curtime, pStatus, pSentence );
		break;
	}
}


//-----------------------------------------------------------------------------
// Check for queued-up-sentences + speak them
//-----------------------------------------------------------------------------
void CAI_SentenceBase::ClearQueue()
{
	m_nQueuedSentenceIndex = -1;
}


//-----------------------------------------------------------------------------
// Check for queued-up-sentences + speak them
//-----------------------------------------------------------------------------
void CAI_SentenceBase::UpdateSentenceQueue()
{
	if ( m_nQueuedSentenceIndex == -1 )
		return;

	// Check for timeout
	if ( m_flQueueTimeout < gpGlobals->curtime )
	{
		ClearQueue();
		return;
	}

	if ( GetOuter()->FOkToMakeSound( m_nQueueSoundPriority ) )
	{
		SENTENCEG_PlaySentenceIndex( GetOuter()->edict(), m_nQueuedSentenceIndex, GetVolume(), GetSoundLevel(), 0, GetVoicePitch() );

		const char *pSentenceName = engine->SentenceNameFromIndex( m_nQueuedSentenceIndex ); 
		SentenceMsg( "Speaking [from QUEUE]", pSentenceName );

		GetOuter()->JustMadeSound( m_nQueueSoundPriority );
		ClearQueue();
	}
}


//-----------------------------------------------------------------------------
// Speech criteria
//-----------------------------------------------------------------------------
bool CAI_SentenceBase::MatchesCriteria( SentenceCriteria_t nCriteria )
{
	switch(	nCriteria )
	{
	case SENTENCE_CRITERIA_ALWAYS:
		return true;

	case SENTENCE_CRITERIA_NORMAL:
		return (GetOuter()->GetState() == NPC_STATE_COMBAT) || (GetOuter()->HasSpawnFlags( SF_NPC_GAG ) == 0);

	case SENTENCE_CRITERIA_IN_SQUAD:
		if ( (GetOuter()->GetState() != NPC_STATE_COMBAT) && GetOuter()->HasSpawnFlags( SF_NPC_GAG ) )
			return false;
		return GetOuter()->GetSquad() && (GetOuter()->GetSquad()->NumMembers() > 1);

	case SENTENCE_CRITERIA_SQUAD_LEADER:
		{
			if ( (GetOuter()->GetState() != NPC_STATE_COMBAT) && GetOuter()->HasSpawnFlags( SF_NPC_GAG ) )
				return false;

			CAI_Squad *pSquad = GetOuter()->GetSquad();
			return pSquad && (pSquad->NumMembers() > 1) && pSquad->IsLeader( GetOuter() );
		}
	}

	return true;
}


//-----------------------------------------------------------------------------
// Play the actual sentence
//-----------------------------------------------------------------------------
int CAI_SentenceBase::PlaySentence( const char *pSentence )
{
	int nSentenceIndex = SENTENCEG_PlayRndSz( GetOuter()->edict(), pSentence, GetVolume(), GetSoundLevel(), 0, GetVoicePitch());
	if ( nSentenceIndex < 0 )
	{
		SentenceMsg( "BOGUS", pSentence );
		return -1;
	}

	const char *pSentenceName = engine->SentenceNameFromIndex( nSentenceIndex ); 
	SentenceMsg( "Speaking", pSentenceName );
	return nSentenceIndex;
}


//-----------------------------------------------------------------------------
// Speech
//-----------------------------------------------------------------------------
int CAI_SentenceBase::Speak( const char *pSentence, SentencePriority_t nSoundPriority, SentenceCriteria_t nCriteria )
{
	if ( !MatchesCriteria(nCriteria) )
		return -1;

	// Speaking clears the queue
	ClearQueue();

	if ( nSoundPriority == SENTENCE_PRIORITY_INVALID )
	{
		return PlaySentence( pSentence );
	}

	int nSentenceIndex = -1;
	if ( GetOuter()->FOkToMakeSound( nSoundPriority ) )
	{
		nSentenceIndex = PlaySentence( pSentence );

		// Make sure sentence length utility works
//		float flSentenceTime = enginesound->GetSoundDuration( nSentenceIndex );
		GetOuter()->JustMadeSound( nSoundPriority, 2.0f /*flSentenceTime*/ );
	}
	else
	{
		SentenceMsg( "CULL", pSentence );
	}

	return nSentenceIndex;
}


//-----------------------------------------------------------------------------
// Speech w/ queue
//-----------------------------------------------------------------------------
int CAI_SentenceBase::SpeakQueued( const char *pSentence, SentencePriority_t nSoundPriority, SentenceCriteria_t nCriteria )
{
	if ( !MatchesCriteria(nCriteria) )
		return -1;

	// Speaking clears the queue
	ClearQueue();

	int nSentenceIndex = Speak( pSentence, nSoundPriority, nCriteria );
	if ( nSentenceIndex >= 0 )
		return nSentenceIndex;
	
	// Queue up the sentence for later playing 
	int nQueuedSentenceIndex = SENTENCEG_PickRndSz( pSentence );
	if ( nQueuedSentenceIndex == -1 )
		return -1;

	int nSquadCount = GetOuter()->GetSquad() ? GetOuter()->GetSquad()->NumMembers() : 1;
	m_flQueueTimeout = gpGlobals->curtime + nSquadCount * 2.0f;
	m_nQueueSoundPriority = nSoundPriority;
	m_nQueuedSentenceIndex = nQueuedSentenceIndex;
	return -1;
}