BVB Source Codes

CRYENGINE Show DialogActorContext.cpp Source code

Return Download CRYENGINE: download DialogActorContext.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. #include "StdAfx.h"
  4. #include "DialogActorContext.h"
  5. #include "DialogSession.h"
  6. #include "DialogCommon.h"
  7. #include <CryAnimation/ICryAnimation.h>
  8. #include <CryAnimation/IFacialAnimation.h>
  9. #include <CryString/StringUtils.h>
  10. #include "IMovementController.h"
  11. #include <CrySystem/ILocalizationManager.h>
  12. #include <CryAISystem/IAIObject.h>
  13. #include <CryAISystem/IAIActor.h>
  14. #include <CryAISystem/IAIActorProxy.h>
  15.  
  16. static const float LOOKAT_TIMEOUT = 1.0f;
  17. static const float ANIM_TIMEOUT = 1.0f;
  18. static const float SOUND_TIMEOUT = 1.0f;
  19. static const float PLAYER_CHECKTIME = 0.2f;    // check the player every 0.2 seconds
  20.  
  21. static const uint32 INVALID_FACIAL_CHANNEL_ID = ~0;
  22.  
  23. #define DIALOG_VOICE_POSITION_NEEDS_UPDATE -2
  24.  
  25. string CDialogActorContext::m_tempBuffer;
  26.  
  27. void CDialogActorContext::ResetStaticData()
  28. {
  29.         stl::free_container(m_tempBuffer);
  30. }
  31.  
  32. // returns ptr to static string buffer.
  33. const char* CDialogActorContext::GetSoundKey(const string& soundName)
  34. {
  35.         stack_string const sLocalizationFolder(PathUtil::GetLocalizationFolder() + CRY_NATIVE_PATH_SEPSTR "dialog" CRY_NATIVE_PATH_SEPSTR);
  36.         const size_t prefixLen = sLocalizationFolder.size();
  37.  
  38.         // check if it already starts localizationfoldername/dialog. then replace it
  39.         if (strnicmp(soundName.c_str(), sLocalizationFolder.c_str(), prefixLen) == 0)
  40.         {
  41.                 m_tempBuffer.assign(soundName.c_str() + prefixLen);
  42.         }
  43.         else
  44.         {
  45.                 m_tempBuffer.assign(soundName);
  46.         }
  47.         PathUtil::RemoveExtension(m_tempBuffer);
  48.         return m_tempBuffer.c_str();
  49. }
  50.  
  51. // returns ptr to static string buffer.
  52. const char* CDialogActorContext::FullSoundName(const string& soundName, bool bWav)
  53. {
  54.         stack_string const sLocalizationFolder(PathUtil::GetLocalizationFolder() + CRY_NATIVE_PATH_SEPSTR "dialog" CRY_NATIVE_PATH_SEPSTR);
  55.  
  56.         // check if it already starts with full path
  57.         if (CryStringUtils::stristr(soundName.c_str(), sLocalizationFolder.c_str()) == soundName.c_str())
  58.         {
  59.                 m_tempBuffer = soundName;
  60.         }
  61.         else
  62.         {
  63.                 m_tempBuffer = sLocalizationFolder.c_str();
  64.                 m_tempBuffer += soundName;
  65.         }
  66.         PathUtil::RemoveExtension(m_tempBuffer);
  67.         if (bWav)
  68.                 m_tempBuffer += ".wav";
  69.         return m_tempBuffer.c_str();
  70. }
  71.  
  72. ////////////////////////////////////////////////////////////////////////////
  73. CDialogActorContext::CDialogActorContext(CDialogSession* pSession, CDialogScript::TActorID actorID)
  74.         : m_pCurLine(0)
  75. {
  76.         static int uniqueID = 0;
  77.         m_ContextID = ++uniqueID;
  78.  
  79.         m_pSession = pSession;
  80.         m_actorID = actorID;
  81.         m_entityID = pSession->GetActorEntityId(m_actorID);
  82.         IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_entityID);
  83.         const char* debugName = pEntity ? pEntity->GetName() : "<no entity>";
  84.         m_pIActor = CCryAction::GetCryAction()->GetIActorSystem()->GetActor(m_entityID);
  85.         m_bIsLocalPlayer = m_pIActor != 0 && CCryAction::GetCryAction()->GetClientActor() == m_pIActor;
  86.         m_SpeechAuxProxy = INVALID_AUDIO_PROXY_ID;
  87.  
  88.         ResetState();
  89.         DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::ctor: %s 0x%p actorID=%d entity=%s entityId=%u",
  90.                     m_pSession->GetDebugName(), this, m_actorID, debugName, m_entityID);
  91. }
  92.  
  93. ////////////////////////////////////////////////////////////////////////////
  94. CDialogActorContext::~CDialogActorContext()
  95. {
  96.         if (m_SpeechAuxProxy != INVALID_AUDIO_PROXY_ID)
  97.         {
  98.                 IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
  99.                 if (pActorEntity)
  100.                 {
  101.                         IEntityAudioComponent* pActorAudioProxy = m_pSession->GetEntityAudioProxy(pActorEntity);
  102.                         if (pActorAudioProxy)
  103.                         {
  104.                                 pActorAudioProxy->RemoveAsListenerFromAuxAudioProxy(m_SpeechAuxProxy, &CDialogActorContext::OnAudioTriggerFinished);
  105.                                 pActorAudioProxy->RemoveAuxAudioProxy(m_SpeechAuxProxy);
  106.                         }
  107.                 }
  108.         }
  109.  
  110.         StopSound();
  111.         CancelCurrent();
  112.         IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_entityID);
  113.         const char* debugName = pEntity ? pEntity->GetName() : "<no entity>";
  114.         DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::dtor: %s 0x%p actorID=%d entity=%s entityId=%d",
  115.                     m_pSession->GetDebugName(), this, m_actorID, debugName, m_entityID);
  116. }
  117.  
  118. ////////////////////////////////////////////////////////////////////////////
  119. void CDialogActorContext::ResetState()
  120. {
  121.         // stop sound just in case to prevent forgetting to unrgister ourself as sound listener(can lead to a crash due dangling ptr)
  122.         StopSound();
  123.         m_pCurLine = 0;
  124.         m_pAGState = 0;
  125.         m_queryID = 0;
  126.         m_bAnimStarted = false;
  127.         m_bAnimUseAGSignal = false;
  128.         m_bAnimUseEP = false;
  129.         m_lookAtActorID = CDialogScript::NO_ACTOR_ID;
  130.         m_stickyLookAtActorID = CDialogScript::NO_ACTOR_ID;
  131.         m_bLookAtNeedsReset = false;
  132.         m_goalPipeID = 0;
  133.         m_exPosAnimPipeID = 0;
  134.         m_phase = eDAC_Idle;
  135.         m_bInCancel = false;
  136.         m_bAbortFromAI = false;
  137.         m_abortReason = CDialogSession::eAR_None;
  138.         m_bIsAware = true;
  139.         m_bIsAwareLooking = true;
  140.         m_bIsAwareInRange = true;
  141.         m_bSoundStopsAnim = false;
  142.         m_checkPlayerTimeOut = 0.0f;                                      // start to check player on start
  143.         m_playerAwareTimeOut = m_pSession->GetPlayerAwarenessGraceTime(); // set timeout
  144.         m_currentEffectorChannelID = INVALID_FACIAL_CHANNEL_ID;
  145.         m_bNeedsCancel = false; // no cancel on start
  146.         m_bSoundStarted = false;
  147.         m_VoiceAttachmentIndex = DIALOG_VOICE_POSITION_NEEDS_UPDATE;
  148.         m_BoneHeadJointID = DIALOG_VOICE_POSITION_NEEDS_UPDATE;
  149. }
  150.  
  151. ////////////////////////////////////////////////////////////////////////////
  152. void CDialogActorContext::BeginSession()
  153. {
  154.         DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::BeginSession: %s Now=%f 0x%p actorID=%d ",
  155.                     m_pSession->GetDebugName(), m_pSession->GetCurTime(), this, m_actorID);
  156.  
  157.         ResetState();
  158.  
  159.         IEntitySystem* pES = gEnv->pEntitySystem;
  160.         pES->AddEntityEventListener(m_entityID, ENTITY_EVENT_AI_DONE, this);
  161.         pES->AddEntityEventListener(m_entityID, ENTITY_EVENT_DONE, this);
  162.         pES->AddEntityEventListener(m_entityID, ENTITY_EVENT_RESET, this);
  163.  
  164.         switch (GetAIBehaviourMode())
  165.         {
  166.         case CDialogSession::eDIB_InterruptAlways:
  167.                 ExecuteAI(m_goalPipeID, "ACT_ANIM");
  168.                 break;
  169.         case CDialogSession::eDIB_InterruptMedium:
  170.                 ExecuteAI(m_goalPipeID, "ACT_DIALOG");
  171.                 break;
  172.         case CDialogSession::eDIB_InterruptNever:
  173.                 break;
  174.         }
  175.         m_bNeedsCancel = true;
  176. }
  177.  
  178. ////////////////////////////////////////////////////////////////////////////
  179. void CDialogActorContext::EndSession()
  180. {
  181.         CancelCurrent();
  182.         DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::EndSession: %s now=%f 0x%p actorID=%d ",
  183.                     m_pSession->GetDebugName(), m_pSession->GetCurTime(), this, m_actorID);
  184. }
  185.  
  186. ////////////////////////////////////////////////////////////////////////////
  187. bool CDialogActorContext::Update(float dt)
  188. {
  189.         if (IsAborted())
  190.                 return true;
  191.  
  192.         // FIXME: this should never happen, as we should get a notification before.
  193.         //        temp leave in for tracking down a bug [AlexL: 23/11/2006]
  194.         IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_entityID);
  195.         if (pEntity == 0)
  196.         {
  197.                 m_pIActor = 0;
  198.                 GameWarning("[DIALOG] CDialogActorContext::Update: %s Actor=%d (EntityId=%d) no longer existent.",
  199.                             m_pSession->GetDebugName(), m_actorID, m_entityID);
  200.                 AbortContext(true, CDialogSession::eAR_EntityDestroyed);
  201.                 return true;
  202.         }
  203.  
  204.         CDialogSession::AlertnessInterruptMode alertnessInterruptMode = m_pSession->GetAlertnessInterruptMode();
  205.         if (alertnessInterruptMode != CDialogSession::None)
  206.         {
  207.                 if (IAIObject* aiObject = pEntity->GetAI())
  208.                 {
  209.                         if (IAIActorProxy* aiActorProxy = aiObject->GetProxy())
  210.                         {
  211.                                 if (aiActorProxy->GetAlertnessState() >= alertnessInterruptMode)
  212.                                 {
  213.                                         AbortContext(true, CDialogSession::eAR_AIAborted);
  214.                                         return true;
  215.                                 }
  216.                         }
  217.                 }
  218.         }
  219.  
  220.         float now = m_pSession->GetCurTime();
  221.  
  222.         if (!CheckActorFlags(CDialogSession::eDACF_NoActorDeadAbort) && m_pIActor && m_pIActor->IsDead())
  223.         {
  224.                 if (!IsAborted())
  225.                 {
  226.                         DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Actor=%d (EntityId=%d) has died. Aborting.",
  227.                                     m_pSession->GetDebugName(), m_actorID, m_entityID);
  228.                         AbortContext(true, CDialogSession::eAR_ActorDead);
  229.                         return true;
  230.                 }
  231.         }
  232.  
  233.         if (m_bIsLocalPlayer)
  234.         {
  235.                 // when the local player is involved in the conversation do some special checks
  236.                 if (DoLocalPlayerChecks(dt) == false)
  237.                 {
  238.                         DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Abort from LocalPlayer.", m_pSession->GetDebugName());
  239.                         AbortContext(true, m_bIsAwareInRange == false ? CDialogSession::eAR_PlayerOutOfRange : CDialogSession::eAR_PlayerOutOfView);
  240.                         return true;
  241.                 }
  242.         }
  243.  
  244.         if (m_bAbortFromAI)
  245.         {
  246.                 m_bAbortFromAI = false;
  247.                 if (!IsAborted())
  248.                 {
  249.                         DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Abort from AI.", m_pSession->GetDebugName());
  250.                         AbortContext(true, CDialogSession::eAR_AIAborted);
  251.                         return true;
  252.                 }
  253.         }
  254.  
  255.         if (SessionAllowsLookAt())
  256.         {
  257.                 DoStickyLookAt();
  258.         }
  259.  
  260.         int loop = 0;
  261.         do
  262.         {
  263.                 // DiaLOG::Log("[DIALOG] DiaLOG::eAlways"CDialogActorContext::Update: %s now=%f actorId=%d loop=%d", m_pSession->GetDebugName(), now, m_actorID, loop);
  264.  
  265.                 bool bAdvance = false;
  266.                 switch (m_phase)
  267.                 {
  268.                 case eDAC_Idle:
  269.                         break;
  270.  
  271.                 case eDAC_NewLine:
  272.                         {
  273.                                 m_bHasScheduled = false;
  274.                                 m_lookAtTimeOut = LOOKAT_TIMEOUT;
  275.                                 m_animTimeOut = ANIM_TIMEOUT;
  276.                                 m_soundTimeOut = SOUND_TIMEOUT;  // wait one second until sound is timed out
  277.                                 m_bAnimScheduled = false;
  278.                                 m_bAnimStarted = false;
  279.                                 m_bSoundScheduled = false;
  280.                                 m_bSoundStarted = false;
  281.                                 m_soundLength = 0.0f;
  282.  
  283.                                 if (m_pCurLine->m_flagResetLookAt)
  284.                                 {
  285.                                         m_stickyLookAtActorID = CDialogScript::NO_ACTOR_ID;
  286.                                         m_lookAtActorID = CDialogScript::NO_ACTOR_ID;
  287.                                 }
  288.                                 // check if look-at sticky is set
  289.                                 else if (m_pCurLine->m_lookatActor != CDialogScript::NO_ACTOR_ID)
  290.                                 {
  291.                                         if (m_pCurLine->m_flagLookAtSticky == false)
  292.                                         {
  293.                                                 m_lookAtActorID = m_pCurLine->m_lookatActor;
  294.                                                 m_stickyLookAtActorID = CDialogScript::NO_ACTOR_ID;
  295.                                         }
  296.                                         else
  297.                                         {
  298.                                                 m_stickyLookAtActorID = m_pCurLine->m_lookatActor;
  299.                                                 m_lookAtActorID = CDialogScript::NO_ACTOR_ID;
  300.                                         }
  301.                                 }
  302.  
  303.                                 bAdvance = true;
  304.  
  305.                                 // handle the first sticky look-at here
  306.                                 if (SessionAllowsLookAt())
  307.                                 {
  308.                                         DoStickyLookAt();
  309.                                 }
  310.  
  311. #if 0   // test for immediate scheduling of next line while the current line is still playing
  312.                                 // maybe we're going to use some special delay TAGS like FORCE_NEXT, WAIT
  313.                                 if (m_pCurLine->m_delay <= -999.0f)
  314.                                 {
  315.                                         m_bHasScheduled = true;
  316.                                         m_pSession->ScheduleNextLine(0.0f);
  317.                                 }
  318. #endif
  319.                         }
  320.                         break;
  321.  
  322.                 case eDAC_LookAt:
  323.                         {
  324.                                 bool bWaitForLookAtFinish = true;
  325.                                 bAdvance = true;
  326.  
  327.                                 if (SessionAllowsLookAt() == false)
  328.                                 {
  329.                                         break;
  330.                                 }
  331.  
  332.                                 // Question: maybe do this although EP is requested
  333.                                 if (bWaitForLookAtFinish && m_lookAtActorID != CDialogScript::NO_ACTOR_ID && m_pCurLine->m_flagAGEP == false)
  334.                                 {
  335.                                         IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
  336.                                         IEntity* pLookAtEntity = m_pSession->GetActorEntity(m_lookAtActorID);
  337.                                         if (pActorEntity != 0)
  338.                                         {
  339.                                                 m_lookAtTimeOut -= dt;
  340.                                                 bool bTargetReached;
  341.                                                 //bool bSuccess = DoLookAt(pActorEntity, pLookAtEntity, bTargetReached);
  342.                                                 DoLookAt(pActorEntity, pLookAtEntity, bTargetReached);
  343.                                                 //DiaLOG::Log(DiaLOG::eDebugA, "[DIALOG] CDialogActorContext::Update: %s now=%f actorID=%d phase=eDAC_LookAt %d",
  344.                                                 //      m_pSession->GetDebugName(), now, m_actorID, bTargetReached);
  345.  
  346.                                                 if (/* bSuccess == false || */ bTargetReached || m_lookAtTimeOut <= 0.0f)
  347.                                                 {
  348.                                                         DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s now=%f actorID=%d phase=eDAC_LookAt %s",
  349.                                                                     m_pSession->GetDebugName(), now, m_actorID, bTargetReached ? "Target Reached" : "Timed Out");
  350.                                                         m_lookAtActorID = CDialogScript::NO_ACTOR_ID;
  351.                                                 }
  352.                                                 else
  353.                                                         bAdvance = false;
  354.                                         }
  355.                                 }
  356.                         }
  357.                         break;
  358.  
  359.                 case eDAC_Anim:
  360.                         {
  361.                                 bAdvance = true;
  362.                                 if (SessionAllowsLookAt() && m_lookAtActorID != CDialogScript::NO_ACTOR_ID) // maybe: don't do this when EP is requested [&& m_pCurLine->m_flagAGEP == false]
  363.                                 {
  364.                                         IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
  365.                                         IEntity* pLookAtEntity = m_pSession->GetActorEntity(m_lookAtActorID);
  366.                                         if (pActorEntity != 0)
  367.                                         {
  368.                                                 m_lookAtTimeOut -= dt;
  369.                                                 bool bTargetReached;
  370.                                                 //bool bSuccess = DoLookAt(pActorEntity, pLookAtEntity, bTargetReached);
  371.                                                 DoLookAt(pActorEntity, pLookAtEntity, bTargetReached);
  372.                                                 if (/* bSuccess == false || */ bTargetReached || m_lookAtTimeOut <= 0.0f)
  373.                                                 {
  374.                                                         DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s now=%f actorID=%d phase=eDAC_Anim %s",
  375.                                                                     m_pSession->GetDebugName(), now, m_actorID, bTargetReached ? "Target Reached" : "Timed Out");
  376.                                                         m_lookAtActorID = CDialogScript::NO_ACTOR_ID;
  377.                                                 }
  378.                                                 else
  379.                                                         bAdvance = false;
  380.                                         }
  381.                                 }
  382.                                 const bool bHasAnim = !m_pCurLine->m_anim.empty();
  383.                                 if (SessionAllowsAnim() && bHasAnim)
  384.                                 {
  385.                                         bAdvance = false;
  386.                                         if (!m_bAnimScheduled)
  387.                                         {
  388.                                                 m_bSoundStopsAnim = false; // whenever there is a new animation, no need for the still playing sound
  389.                                                                            // to stop the animation
  390.                                                 m_bAnimStarted = false;
  391.                                                 m_bAnimScheduled = true;
  392.                                                 // schedule animation
  393.                                                 IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
  394.                                                 if (pActorEntity)
  395.                                                         DoAnimAction(pActorEntity, m_pCurLine->m_anim, m_pCurLine->m_flagAGSignal, m_pCurLine->m_flagAGEP);
  396.                                                 else
  397.                                                         bAdvance = true;
  398.                                         }
  399.                                         else
  400.                                         {
  401.                                                 // we scheduled it already
  402.                                                 // wait until it starts or timeout
  403.                                                 m_animTimeOut -= dt;
  404.                                                 bAdvance = m_animTimeOut <= 0.0f || m_bAnimStarted;
  405.                                                 if (bAdvance)
  406.                                                 {
  407.                                                         DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Now=%f actorID=%d phase=eDAC_Anim %s",
  408.                                                                     m_pSession->GetDebugName(), now, m_actorID, m_bAnimStarted ? "Anim Started" : "Anim Timed Out");
  409.                                                 }
  410.                                         }
  411.                                 }
  412.                         }
  413.                         break;
  414.  
  415.                 case eDAC_ScheduleSoundPlay:
  416.                         {
  417.                                 bAdvance = true;
  418.                                 const bool bHasSound = m_pCurLine->m_audioID != INVALID_AUDIO_CONTROL_ID;
  419.                                 if (bHasSound)
  420.                                 {
  421.                                         if (m_bSoundScheduled == false)
  422.                                         {
  423.                                                 IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
  424.                                                 if (pActorEntity == 0)
  425.                                                         break;
  426.  
  427.                                                 IEntityAudioComponent* pActorAudioProxy = m_pSession->GetEntityAudioProxy(pActorEntity);
  428.  
  429.                                                 if (pActorAudioProxy == 0)
  430.                                                         break;
  431.  
  432.                                                 if (m_SpeechAuxProxy == INVALID_AUDIO_PROXY_ID)
  433.                                                 {
  434.                                                         m_SpeechAuxProxy = pActorAudioProxy->CreateAuxAudioProxy();
  435.                                                         pActorAudioProxy->AddAsListenerToAuxAudioProxy(m_SpeechAuxProxy, &CDialogActorContext::OnAudioTriggerFinished, eAudioRequestType_AudioCallbackManagerRequest, eAudioCallbackManagerRequestType_ReportFinishedTriggerInstance);
  436.                                                 }
  437.                                                 UpdateAuxProxyPosition();
  438.  
  439.                                                 SAudioCallBackInfo const callbackInfo(nullptr, (void*)CDialogActorContext::GetClassIdentifier(), reinterpret_cast<void*>(static_cast<intptr_t>(m_ContextID)), eAudioRequestFlags_PriorityNormal | eAudioRequestFlags_SyncFinishedCallback);
  440.                                                 if (!pActorAudioProxy->ExecuteTrigger(m_pCurLine->m_audioID, m_SpeechAuxProxy, callbackInfo))
  441.                                                 {
  442.                                                         m_bSoundStarted = false;
  443.                                                         m_bHasScheduled = false;
  444.                                                         m_pSession->ScheduleNextLine(2.0f);
  445.                                                 }
  446.                                                 else
  447.                                                 {
  448.                                                         m_bSoundStarted = true;
  449.                                                         m_bHasScheduled = true;
  450.  
  451.                                                         DiaLOG::Log(DiaLOG::eDebugA, "[DIALOG] CDialogActorContex::Update: %s Now=%f actorID=%d phase=eDAC_ScheduleSoundPlay: Starting '%s'",
  452.                                                                     m_pSession->GetDebugName(), now, m_actorID, "dialog trigger");
  453.                                                 }
  454.                                         }
  455.                                         else
  456.                                         {
  457.                                                 // sound has been scheduled
  458.                                                 // wait for sound start or timeout
  459.                                                 m_soundTimeOut -= dt;
  460.                                                 const bool bTimedOut = m_soundTimeOut <= 0.0f;
  461.                                                 bAdvance = bTimedOut || m_bSoundStarted;
  462.                                                 if (bAdvance)
  463.                                                 {
  464.                                                         if (bTimedOut)
  465.                                                                 StopSound(true); // unregister from sound as listener and free resource
  466.                                                         DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Now=%f actorID=%d phase=eDAC_ScheduleSoundPlay %s",
  467.                                                                     m_pSession->GetDebugName(), now, m_actorID, m_bSoundStarted ? "Sound Started" : "Sound Timed Out");
  468.                                                 }
  469.                                         }
  470.                                 }
  471.                         }
  472.                         break;
  473.  
  474.                 case eDAC_SoundFacial:
  475.                         {
  476.                                 bAdvance = true;
  477.                                 const bool bHasSound = m_pCurLine->m_audioID != INVALID_AUDIO_CONTROL_ID;
  478.                                 const bool bHasFacial = !m_pCurLine->m_facial.empty() || m_pCurLine->m_flagResetFacial;
  479.                                 if (bHasFacial)
  480.                                 {
  481.                                         IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
  482.                                         if (pActorEntity)
  483.                                                 DoFacialExpression(pActorEntity, m_pCurLine->m_facial, m_pCurLine->m_facialWeight, m_pCurLine->m_facialFadeTime);
  484.                                 }
  485.  
  486.                                 //hd-todo: re-add me, when we have a way to query the length of the audio-lines
  487.                                 //float delay = m_pCurLine->m_delay;
  488.                                 //if (bHasSound && m_bSoundStarted)
  489.                                 //{
  490.                                 //      if (m_soundLength <= 0.0f)
  491.                                 //      {
  492.                                 //              m_soundLength = cry_random(2.0f, 6.0f);
  493.                                 //              DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Now=%f actorID=%d phase=eDAC_SoundFacial Faking SoundTime to %f",
  494.                                 //                      m_pSession->GetDebugName(), now, m_actorID, m_soundLength);
  495.                                 //      }
  496.  
  497.                                 //      DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Now=%f actorID=%d phase=eDAC_SoundFacial Delay=%f SoundTime=%f",
  498.                                 //              m_pSession->GetDebugName(), now , m_actorID, delay, m_soundLength);
  499.                                 //      delay += m_soundLength;
  500.                                 //}
  501.  
  502.                                 //// schedule END
  503.                                 //if (delay < 0.0f)
  504.                                 //      delay = 0.0f;
  505.                                 //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
  506.                                 //                                                                                                                                                                       // 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)
  507.                                 //                                                                                                                                                                       // and that looks bad if subtitles are enabled. So we add this small delay here to try to minimize that situation.
  508.                                 //                                                                                                                                                                       // this is part of the workaround for some dialogs apparently never finishing in the engine side (rare).
  509.                                 //m_bHasScheduled = true;
  510.                         }
  511.                         break;
  512.  
  513.                 case eDAC_EndLine:
  514.                         bAdvance = true;
  515.                         if (m_bHasScheduled == false)
  516.                         {
  517.                                 m_bHasScheduled = true;
  518.                                 m_pSession->ScheduleNextLine(m_pCurLine->m_delay);
  519.                         }
  520.                         break;
  521.                 }
  522.  
  523.                 if (bAdvance)
  524.                 {
  525.                         AdvancePhase();
  526.                         dt = 0.0f;
  527.                         ++loop;
  528.                         assert(loop <= eDAC_EndLine + 1);
  529.                         if (loop > eDAC_EndLine + 1)
  530.                         {
  531.                                 DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::Update: %s Actor=%d InternalLoopCount=%d. Final Exit!",
  532.                                             m_pSession->GetDebugName(), m_actorID, loop);
  533.                         }
  534.                 }
  535.                 else
  536.                 {
  537.                         if (IsStillPlaying())
  538.                         {
  539.                                 UpdateAuxProxyPosition();
  540.                         }
  541.  
  542.                         break;
  543.                 }
  544.         }
  545.         while (true);
  546.  
  547.         return true;
  548. }
  549. ////////////////////////////////////////////////////////////////////////////
  550.  
  551. void CDialogActorContext::UpdateAuxProxyPosition()
  552. {
  553.         IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
  554.         if (pActorEntity == 0)
  555.                 return;
  556.  
  557.         IEntityAudioComponent* pActorAudioProxy = m_pSession->GetEntityAudioProxy(pActorEntity);
  558.         if (pActorAudioProxy == 0)
  559.                 return;
  560.  
  561.         ICharacterInstance* const pCharacter = pActorEntity->GetCharacter(0);
  562.  
  563.         //cache some IDs
  564.         if (m_VoiceAttachmentIndex == DIALOG_VOICE_POSITION_NEEDS_UPDATE && pCharacter)
  565.         {
  566.                 const IAttachmentManager* pAttachmentManager = pCharacter->GetIAttachmentManager();
  567.                 if (pAttachmentManager)
  568.                 {
  569.                         m_VoiceAttachmentIndex = pAttachmentManager->GetIndexByName("voice");  //First prio: get the "voice" attachment position
  570.  
  571.                         if (m_VoiceAttachmentIndex == -1)
  572.                         {
  573.                                 // There's no attachment so let's try to find the head bone.
  574.                                 IDefaultSkeleton& rIDefaultSkeleton = pCharacter->GetIDefaultSkeleton();
  575.                                 m_BoneHeadJointID = rIDefaultSkeleton.GetJointIDByName("Bip01 Head");  //Second prio: use the Bip01 head bone position
  576.                                 if (m_BoneHeadJointID == -1)
  577.                                 {
  578.                                         // Has it been named differently?
  579.                                         m_BoneHeadJointID = rIDefaultSkeleton.GetJointIDByName("def_head");  //third prio: use the Bip01 head bone position
  580.                                 }
  581.                         }
  582.                 }
  583.         }
  584.  
  585.         Matrix34 tmHead;
  586.  
  587.         //try to get a position close to the "mouth" of our actor
  588.         if (m_VoiceAttachmentIndex > 0 && pCharacter)
  589.         {
  590.                 const IAttachmentManager* pAttachmentManager = pCharacter->GetIAttachmentManager();
  591.                 const IAttachment* pAttachment = pAttachmentManager->GetInterfaceByIndex(m_VoiceAttachmentIndex);
  592.                 if (pAttachment)
  593.                 {
  594.                         tmHead = Matrix34(pAttachment->GetAttModelRelative());
  595.                 }
  596.         }
  597.         else if (m_BoneHeadJointID > 0 && pCharacter)
  598.         {
  599.                 // re-query SkeletonPose to prevent crash on removed Character
  600.                 if (ISkeletonPose* const pSkeletonPose = pCharacter->GetISkeletonPose())
  601.                 {
  602.                         tmHead = Matrix34(pSkeletonPose->GetAbsJointByID(m_BoneHeadJointID));
  603.                 }
  604.         }
  605.         else
  606.         {
  607.                 //last-resort: if we could not find a head attachment point or a head-bone: Lets just assume the head is 1.80m above the feet
  608.                 tmHead = Matrix34(IDENTITY, Vec3(0.0f, 1.80f, 0.0f));
  609.         }
  610.  
  611.         pActorAudioProxy->SetAuxAudioProxyOffset(tmHead, m_SpeechAuxProxy);
  612. }
  613.  
  614. ////////////////////////////////////////////////////////////////////////////
  615. static const char* PhaseNames[] =
  616. {
  617.         "eDAC_Idle",
  618.         "eDAC_NewLine",
  619.         "eDAC_LookAt",
  620.         "eDAC_Anim",
  621.         "eDAC_ScheduleSoundPlay",
  622.         "eDAC_SoundFacial",
  623.         "eDAC_EndLine"
  624. };
  625.  
  626. ////////////////////////////////////////////////////////////////////////////
  627. void CDialogActorContext::AdvancePhase()
  628. {
  629.         const int oldPhase = m_phase;
  630.         ++m_phase;
  631.         if (m_phase > eDAC_EndLine)
  632.                 m_phase = eDAC_Idle;
  633.  
  634.         DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext:AdvancePhase: %s ActorID=%d %s->%s",
  635.                     m_pSession->GetDebugName(), m_actorID, PhaseNames[oldPhase], PhaseNames[m_phase]);
  636. }
  637.  
  638. ////////////////////////////////////////////////////////////////////////////
  639. bool CDialogActorContext::PlayLine(const CDialogScript::SScriptLine* pLine)
  640. {
  641.         m_pCurLine = pLine;
  642.         m_phase = eDAC_NewLine;
  643.         return true;
  644. }
  645.  
  646. ////////////////////////////////////////////////////////////////////////////
  647. bool CDialogActorContext::DoAnimAction(IEntity* pEntity, const string& action, bool bIsSignal, bool bUseEP)
  648. {
  649.         m_bAnimUseEP = bUseEP;
  650.         m_bAnimUseAGSignal = bIsSignal;
  651.  
  652.         if (m_bAnimUseEP == false)
  653.         {
  654.                 const bool bSuccess = DoAnimActionAG(pEntity, action.c_str());
  655.                 return bSuccess;
  656.         }
  657.         else
  658.         {
  659.                 const bool bSuccess = DoAnimActionEP(pEntity, action.c_str());
  660.                 return bSuccess;
  661.         }
  662.         return false; // make some compilers happy
  663. }
  664.  
  665. ////////////////////////////////////////////////////////////////////////////
  666. bool CDialogActorContext::DoAnimActionAG(IEntity* pEntity, const char* sAction)
  667. {
  668.         IActor* pActor = gEnv->pGameFramework->GetIActorSystem()->GetActor(m_entityID);
  669.         if (pActor)
  670.         {
  671.                 m_pAGState = pActor->GetAnimationGraphState();
  672.                 if (m_pAGState)
  673.                 {
  674.                         m_pAGState->AddListener("dsctx", this);
  675.                         if (m_bAnimUseAGSignal)
  676.                         {
  677.                                 DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext:DoAnimAction: %s ActorID=%d Setting signal to '%s'",
  678.                                             m_pSession->GetDebugName(), m_actorID, sAction);
  679.                                 m_pAGState->SetInput("Signal", sAction, &m_queryID);
  680.                         }
  681.                         else
  682.                         {
  683.                                 DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext:DoAnimAction: %s ActorID=%d Setting input to '%s'",
  684.                                             m_pSession->GetDebugName(), m_actorID, sAction);
  685.                                 m_pAGState->SetInput("Action", sAction, &m_queryID);
  686.                         }
  687.                 }
  688.         }
  689.         return true;
  690. }
  691.  
  692. ////////////////////////////////////////////////////////////////////////////
  693. bool CDialogActorContext::DoAnimActionEP(IEntity* pEntity, const char* sAction)
  694. {
  695.         IAIObject* pAI = pEntity->GetAI();
  696.         if (pAI == 0)
  697.                 return false;
  698.  
  699.         IPipeUser* pPipeUser = pAI->CastToIPipeUser();
  700.         if (!pPipeUser)
  701.         {
  702.                 return false;
  703.         }
  704.  
  705.         Vec3 pos = pEntity->GetWorldPos();
  706.         Vec3 dir = pAI->GetMoveDir();
  707.  
  708.         // EP Direction is either lookat direction or forward direction
  709.         CDialogScript::TActorID lookAt = m_pCurLine->m_lookatActor;
  710.         if (lookAt != CDialogScript::NO_ACTOR_ID)
  711.         {
  712.                 IEntity* pLookAtEntity = m_pSession->GetActorEntity(lookAt);
  713.                 if (pLookAtEntity != 0)
  714.                 {
  715.                         dir = pLookAtEntity->GetWorldPos();
  716.                         dir -= pos;
  717.                         dir.z = 0;
  718.                         dir.NormalizeSafe(pAI->GetMoveDir());
  719.                 }
  720.         }
  721.         pPipeUser->SetRefPointPos(pos, dir);
  722.  
  723.         static const Vec3 startRadius(0.1f, 0.1f, 0.1f);
  724.         static const float dirTolerance = 5.f;
  725.         static const float targetRadius = 0.05f;
  726.  
  727.         IAISignalExtraData* pData = gEnv->pAISystem->CreateSignalExtraData();
  728.         pData->iValue2 = m_bAnimUseAGSignal ? 1 : 0;
  729.         pData->SetObjectName(sAction);
  730.         pData->point = startRadius;
  731.         pData->fValue = dirTolerance;
  732.         pData->point2.x = targetRadius;
  733.  
  734.         const bool ok = ExecuteAI(m_exPosAnimPipeID, "ACT_ANIMEX", pData);
  735.         return ok;
  736. }
  737.  
  738. ////////////////////////////////////////////////////////////////////////////
  739. bool CDialogActorContext::DoFacialExpression(IEntity* pEntity, const string& expression, float weight, float fadeTime)
  740. {
  741.         ICharacterInstance* pCharacter = pEntity->GetCharacter(0);
  742.         if (!pCharacter)
  743.                 return false;
  744.         IFacialInstance* pFacialInstance = pCharacter->GetFacialInstance();
  745.         if (!pFacialInstance)
  746.                 return false;
  747.         IFacialModel* pFacialModel = pFacialInstance->GetFacialModel();
  748.         if (!pFacialModel)
  749.                 return false;
  750.         IFacialEffectorsLibrary* pLibrary = pFacialModel->GetLibrary();
  751.         if (!pLibrary)
  752.                 return false;
  753.  
  754.         IFacialEffector* pEffector = 0;
  755.         if (!expression.empty())
  756.         {
  757.                 pEffector = pLibrary->Find(expression.c_str());
  758.                 if (!pEffector)
  759.                 {
  760.                         GameWarning("[DIALOG] CDialogActorContext::DoFacialExpression: %s Cannot find '%s' for Entity '%s'", m_pSession->GetDebugName(), expression.c_str(), pEntity->GetName());
  761.                         return false;
  762.                 }
  763.         }
  764.  
  765.         if (m_currentEffectorChannelID != INVALID_FACIAL_CHANNEL_ID)
  766.         {
  767.                 // we fade out with the same fadeTime as fade in
  768.                 pFacialInstance->StopEffectorChannel(m_currentEffectorChannelID, fadeTime);
  769.                 m_currentEffectorChannelID = INVALID_FACIAL_CHANNEL_ID;
  770.         }
  771.  
  772.         if (pEffector)
  773.         {
  774.                 m_currentEffectorChannelID = pFacialInstance->StartEffectorChannel(pEffector, weight, fadeTime); // facial instance wants ms
  775.         }
  776.         return true;
  777. }
  778.  
  779. ////////////////////////////////////////////////////////////////////////////
  780. bool CDialogActorContext::DoLookAt(IEntity* pEntity, IEntity* pLookAtEntity, bool& bReachedTarget)
  781. {
  782.         bReachedTarget = false;
  783.         IAIObject* pAI = pEntity->GetAI();
  784.         if (pAI == 0)
  785.                 return false;
  786.  
  787.         IAIActor* pAIActor = pAI->CastToIAIActor();
  788.         if (!pAIActor)
  789.         {
  790.                 return false;
  791.         }
  792.  
  793.         if (pLookAtEntity == 0)
  794.         {
  795.                 pAIActor->ResetLookAt();
  796.                 bReachedTarget = true;
  797.                 m_bLookAtNeedsReset = false;
  798.         }
  799.         else
  800.         {
  801.                 IAIObject* pTargetAI = pLookAtEntity->GetAI();
  802.                 Vec3 pos = pTargetAI ? pTargetAI->GetPos() : pLookAtEntity->GetWorldPos();
  803.                 bReachedTarget = pAIActor->SetLookAtPointPos(pos, true);
  804.                 m_bLookAtNeedsReset = true;
  805.         }
  806.  
  807.         return true;
  808. }
  809.  
  810. ////////////////////////////////////////////////////////////////////////////
  811. void CDialogActorContext::DoStickyLookAt()
  812. {
  813.         if (m_stickyLookAtActorID != CDialogScript::NO_ACTOR_ID)
  814.         {
  815.                 IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
  816.                 IEntity* pLookAtEntity = m_pSession->GetActorEntity(m_stickyLookAtActorID);
  817.                 if (pActorEntity != 0)
  818.                 {
  819.                         bool bTargetReached;
  820.                         DoLookAt(pActorEntity, pLookAtEntity, bTargetReached);
  821.                 }
  822.         }
  823. }
  824.  
  825. ////////////////////////////////////////////////////////////////////////////
  826. void CDialogActorContext::CancelCurrent(bool bResetStates)
  827. {
  828.         if (!m_bNeedsCancel)
  829.                 return;
  830.  
  831.         assert(m_bInCancel == false);
  832.         if (m_bInCancel == true)
  833.                 return;
  834.         m_bInCancel = true;
  835.  
  836.         // remove from AG
  837.         if (m_pAGState != 0)
  838.         {
  839.                 m_pAGState->RemoveListener(this);
  840.                 if (bResetStates)
  841.                 {
  842.                         ResetAGState();
  843.                 }
  844.                 m_pAGState = 0;
  845.         }
  846.         m_queryID = 0;
  847.         m_bAnimStarted = false;
  848.  
  849.         // reset lookat
  850.         IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_entityID);
  851.         if (pEntity)
  852.         {
  853.                 IAIObject* pAI = pEntity->GetAI();
  854.                 if (pAI)
  855.                 {
  856.                         IAIActor* pAIActor = pAI->CastToIAIActor();
  857.                         if (pAIActor)
  858.                         {
  859.                                 if (m_bLookAtNeedsReset)
  860.                                 {
  861.                                         pAIActor->ResetLookAt();
  862.                                         m_bLookAtNeedsReset = false;
  863.                                 }
  864.  
  865.                                 IPipeUser* pPipeUser = pAI->CastToIPipeUser();
  866.                                 if (pPipeUser)
  867.                                 {
  868.                                         if (m_goalPipeID > 0)
  869.                                         {
  870.                                                 if (GetAIBehaviourMode() == CDialogSession::eDIB_InterruptMedium)
  871.                                                 {
  872.                                                         int dummyPipe = 0;
  873.                                                         ExecuteAI(dummyPipe, "ACT_DIALOG_OVER", 0, false);
  874.                                                 }
  875.                                                 pPipeUser->UnRegisterGoalPipeListener(this, m_goalPipeID);
  876.                                                 pPipeUser->RemoveSubPipe(m_goalPipeID, true);
  877.                                                 m_goalPipeID = 0;
  878.                                         }
  879.                                         if (m_exPosAnimPipeID > 0)
  880.                                         {
  881.                                                 pPipeUser->UnRegisterGoalPipeListener(this, m_exPosAnimPipeID);
  882.                                                 pPipeUser->CancelSubPipe(m_exPosAnimPipeID);
  883.                                                 pPipeUser->RemoveSubPipe(m_exPosAnimPipeID, false);
  884.                                                 m_exPosAnimPipeID = 0;
  885.                                         }
  886.                                 }
  887.                         }
  888.                 }
  889.         }
  890.  
  891.         // facial expression is always reset
  892.         // if (bResetStates)
  893.         {
  894.                 // Reset Facial Expression
  895.                 IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
  896.                 if (pActorEntity)
  897.                 {
  898.                         DoFacialExpression(pActorEntity, "", 1.0f, 0.0f);
  899.                 }
  900.         }
  901.  
  902.         // should we stop the current sound?
  903.         // we don't stop the sound if the actor aborts and has eDACF_NoAbortSound set.
  904.         // if actor died (entity destroyed) though, sound is stopped anyway
  905.         const bool bDontStopSound = (IsAborted() == false && CheckActorFlags(CDialogSession::eDACF_NoAbortSound))
  906.                                     || (IsAborted()
  907.                                         && CheckActorFlags(CDialogSession::eDACF_NoAbortSound)
  908.                                         && GetAbortReason() != CDialogSession::eAR_ActorDead
  909.                                         && GetAbortReason() != CDialogSession::eAR_EntityDestroyed);
  910.  
  911.         if (bDontStopSound == false)
  912.         {
  913.                 // stop sound (this also forces m_soundId to be INVALID_SOUNDID) and markes Context as non-playing!
  914.                 // e.g. IsStillPlaying will then return false
  915.                 // we explicitly stop the sound in the d'tor if we don't take this path here
  916.                 StopSound();
  917.         }
  918.  
  919.         IEntitySystem* pES = gEnv->pEntitySystem;
  920.         pES->RemoveEntityEventListener(m_entityID, ENTITY_EVENT_AI_DONE, this);
  921.         pES->RemoveEntityEventListener(m_entityID, ENTITY_EVENT_DONE, this);
  922.         pES->RemoveEntityEventListener(m_entityID, ENTITY_EVENT_RESET, this);
  923.  
  924.         m_phase = eDAC_Idle;
  925.  
  926.         m_bInCancel = false;
  927.         m_bNeedsCancel = false;
  928. }
  929.  
  930. ////////////////////////////////////////////////////////////////////////////
  931. void CDialogActorContext::ResetAGState()
  932. {
  933.         if (!m_pAGState)
  934.                 return;
  935.  
  936.         if (m_bAnimUseAGSignal)
  937.         {
  938.                 if (!m_bAnimStarted)
  939.                         m_pAGState->SetInput("Signal", "none");
  940.         }
  941.         else
  942.                 m_pAGState->SetInput("Action", "idle");
  943. }
  944.  
  945. ////////////////////////////////////////////////////////////////////////////
  946. void CDialogActorContext::AbortContext(bool bCancel, CDialogSession::EAbortReason reason)
  947. {
  948.         DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext:AbortContext: %s actorID=%d ", m_pSession->GetDebugName(), m_actorID);
  949.         m_phase = eDAC_Aborted;
  950.         m_abortReason = reason;
  951.         if (bCancel)
  952.                 CancelCurrent();
  953.         // need to set it again, as CancelCurrent might have changed them
  954.         m_phase = eDAC_Aborted;
  955.         m_abortReason = reason;
  956. }
  957.  
  958. ////////////////////////////////////////////////////////////////////////////
  959. bool CDialogActorContext::IsAborted() const
  960. {
  961.         return m_phase == eDAC_Aborted;
  962. }
  963.  
  964. // IAnimationGraphStateListener
  965. ////////////////////////////////////////////////////////////////////////////
  966. void CDialogActorContext::SetOutput(const char* output, const char* value)
  967. {
  968. }
  969.  
  970. ////////////////////////////////////////////////////////////////////////////
  971. void CDialogActorContext::QueryComplete(TAnimationGraphQueryID queryID, bool succeeded)
  972. {
  973.         IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_entityID);
  974.         if (!pEntity)
  975.                 return;
  976.  
  977.         DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext:QueryComplete: %s actorID=%d m_queryID=%d queryID=%d",
  978.                     m_pSession->GetDebugName(), m_actorID, m_queryID, queryID);
  979.  
  980.         if (queryID != m_queryID)
  981.                 return;
  982.  
  983.         if (succeeded || (m_bAnimStarted && !m_bAnimUseAGSignal))
  984.         {
  985.                 if (m_bAnimStarted == false)
  986.                 {
  987.                         m_bAnimStarted = true;
  988.                         if (m_bAnimUseAGSignal)
  989.                         {
  990.                                 m_pAGState->QueryLeaveState(&m_queryID);
  991.                         }
  992.                         else
  993.                         {
  994.                                 m_pAGState->QueryChangeInput("Action", &m_queryID);
  995.                         }
  996.                 }
  997.                 else
  998.                 {
  999.                         if (m_pAGState)
  1000.                         {
  1001.                                 m_pAGState->RemoveListener(this);
  1002.                                 m_pAGState = 0;
  1003.                                 m_queryID = 0;
  1004.                                 m_bAnimStarted = false;
  1005.                         }
  1006.                 }
  1007.         }
  1008.         else
  1009.         {
  1010.                 ;
  1011.         }
  1012. }
  1013.  
  1014. ////////////////////////////////////////////////////////////////////////////
  1015. void CDialogActorContext::DestroyedState(IAnimationGraphState*)
  1016. {
  1017.         m_pAGState = 0;
  1018.         m_queryID = 0;
  1019.         m_bAnimStarted = false;
  1020. }
  1021.  
  1022. // ~IAnimationGraphStateListener
  1023.  
  1024. ////////////////////////////////////////////////////////////////////////////
  1025. bool CDialogActorContext::ExecuteAI(int& goalPipeID, const char* signalText, IAISignalExtraData* pExtraData, bool bRegisterAsListener)
  1026. {
  1027.         IEntitySystem* pSystem = gEnv->pEntitySystem;
  1028.         IEntity* pEntity = pSystem->GetEntity(m_entityID);
  1029.         if (pEntity == 0)
  1030.                 return false;
  1031.  
  1032.         IAIObject* pAI = pEntity->GetAI();
  1033.         if (pAI == 0)
  1034.                 return false;
  1035.  
  1036.         unsigned short nType = pAI->GetAIType();
  1037.         if (nType != AIOBJECT_ACTOR)
  1038.         {
  1039.                 if (nType == AIOBJECT_PLAYER)
  1040.                 {
  1041.                         goalPipeID = -1;
  1042.  
  1043.                         // not needed for player
  1044.                         // pAI->SetSignal( 10, signalText, pEntity, NULL ); // 10 means this signal must be sent (but sent[!], not set)
  1045.                         // even if the same signal is already present in the queue
  1046.                         return true;
  1047.                 }
  1048.  
  1049.                 // invalid AIObject type
  1050.                 return false;
  1051.         }
  1052.  
  1053.         IPipeUser* pPipeUser = pAI->CastToIPipeUser();
  1054.         if (pPipeUser)
  1055.         {
  1056.                 if (goalPipeID > 0)
  1057.                 {
  1058.                         pPipeUser->RemoveSubPipe(goalPipeID, true);
  1059.                         pPipeUser->UnRegisterGoalPipeListener(this, goalPipeID);
  1060.                         goalPipeID = 0;
  1061.                 }
  1062.         }
  1063.  
  1064.         goalPipeID = gEnv->pAISystem->AllocGoalPipeId();
  1065.         if (pExtraData == 0)
  1066.                 pExtraData = gEnv->pAISystem->CreateSignalExtraData();
  1067.         pExtraData->iValue = goalPipeID;
  1068.  
  1069.         if (pPipeUser && bRegisterAsListener)
  1070.         {
  1071.                 pPipeUser->RegisterGoalPipeListener(this, goalPipeID, "CDialogActorContext::ExecuteAI");
  1072.         }
  1073.  
  1074.         IAIActor* pAIActor = CastToIAIActorSafe(pAI);
  1075.         if (pAIActor)
  1076.                 pAIActor->SetSignal(10, signalText, pEntity, pExtraData);   // 10 means this signal must be sent (but sent[!], not set)
  1077.         // even if the same signal is already present in the queue
  1078.         return true;
  1079. }
  1080.  
  1081. ////////////////////////////////////////////////////////////////////////////
  1082. void CDialogActorContext::StopSound(bool bUnregisterOnly)
  1083. {
  1084.         if (bUnregisterOnly)
  1085.         {
  1086.                 return;  //nothing to do here, because we dont registered for anything.
  1087.         }
  1088.  
  1089.         // Stop Sound
  1090.         if (IsStillPlaying())
  1091.         {
  1092.                 IEntity* pActorEntity = m_pSession->GetActorEntity(m_actorID);
  1093.                 if (pActorEntity == 0)
  1094.                         return;
  1095.  
  1096.                 IEntityAudioComponent* pActorAudioProxy = m_pSession->GetEntityAudioProxy(pActorEntity);
  1097.                 if (pActorAudioProxy == 0)
  1098.                         return;
  1099.  
  1100.                 pActorAudioProxy->StopTrigger(m_pCurLine->m_audioID, m_SpeechAuxProxy);
  1101.         }
  1102. }
  1103.  
  1104. bool CDialogActorContext::DoLocalPlayerChecks(const float dt)
  1105. {
  1106.         // don't check this every frame, but only every .2 secs
  1107.         m_checkPlayerTimeOut -= dt;
  1108.         if (m_checkPlayerTimeOut <= 0.0f)
  1109.         {
  1110.                 do // a dummy loop to use break
  1111.                 {
  1112.                         float awareDistance;
  1113.                         float awareDistanceSq;
  1114.                         float awareAngle;
  1115.                         m_pSession->GetPlayerAwarenessValues(awareDistance, awareAngle);
  1116.                         awareDistanceSq = awareDistance * awareDistance;
  1117.  
  1118.                         m_checkPlayerTimeOut = PLAYER_CHECKTIME;
  1119.                         const float spotAngleCos = cos_tpl(DEG2RAD(awareAngle));
  1120.  
  1121.                         const CDialogSession::TActorContextMap& contextMap = m_pSession->GetAllContexts();
  1122.                         if (contextMap.size() == 1 && contextMap.begin()->first == m_actorID)
  1123.                         {
  1124.                                 m_bIsAware = true;
  1125.                                 break;
  1126.                         }
  1127.  
  1128.                         // early out, when we don't have to do any checks
  1129.                         if (awareDistance <= 0.0f && awareAngle <= 0.0f)
  1130.                         {
  1131.                                 m_bIsAware = true;
  1132.                                 break;
  1133.                         }
  1134.  
  1135.                         IEntity* pThisEntity = m_pSession->GetActorEntity(m_actorID);
  1136.                         if (!pThisEntity)
  1137.                         {
  1138.                                 assert(false);
  1139.                                 m_bIsAware = true;
  1140.                                 break;
  1141.                         }
  1142.                         IMovementController* pMC = (m_pIActor != NULL) ? m_pIActor->GetMovementController() : NULL;
  1143.                         if (!pMC)
  1144.                         {
  1145.                                 assert(false);
  1146.                                 m_bIsAware = true;
  1147.                                 break;
  1148.                         }
  1149.                         SMovementState moveState;
  1150.                         pMC->GetMovementState(moveState);
  1151.                         Vec3 viewPos = moveState.eyePosition;
  1152.                         Vec3 viewDir = moveState.eyeDirection;
  1153.                         viewDir.z = 0.0f;
  1154.                         viewDir.NormalizeSafe();
  1155.  
  1156.                         // check the player's position
  1157.                         // check the player's view direction
  1158.                         AABB groupBounds;
  1159.                         groupBounds.Reset();
  1160.  
  1161.                         CDialogSession::TActorContextMap::const_iterator iter = contextMap.begin();
  1162.                         CDialogScript::SActorSet lookingAt = 0;
  1163.                         while (iter != contextMap.end())
  1164.                         {
  1165.                                 if (iter->first != m_actorID)
  1166.                                 {
  1167.                                         IEntity* pActorEntity = m_pSession->GetActorEntity(iter->first);
  1168.                                         if (pActorEntity)
  1169.                                         {
  1170.                                                 Vec3 vEntityPos = pActorEntity->GetWorldPos();
  1171.                                                 AABB worldBounds;
  1172.                                                 pActorEntity->GetWorldBounds(worldBounds);
  1173.                                                 groupBounds.Add(worldBounds);
  1174.                                                 // calc if we look at it somehow
  1175.                                                 Vec3 vEntityDir = vEntityPos - viewPos;
  1176.                                                 vEntityDir.z = 0.0f;
  1177.                                                 vEntityDir.NormalizeSafe();
  1178.                                                 if (viewDir.IsUnit() && vEntityDir.IsUnit())
  1179.                                                 {
  1180.                                                         const float dot = clamp_tpl(viewDir.Dot(vEntityDir), -1.0f, +1.0f); // clamping should not be needed
  1181.                                                         if (spotAngleCos <= dot)
  1182.                                                                 lookingAt.SetActor(iter->first);
  1183.                                                         DiaLOG::Log(DiaLOG::eDebugC, "Angle to actor %d is %f deg", iter->first, RAD2DEG(acos_tpl(dot)));
  1184.                                                 }
  1185.                                         }
  1186.                                 }
  1187.                                 ++iter;
  1188.                         }
  1189.  
  1190.                         const float distanceSq = pThisEntity->GetWorldPos().GetSquaredDistance(groupBounds.GetCenter());
  1191.                         CCamera& camera = gEnv->pSystem->GetViewCamera();
  1192.                         const bool bIsInAABB = camera.IsAABBVisible_F(groupBounds);
  1193.                         const bool bIsInRange = distanceSq <= awareDistanceSq;
  1194.                         const bool bIsLooking = contextMap.empty() || lookingAt.NumActors() > 0;
  1195.                         m_bIsAwareLooking = awareAngle <= 0.0f || (bIsInAABB || bIsLooking);
  1196.                         m_bIsAwareInRange = awareDistance <= 0.0f || bIsInRange;
  1197.                         m_bIsAware = m_bIsAwareLooking && m_bIsAwareInRange;
  1198.  
  1199.                         DiaLOG::Log(DiaLOG::eDebugB, "[DIALOG] LPC: %s awDist=%f awAng=%f AABBVis=%d IsLooking=%d InRange=%d [Distance=%f LookingActors=%d] Final=%saware",
  1200.                                     m_pSession->GetDebugName(), awareDistance, awareAngle, bIsInAABB, bIsLooking, bIsInRange, sqrt_tpl(distanceSq), lookingAt.NumActors(), m_bIsAware ? "" : "not ");
  1201.  
  1202.                 }
  1203.                 while (false);
  1204.         }
  1205.  
  1206.         if (m_bIsAware)
  1207.         {
  1208.                 m_playerAwareTimeOut = m_pSession->GetPlayerAwarenessGraceTime();
  1209.         }
  1210.         else
  1211.         {
  1212.                 m_playerAwareTimeOut -= dt;
  1213.                 if (m_playerAwareTimeOut <= 0)
  1214.                 {
  1215.                         return false;
  1216.                 }
  1217.         }
  1218.  
  1219.         return true;
  1220. }
  1221.  
  1222. ////////////////////////////////////////////////////////////////////////////
  1223. bool CDialogActorContext::IsStillPlaying() const
  1224. {
  1225.         return m_bSoundStarted && m_pCurLine && m_pCurLine->m_audioID != INVALID_AUDIO_CONTROL_ID; //m_soundID != INVALID_SOUNDID && m_bSoundStarted;
  1226. }
  1227.  
  1228. // IEntityEventListener
  1229. void CDialogActorContext::OnEntityEvent(IEntity* pEntity, SEntityEvent& event)
  1230. {
  1231.         switch (event.event)
  1232.         {
  1233.         case ENTITY_EVENT_RESET:
  1234.         case ENTITY_EVENT_DONE:
  1235.                 AbortContext(true, CDialogSession::eAR_EntityDestroyed);
  1236.                 break;
  1237.         default:
  1238.                 break;
  1239.         }
  1240. }
  1241.  
  1242. // ~IEntityEventListener
  1243.  
  1244. const char* EventName(EGoalPipeEvent event)
  1245. {
  1246.         switch (event)
  1247.         {
  1248.         case ePN_Deselected:
  1249.                 return "ePN_Deselected";
  1250.         case ePN_Removed:
  1251.                 return "ePN_Removed";
  1252.         case ePN_Finished:
  1253.                 return "ePN_Finished";
  1254.         case ePN_Suspended:
  1255.                 return "ePN_Suspended";
  1256.         case ePN_Resumed:
  1257.                 return "ePN_Resumed";
  1258.         case ePN_AnimStarted:
  1259.                 return "ePN_AnimStarted";
  1260.         case ePN_RefPointMoved:
  1261.                 return "ePN_RefPointMoved";
  1262.         default:
  1263.                 return "UNKNOWN GOAL PIPEEVENT";
  1264.         }
  1265. }
  1266.  
  1267. // IGoalPipeListener
  1268. ////////////////////////////////////////////////////////////////////////////
  1269. void CDialogActorContext::OnGoalPipeEvent(IPipeUser* pPipeUser, EGoalPipeEvent event, int goalPipeId, bool& unregisterListenerAfterEvent)
  1270. {
  1271.         if (m_goalPipeID != goalPipeId && m_exPosAnimPipeID != goalPipeId)
  1272.                 return;
  1273.  
  1274. #if 1
  1275.         DiaLOG::Log(DiaLOG::eAlways, "[DIALOG] CDialogActorContext::OnGoalPipeEvent: %s 0x%p actorID=%d goalPipe=%d m_goalPipeID=%d m_exPosAnimPipeID=%d event=%s",
  1276.                     m_pSession->GetDebugName(), this, m_actorID, goalPipeId, m_goalPipeID, m_exPosAnimPipeID, EventName(event));
  1277. #endif
  1278.  
  1279.         switch (event)
  1280.         {
  1281.         case ePN_Deselected:
  1282.         case ePN_Removed:
  1283.                 if (CheckActorFlags(CDialogSession::eDACF_NoAIAbort) == false)
  1284.                 {
  1285.                         if (m_goalPipeID == goalPipeId)
  1286.                                 m_bAbortFromAI = true;
  1287.                 }
  1288.                 break;
  1289.         case ePN_AnimStarted:
  1290.                 m_bAnimStarted = true;
  1291.                 break;
  1292.         default:
  1293.                 break;
  1294.         }
  1295. }
  1296. // ~IGoalPipeListener
  1297.  
  1298. ////////////////////////////////////////////////////////////////////////////
  1299. void CDialogActorContext::GetMemoryUsage(ICrySizer* pSizer) const
  1300. {
  1301.         pSizer->AddObject(m_pSession);
  1302.         pSizer->AddObject(m_pCurLine);
  1303.         pSizer->AddObject(m_pIActor);
  1304.         pSizer->AddObject(m_pAGState);
  1305. }
  1306.  
  1307. ////////////////////////////////////////////////////////////////////////////
  1308. void CDialogActorContext::OnAudioTriggerFinished(SAudioRequestInfo const* const pAudioRequestInfo)
  1309. {
  1310.         CDialogActorContext* dialogContext = GetDialogActorContextByAudioCallbackData(pAudioRequestInfo);
  1311.         if (dialogContext)
  1312.         {
  1313.                 //hd-todo: for now we schedule the next line, as soon as the current line has finished. replace this with the old manual delay system, as soon as we have a way to figure out the length of the audio-lines
  1314.                 dialogContext->m_pSession->ScheduleNextLine(0.2f);
  1315.                 //mark as finished
  1316.                 dialogContext->m_bSoundStarted = false;
  1317.         }
  1318. }
  1319.  
  1320. ////////////////////////////////////////////////////////////////////////////
  1321. CDialogActorContext* CDialogActorContext::GetDialogActorContextByAudioCallbackData(SAudioRequestInfo const* const pAudioRequestInfo)
  1322. {
  1323.         if (pAudioRequestInfo->pUserDataOwner && pAudioRequestInfo->pUserData == CDialogActorContext::GetClassIdentifier())
  1324.         {
  1325.                 EntityId const nContextID = static_cast<EntityId>(reinterpret_cast<UINT_PTR>(pAudioRequestInfo->pUserDataOwner));
  1326.                 CDialogSystem* pDS = CCryAction::GetCryAction()->GetDialogSystem();
  1327.                 return pDS->GetActiveSessionActorContext(nContextID);
  1328.         }
  1329.         return 0;
  1330. }
  1331.  
downloadDialogActorContext.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top