Пример #1
0
bool CDialogActorContext::Update(float dt)
{
	if (IsAborted())
		return true;

	// FIXME: this should never happen, as we should get a notification before.
	//        temp leave in for tracking down a bug [AlexL: 23/11/2006]
	IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_entityID);
	if (pEntity == 0)
	{
		m_pIActor = 0;
		GameWarning("[DIALOG] CDialogActorContext::Update: %s Actor=%d (EntityId=%d) no longer existent.",
			m_pSession->GetDebugName(), m_actorID, m_entityID);
		AbortContext(true, CDialogSession::eAR_EntityDestroyed);
		return true;
	}

	CDialogSession::AlertnessInterruptMode alertnessInterruptMode = m_pSession->GetAlertnessInterruptMode();
	if(alertnessInterruptMode != CDialogSession::None)
	{
		if(IAIObject* aiObject = pEntity->GetAI())
		{
			if(IAIActorProxy* aiActorProxy = aiObject->GetProxy())
			{
				if(aiActorProxy->GetAlertnessState() >= alertnessInterruptMode)
				{
					AbortContext(true, CDialogSession::eAR_AIAborted);
					return true;
				}
			}
		}
	}

	float now = m_pSession->GetCurTime();

	if (!CheckActorFlags(CDialogSession::eDACF_NoActorDeadAbort) && m_pIActor && m_pIActor->IsDead())
	{
		if (!IsAborted())
		{
			DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Actor=%d (EntityId=%d) has died. Aborting.",
				m_pSession->GetDebugName(), m_actorID, m_entityID);
			AbortContext(true, CDialogSession::eAR_ActorDead);
			return true;
		}
	}

	if (m_bIsLocalPlayer)
	{
		// when the local player is involved in the conversation do some special checks
		if (DoLocalPlayerChecks(dt) == false)
		{
			DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Abort from LocalPlayer.", m_pSession->GetDebugName());
			AbortContext(true, m_bIsAwareInRange == false ? CDialogSession::eAR_PlayerOutOfRange : CDialogSession::eAR_PlayerOutOfView);
			return true;
		}
	}

	if (m_bAbortFromAI)
	{
		m_bAbortFromAI = false;
		if (!IsAborted())
		{
			DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Abort from AI.", m_pSession->GetDebugName());
			AbortContext(true, CDialogSession::eAR_AIAborted);
			return true;
		}
	}

	if (SessionAllowsLookAt())
	{
		DoStickyLookAt();
	}

	int loop = 0;
	do 
	{
		// DiaLOG::Log("[DIALOG] DiaLOG::eAlways"CDialogActorContext::Update: %s now=%f actorId=%d loop=%d", m_pSession->GetDebugName(), now, m_actorID, loop);

		bool bAdvance = false;
		switch (m_phase)
		{
		case eDAC_Idle:
			break;

		case eDAC_NewLine:
			{
				m_bHasScheduled = false;
				m_lookAtTimeOut = LOOKAT_TIMEOUT;
				m_animTimeOut   = ANIM_TIMEOUT;
				m_soundTimeOut  = SOUND_TIMEOUT; // wait one second until sound is timed out
				m_bAnimScheduled = false;
				m_bAnimStarted   = false;
				m_bSoundScheduled = false;
				m_bSoundStarted   = false;
				m_soundLength   = 0.0f;

				if (m_pCurLine->m_flagResetLookAt)
				{
					m_stickyLookAtActorID = CDialogScript::NO_ACTOR_ID;
					m_lookAtActorID = CDialogScript::NO_ACTOR_ID;
				}
				// check if look-at sticky is set
				else if (m_pCurLine->m_lookatActor != CDialogScript::NO_ACTOR_ID)
				{
					if (m_pCurLine->m_flagLookAtSticky == false)
					{
						m_lookAtActorID = m_pCurLine->m_lookatActor;
						m_stickyLookAtActorID = CDialogScript::NO_ACTOR_ID;
					}
					else
					{
						m_stickyLookAtActorID = m_pCurLine->m_lookatActor;
						m_lookAtActorID = CDialogScript::NO_ACTOR_ID;
					}
				}

				bAdvance = true;

				// handle the first sticky look-at here
				if (SessionAllowsLookAt())
				{
					DoStickyLookAt();
				}









			}
			break;

		case eDAC_LookAt:
			{
				bool bWaitForLookAtFinish = true;
				bAdvance = true;
	
				if (SessionAllowsLookAt() == false)
				{
					break;
				}

				// Question: maybe do this although EP is requested
				if (bWaitForLookAtFinish && m_lookAtActorID != CDialogScript::NO_ACTOR_ID && m_pCurLine->m_flagAGEP == false) 
				{
					IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
					IEntity* pLookAtEntity = m_pSession->GetActorEntity(m_lookAtActorID);
					if (pActorEntity != 0)
					{
						m_lookAtTimeOut -= dt;
						bool bTargetReached;
						//bool bSuccess = DoLookAt(pActorEntity, pLookAtEntity, bTargetReached);
						DoLookAt(pActorEntity, pLookAtEntity, bTargetReached);
						//DiaLOG::Log(DiaLOG::eDebugA, "[DIALOG] CDialogActorContext::Update: %s now=%f actorID=%d phase=eDAC_LookAt %d",
						//	m_pSession->GetDebugName(), now, m_actorID, bTargetReached);

						if (/* bSuccess == false || */ bTargetReached || m_lookAtTimeOut<=0.0f)
						{
							DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s now=%f actorID=%d phase=eDAC_LookAt %s",
								m_pSession->GetDebugName(), now, m_actorID, bTargetReached ? "Target Reached" : "Timed Out");
							m_lookAtActorID = CDialogScript::NO_ACTOR_ID;
						}
						else
							bAdvance = false;
					}
				}
			}
			break;

		case eDAC_Anim:
			{
				bAdvance = true;
				if (SessionAllowsLookAt() && m_lookAtActorID != CDialogScript::NO_ACTOR_ID) // maybe: don't do this when EP is requested [&& m_pCurLine->m_flagAGEP == false]
				{
					IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
					IEntity* pLookAtEntity = m_pSession->GetActorEntity(m_lookAtActorID);
					if (pActorEntity != 0)
					{
						m_lookAtTimeOut -= dt;
						bool bTargetReached;
						//bool bSuccess = DoLookAt(pActorEntity, pLookAtEntity, bTargetReached);
						DoLookAt(pActorEntity, pLookAtEntity, bTargetReached);
						if (/* bSuccess == false || */ bTargetReached || m_lookAtTimeOut<=0.0f)
						{
							DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s now=%f actorID=%d phase=eDAC_Anim %s",
								m_pSession->GetDebugName(), now, m_actorID, bTargetReached ? "Target Reached" : "Timed Out");
							m_lookAtActorID = CDialogScript::NO_ACTOR_ID;
						}
						else
							bAdvance = false;
					}
				}
				const bool bHasAnim = !m_pCurLine->m_anim.empty();
				if (SessionAllowsAnim() && bHasAnim)
				{
					bAdvance = false;
					if (!m_bAnimScheduled)
					{
						m_bSoundStopsAnim = false; // whenever there is a new animation, no need for the still playing sound
						                           // to stop the animation
						m_bAnimStarted = false;
						m_bAnimScheduled = true;
						// schedule animation
						IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
						if (pActorEntity)
							DoAnimAction(pActorEntity, m_pCurLine->m_anim, m_pCurLine->m_flagAGSignal, m_pCurLine->m_flagAGEP);
						else
							bAdvance = true;
					}
					else
					{
						// we scheduled it already
						// wait until it starts or timeout
						m_animTimeOut-=dt;
						bAdvance = m_animTimeOut <= 0.0f || m_bAnimStarted;
						if (bAdvance)
						{
							DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Now=%f actorID=%d phase=eDAC_Anim %s",
								m_pSession->GetDebugName(), now, m_actorID, m_bAnimStarted ? "Anim Started" : "Anim Timed Out");
						}
					}
				}
			}
			break;

		case eDAC_ScheduleSoundPlay:
			{
				bAdvance = true;
				const bool bHasSound  = !m_pCurLine->m_sound.empty();
				if (bHasSound)
				{
					if (m_bSoundScheduled == false)
					{
						IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
						if (pActorEntity == 0)
							break;

						IEntityAudioProxy* pActorAudioProxy = m_pSession->GetEntityAudioProxy(pActorEntity);
						if (pActorAudioProxy == 0)
							break;

						REINST("play voice line");
						// start a new sound
						//int sFlags = CDialogActorContext::SOUND_FLAGS;
						//if (CDialogSystem::sLoadSoundSynchronously != 0)
						//	sFlags |= FLAG_SOUND_LOAD_SYNCHRONOUSLY;
						//
						//// if it's the local player make the sound relative to the entity
						//if (m_bIsLocalPlayer)
						//	sFlags |= FLAG_SOUND_RELATIVE;

						//const char* soundKey = GetSoundKey(m_pCurLine->m_sound);
						//ISound* pSound = 0;

						//pSound = gEnv->pAudioSystem->CreateSound(soundKey, sFlags);

						//DiaLOG::Log(DiaLOG::eDebugA, "[DIALOG] CDialogActorContex::Update: %s Now=%f actorID=%d phase=eDAC_ScheduleSoundPlay: Starting '%s' [key=%s]",
						//	m_pSession->GetDebugName(), now, m_actorID, m_pCurLine->m_sound.c_str(), soundKey);

						//if (!pSound) 
						//{
						//	GameWarning("[DIALOG] CDialogActorContext::Update: %s ActorID=%d: Cannot play sound '%s'",
						//		m_pSession->GetDebugName(), m_actorID, m_pCurLine->m_sound.c_str());
						//}

						//if (pSound)
						//{
						//	if (m_bSoundStopsAnim)
						//	{
						//		m_bSoundStopsAnim = false;
						//		if (m_pAGState != 0)
						//		{
						//			ResetAGState();
						//			DiaLOG::Log(DiaLOG::eDebugA, "[DIALOG] CDialogActorContext::Update: %s Now=%f actorID=%d phase=eDAC_ScheduleSoundPlay: Stopping old animation",
						//				m_pSession->GetDebugName(), now, m_actorID);
						//		}
						//	}
						//	StopSound(); // apparently, if we dont explicitely stop the sound, in rare cases it never stops. Im pretty sure that is an engine/fmod bug.
						//	             // stopping it this way may lead to some subtitles staying for an extra couple seconds on screen (this comes from another engine bug/problem related to an extra fade out time added to cover the dummy NAX soudns) 
						//	m_soundID = pSound->GetId();
						//	m_bSoundStarted = false;
						//	m_bSoundScheduled = true;
						//	// tell the animation whether to stop on sound stop
						//	m_bSoundStopsAnim = m_pCurLine->m_flagSoundStopsAnim;

						//	DiaLOG::Log(DiaLOG::eDebugA, "[DIALOG] CDialogActorContext::Update: %s Now=%f actorID=%d phase=eDAC_ScheduleSoundPlay: Reg as listener on 0x%p '%s'",
						//		m_pSession->GetDebugName(), now, m_actorID, pSound, pSound->GetName());

						//	pSound->SetSemantic(eSoundSemantic_Dialog);
						//	pSound->AddEventListener(this, "DialogActor"); // event listener will set m_soundLength
						//	// sound proxy uses head pos on dialog sounds
						//	const bool bResult = pActorAudioProxy->PlaySound(pSound, Vec3(ZERO), FORWARD_DIRECTION, 1.0f);

						//	if (bResult)
						//	{
						//		// Fetch some localization info for the sound
						//		ILocalizationManager* pLocMgr = gEnv->pSystem->GetLocalizationManager();
						//		if (pLocMgr && CDialogSystem::sWarnOnMissingLoc != 0)
						//		{
						//			SLocalizedInfoGame GameInfo;

						//			const bool bFound = pLocMgr->GetLocalizedInfoByKey(soundKey, GameInfo);
						//			if (!bFound)
						//			{
						//				GameWarning("[DIALOG] CDialogActorContext::Update: '%s' DialogScript '%s': Localized info for '%s' not found!", 
						//					m_pSession->GetDebugName(), m_pSession->GetScript()->GetID().c_str(), m_pCurLine->m_sound.c_str());
						//			}
						//		}

						//		bAdvance = false; // don't advance
						//	}
						//	else
						//	{
						//		GameWarning("[DIALOG] CDialogActorContext::Update: %s ActorID=%d: Cannot play sound '%s' [AudioProxy ignored playback]",
						//			m_pSession->GetDebugName(), m_actorID, m_pCurLine->m_sound.c_str());

						//		pSound->Stop(ESoundStopMode_AtOnce);
						//		m_soundID = INVALID_SOUNDID;
						//		pSound->RemoveEventListener(this);
						//		pSound = NULL;
						//	}
						//}
						//else
						//{
						//	GameWarning("[DIALOG] CDialogActorContext::Update: %s ActorID=%d: Cannot play sound '%s' [AudioProxy returns invalid sound]",
						//		m_pSession->GetDebugName(), m_actorID, m_pCurLine->m_sound.c_str());
						//}
					}
					else
					{
						// sound has been scheduled
						// wait for sound start or timeout
						m_soundTimeOut-=dt;
						const bool bTimedOut = m_soundTimeOut <= 0.0f;
						bAdvance = bTimedOut || m_bSoundStarted;
						if (bAdvance)
						{
							if (bTimedOut)
								StopSound(true); // unregister from sound as listener and free resource
							DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Now=%f actorID=%d phase=eDAC_ScheduleSoundPlay %s",
								m_pSession->GetDebugName(), now, m_actorID, m_bSoundStarted ? "Sound Started" : "Sound Timed Out");
						}
					}
				}
			}
			break;

		case eDAC_SoundFacial:
			{
				bAdvance = true;
				const bool bHasSound  = !m_pCurLine->m_sound.empty();
				const bool bHasFacial = !m_pCurLine->m_facial.empty() || m_pCurLine->m_flagResetFacial;
				if (bHasFacial)
				{
					IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
					if (pActorEntity)
						DoFacialExpression(pActorEntity, m_pCurLine->m_facial, m_pCurLine->m_facialWeight, m_pCurLine->m_facialFadeTime);
				}

				float delay = m_pCurLine->m_delay;
				if (bHasSound && m_bSoundStarted)
				{
					if (m_soundLength < 0.0f)
					{
						m_soundLength = Random(2.0f,6.0f);
						DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Now=%f actorID=%d phase=eDAC_SoundFacial Faking SoundTime to %f",
							m_pSession->GetDebugName(), now, m_actorID, m_soundLength);
					}

					DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Now=%f actorID=%d phase=eDAC_SoundFacial Delay=%f SoundTime=%f",
						m_pSession->GetDebugName(), now , m_actorID, delay, m_soundLength);
					delay += m_soundLength;
				}

				// schedule END
				if (delay < 0.0f)
					delay = 0.0f;
				m_pSession->ScheduleNextLine(delay+0.05f); // ~1 frame at 20 fps. we now stop the current line sound before going for next line. Sometimes, this stop call is right before the
																									 // sound has actually stopped in engine side. When that happens, the engine is adding ~2 seconds extra to the sound duration (because fade problems related to NAX header)
																									 // and that looks bad if subtitles are enabled. So we add this small delay here to try to minimize that situation.
																									 // this is part of the workaround for some dialogs apparently never finishing in the engine side (rare).
				m_bHasScheduled = true;
			}
			break;

		case eDAC_EndLine:
			bAdvance = true;
			if (m_bHasScheduled == false)
			{
				m_bHasScheduled = true;
				m_pSession->ScheduleNextLine(m_pCurLine->m_delay);
			}
			break;
		}

		if (bAdvance)
		{
			AdvancePhase();
			dt = 0.0f;
			++loop;
			assert (loop <= eDAC_EndLine+1);
			if (loop > eDAC_EndLine+1)
			{
				DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Actor=%d InternalLoopCount=%d. Final Exit!",
					m_pSession->GetDebugName(), m_actorID, loop);
			}
		}
		else
			break;
	}
	while (true);

	return true;
}
bool CDialogActorContext::Update(float dt)
{
    if (IsAborted())
        return true;

    // FIXME: this should never happen, as we should get a notification before.
    //        temp leave in for tracking down a bug [AlexL: 23/11/2006]
    IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_entityID);
    if (pEntity == 0)
    {
        m_pIActor = 0;
        GameWarning("[DIALOG] CDialogActorContext::Update: %s Actor=%d (EntityId=%d) no longer existent.",
                    m_pSession->GetDebugName(), m_actorID, m_entityID);
        AbortContext(true, CDialogSession::eAR_EntityDestroyed);
        return true;
    }

    CDialogSession::AlertnessInterruptMode alertnessInterruptMode = m_pSession->GetAlertnessInterruptMode();
    if(alertnessInterruptMode != CDialogSession::None)
    {
        if(IAIObject* aiObject = pEntity->GetAI())
        {
            if(IAIActorProxy* aiActorProxy = aiObject->GetProxy())
            {
                if(aiActorProxy->GetAlertnessState() >= alertnessInterruptMode)
                {
                    AbortContext(true, CDialogSession::eAR_AIAborted);
                    return true;
                }
            }
        }
    }

    float now = m_pSession->GetCurTime();

    if (!CheckActorFlags(CDialogSession::eDACF_NoActorDeadAbort) && m_pIActor && m_pIActor->IsDead())
    {
        if (!IsAborted())
        {
            DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Actor=%d (EntityId=%d) has died. Aborting.",
                        m_pSession->GetDebugName(), m_actorID, m_entityID);
            AbortContext(true, CDialogSession::eAR_ActorDead);
            return true;
        }
    }

    if (m_bIsLocalPlayer)
    {
        // when the local player is involved in the conversation do some special checks
        if (DoLocalPlayerChecks(dt) == false)
        {
            DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Abort from LocalPlayer.", m_pSession->GetDebugName());
            AbortContext(true, m_bIsAwareInRange == false ? CDialogSession::eAR_PlayerOutOfRange : CDialogSession::eAR_PlayerOutOfView);
            return true;
        }
    }

    if (m_bAbortFromAI)
    {
        m_bAbortFromAI = false;
        if (!IsAborted())
        {
            DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Abort from AI.", m_pSession->GetDebugName());
            AbortContext(true, CDialogSession::eAR_AIAborted);
            return true;
        }
    }

    if (SessionAllowsLookAt())
    {
        DoStickyLookAt();
    }

    int loop = 0;
    do
    {
        // DiaLOG::Log("[DIALOG] DiaLOG::eAlways"CDialogActorContext::Update: %s now=%f actorId=%d loop=%d", m_pSession->GetDebugName(), now, m_actorID, loop);

        bool bAdvance = false;
        switch (m_phase)
        {
        case eDAC_Idle:
            break;

        case eDAC_NewLine:
        {
            m_bHasScheduled = false;
            m_lookAtTimeOut = LOOKAT_TIMEOUT;
            m_animTimeOut   = ANIM_TIMEOUT;
            m_soundTimeOut  = SOUND_TIMEOUT; // wait one second until sound is timed out
            m_bAnimScheduled = false;
            m_bAnimStarted   = false;
            m_bSoundScheduled = false;
            m_bSoundStarted   = false;
            m_soundLength   = 0.0f;

            if (m_pCurLine->m_flagResetLookAt)
            {
                m_stickyLookAtActorID = CDialogScript::NO_ACTOR_ID;
                m_lookAtActorID = CDialogScript::NO_ACTOR_ID;
            }
            // check if look-at sticky is set
            else if (m_pCurLine->m_lookatActor != CDialogScript::NO_ACTOR_ID)
            {
                if (m_pCurLine->m_flagLookAtSticky == false)
                {
                    m_lookAtActorID = m_pCurLine->m_lookatActor;
                    m_stickyLookAtActorID = CDialogScript::NO_ACTOR_ID;
                }
                else
                {
                    m_stickyLookAtActorID = m_pCurLine->m_lookatActor;
                    m_lookAtActorID = CDialogScript::NO_ACTOR_ID;
                }
            }

            bAdvance = true;

            // handle the first sticky look-at here
            if (SessionAllowsLookAt())
            {
                DoStickyLookAt();
            }

#if 0   // test for immediate scheduling of next line while the current line is still playing
            // maybe we're going to use some special delay TAGS like FORCE_NEXT, WAIT
            if (m_pCurLine->m_delay <= -999.0f)
            {
                m_bHasScheduled = true;
                m_pSession->ScheduleNextLine(0.0f);
            }
#endif
        }
        break;

        case eDAC_LookAt:
        {
            bool bWaitForLookAtFinish = true;
            bAdvance = true;

            if (SessionAllowsLookAt() == false)
            {
                break;
            }

            // Question: maybe do this although EP is requested
            if (bWaitForLookAtFinish && m_lookAtActorID != CDialogScript::NO_ACTOR_ID && m_pCurLine->m_flagAGEP == false)
            {
                IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
                IEntity* pLookAtEntity = m_pSession->GetActorEntity(m_lookAtActorID);
                if (pActorEntity != 0)
                {
                    m_lookAtTimeOut -= dt;
                    bool bTargetReached;
                    //bool bSuccess = DoLookAt(pActorEntity, pLookAtEntity, bTargetReached);
                    DoLookAt(pActorEntity, pLookAtEntity, bTargetReached);
                    //DiaLOG::Log(DiaLOG::eDebugA, "[DIALOG] CDialogActorContext::Update: %s now=%f actorID=%d phase=eDAC_LookAt %d",
                    //	m_pSession->GetDebugName(), now, m_actorID, bTargetReached);

                    if (/* bSuccess == false || */ bTargetReached || m_lookAtTimeOut<=0.0f)
                    {
                        DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s now=%f actorID=%d phase=eDAC_LookAt %s",
                                    m_pSession->GetDebugName(), now, m_actorID, bTargetReached ? "Target Reached" : "Timed Out");
                        m_lookAtActorID = CDialogScript::NO_ACTOR_ID;
                    }
                    else
                        bAdvance = false;
                }
            }
        }
        break;

        case eDAC_Anim:
        {
            bAdvance = true;
            if (SessionAllowsLookAt() && m_lookAtActorID != CDialogScript::NO_ACTOR_ID) // maybe: don't do this when EP is requested [&& m_pCurLine->m_flagAGEP == false]
            {
                IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
                IEntity* pLookAtEntity = m_pSession->GetActorEntity(m_lookAtActorID);
                if (pActorEntity != 0)
                {
                    m_lookAtTimeOut -= dt;
                    bool bTargetReached;
                    //bool bSuccess = DoLookAt(pActorEntity, pLookAtEntity, bTargetReached);
                    DoLookAt(pActorEntity, pLookAtEntity, bTargetReached);
                    if (/* bSuccess == false || */ bTargetReached || m_lookAtTimeOut<=0.0f)
                    {
                        DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s now=%f actorID=%d phase=eDAC_Anim %s",
                                    m_pSession->GetDebugName(), now, m_actorID, bTargetReached ? "Target Reached" : "Timed Out");
                        m_lookAtActorID = CDialogScript::NO_ACTOR_ID;
                    }
                    else
                        bAdvance = false;
                }
            }
            const bool bHasAnim = !m_pCurLine->m_anim.empty();
            if (SessionAllowsAnim() && bHasAnim)
            {
                bAdvance = false;
                if (!m_bAnimScheduled)
                {
                    m_bSoundStopsAnim = false; // whenever there is a new animation, no need for the still playing sound
                    // to stop the animation
                    m_bAnimStarted = false;
                    m_bAnimScheduled = true;
                    // schedule animation
                    IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
                    if (pActorEntity)
                        DoAnimAction(pActorEntity, m_pCurLine->m_anim, m_pCurLine->m_flagAGSignal, m_pCurLine->m_flagAGEP);
                    else
                        bAdvance = true;
                }
                else
                {
                    // we scheduled it already
                    // wait until it starts or timeout
                    m_animTimeOut-=dt;
                    bAdvance = m_animTimeOut <= 0.0f || m_bAnimStarted;
                    if (bAdvance)
                    {
                        DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Now=%f actorID=%d phase=eDAC_Anim %s",
                                    m_pSession->GetDebugName(), now, m_actorID, m_bAnimStarted ? "Anim Started" : "Anim Timed Out");
                    }
                }
            }
        }
        break;

        case eDAC_ScheduleSoundPlay:
        {
            bAdvance = true;
            const bool bHasSound  = m_pCurLine->m_audioID != INVALID_AUDIO_CONTROL_ID;
            if (bHasSound)
            {
                if (m_bSoundScheduled == false)
                {
                    IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
                    if (pActorEntity == 0)
                        break;

                    IEntityAudioProxy* pActorAudioProxy = m_pSession->GetEntityAudioProxy(pActorEntity);

                    if (pActorAudioProxy == 0)
                        break;

                    if(m_SpeechAuxProxy == INVALID_AUDIO_PROXY_ID)
                    {
                        m_SpeechAuxProxy = pActorAudioProxy->CreateAuxAudioProxy();
                        pActorAudioProxy->AddAsListenerToAuxAudioProxy(m_SpeechAuxProxy, &CDialogActorContext::OnAudioTriggerFinished, eART_AUDIO_CALLBACK_MANAGER_REQUEST, eACMRT_REPORT_FINISHED_TRIGGER_INSTANCE);
                    }
                    UpdateAuxProxyPosition();

                    SAudioCallBackInfos callbackInfos(0, (void*)CDialogActorContext::GetClassIdentifier(), reinterpret_cast<void*>(static_cast<intptr_t>(m_ContextID)), eARF_PRIORITY_NORMAL | eARF_SYNC_FINISHED_CALLBACK);
                    if(!pActorAudioProxy->ExecuteTrigger(m_pCurLine->m_audioID, eLSM_None, m_SpeechAuxProxy, callbackInfos))
                    {
                        m_bSoundStarted = false;
                        m_bHasScheduled = false;
                        m_pSession->ScheduleNextLine(2.0f);
                    }
                    else
                    {
                        m_bSoundStarted = true;
                        m_bHasScheduled = true;
                        //todo: get the length of the sound to schedule the next line (set m_soundLength). Currently we schedule the next line as soon as the current one is finished, ignoring the specified "delay" parameter. its done in: DialogTriggerFinishedCallback

                        const char* triggerName = gEnv->pAudioSystem->GetAudioControlName(eACT_TRIGGER, m_pCurLine->m_audioID);
                        if (triggerName == NULL)
                            triggerName =  "dialog trigger";
                        DiaLOG::Log(DiaLOG::eDebugA, "[DIALOG] CDialogActorContex::Update: %s Now=%f actorID=%d phase=eDAC_ScheduleSoundPlay: Starting '%s'",
                                    m_pSession->GetDebugName(), now, m_actorID, triggerName);
                    }
                }
                else
                {
                    // sound has been scheduled
                    // wait for sound start or timeout
                    m_soundTimeOut-=dt;
                    const bool bTimedOut = m_soundTimeOut <= 0.0f;
                    bAdvance = bTimedOut || m_bSoundStarted;
                    if (bAdvance)
                    {
                        if (bTimedOut)
                            StopSound(true); // unregister from sound as listener and free resource
                        DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Now=%f actorID=%d phase=eDAC_ScheduleSoundPlay %s",
                                    m_pSession->GetDebugName(), now, m_actorID, m_bSoundStarted ? "Sound Started" : "Sound Timed Out");
                    }
                }
            }
        }
        break;

        case eDAC_SoundFacial:
        {
            bAdvance = true;
            const bool bHasSound  = m_pCurLine->m_audioID != INVALID_AUDIO_CONTROL_ID;
            const bool bHasFacial = !m_pCurLine->m_facial.empty() || m_pCurLine->m_flagResetFacial;
            if (bHasFacial)
            {
                IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
                if (pActorEntity)
                    DoFacialExpression(pActorEntity, m_pCurLine->m_facial, m_pCurLine->m_facialWeight, m_pCurLine->m_facialFadeTime);
            }

            //hd-todo: re-add me, when we have a way to query the length of the audio-lines
            //float delay = m_pCurLine->m_delay;
            //if (bHasSound && m_bSoundStarted)
            //{
            //	if (m_soundLength <= 0.0f)
            //	{
            //		m_soundLength = cry_random(2.0f, 6.0f);
            //		DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Now=%f actorID=%d phase=eDAC_SoundFacial Faking SoundTime to %f",
            //			m_pSession->GetDebugName(), now, m_actorID, m_soundLength);
            //	}

            //	DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Now=%f actorID=%d phase=eDAC_SoundFacial Delay=%f SoundTime=%f",
            //		m_pSession->GetDebugName(), now , m_actorID, delay, m_soundLength);
            //	delay += m_soundLength;
            //}

            //// schedule END
            //if (delay < 0.0f)
            //	delay = 0.0f;
            //m_pSession->ScheduleNextLine(delay+0.05f); // ~1 frame at 20 fps. we now stop the current line sound before going for next line. Sometimes, this stop call is right before the
            //																					 // sound has actually stopped in engine side. When that happens, the engine is adding ~2 seconds extra to the sound duration (because fade problems related to NAX header)
            //																					 // and that looks bad if subtitles are enabled. So we add this small delay here to try to minimize that situation.
            //																					 // this is part of the workaround for some dialogs apparently never finishing in the engine side (rare).
            //m_bHasScheduled = true;
        }
        break;

        case eDAC_EndLine:
            bAdvance = true;
            if (m_bHasScheduled == false)
            {
                m_bHasScheduled = true;
                m_pSession->ScheduleNextLine(m_pCurLine->m_delay);
            }
            break;
        }

        if (bAdvance)
        {
            AdvancePhase();
            dt = 0.0f;
            ++loop;
            assert (loop <= eDAC_EndLine+1);
            if (loop > eDAC_EndLine+1)
            {
                DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Actor=%d InternalLoopCount=%d. Final Exit!",
                            m_pSession->GetDebugName(), m_actorID, loop);
            }
        }
        else
        {
            if (IsStillPlaying())
            {
                UpdateAuxProxyPosition();
            }

            break;
        }
    }
    while (true);

    return true;
}