diff --git a/src/logic/CameraController.cpp b/src/logic/CameraController.cpp index 4f97d137..45061aae 100644 --- a/src/logic/CameraController.cpp +++ b/src/logic/CameraController.cpp @@ -50,6 +50,10 @@ Logic::CameraController::CameraController(World::WorldInstance& world, Handle::E m_CameraSettings.firstPersonCameraSettings.pitch = 0; m_CameraSettings.firstPersonCameraSettings.yaw = 0; + m_CameraSettings.dialogueCameraSettings.dialogueShotCounter = 0; + m_CameraSettings.dialogueCameraSettings.dialogueShotLimit = 2; + m_CameraSettings.dialogueCameraSettings.dontShowHeroChance = 4; + m_KeyframeDuration = 1.0f; setupKeybinds(); } @@ -238,153 +242,262 @@ void Logic::CameraController::switchModeActions(ECameraMode mode) } } -void Logic::CameraController::onUpdateExplicit(float deltaTime) -{ - if (m_CameraMode == ECameraMode::ThirdPerson) { - VobTypes::NpcVobInformation player = VobTypes::asNpcVob(m_World, m_World.getScriptEngine().getPlayerEntity()); - - if (player.isValid()) - { - const float verticalFactor = std::sin(m_CameraSettings.thirdPersonCameraSettings.cameraElevation); - const float horizontalFactor = std::cos(m_CameraSettings.thirdPersonCameraSettings.cameraElevation); - // TODO use movestate direction instead? (swimming not tested) - Math::Matrix pTrans = player.playerController->getEntityTransformFacing(); - Math::float3 pdir; - - // If player is currently using a mob check if camera should be locked - // If so, use last known position and finish rotating to it - VobTypes::MobVobInformation mob = VobTypes::asMobVob(m_World, player.playerController->getUsedMob()); - if (!mob.isValid()) - { - pdir = pTrans.Forward(); - } - else if (!mob.mobController->isCameraLocked()) - { - pdir = pTrans.Forward(); - m_savedPdir = pdir; - } - else - pdir = m_savedPdir; - - const float interpolationFraction = std::min(CAMERA_SMOOTHING * deltaTime, 1.0f); - m_CameraSettings.thirdPersonCameraSettings.currentOffsetDirection = Math::float3::lerp(m_CameraSettings.thirdPersonCameraSettings.currentOffsetDirection, - pdir, - interpolationFraction); - - pdir = m_CameraSettings.thirdPersonCameraSettings.currentOffsetDirection; - - - Components::AnimationComponent& anim = Components::Actions::initComponent(player.world->getComponentAllocator(), player.entity); - const auto& playerSize = anim.getAnimHandler().getMeshLib().getBBoxMax(); - const auto& width = playerSize.x; - const auto& height = playerSize.y; - const auto& length = playerSize.z; - float playerDimension = (width + height + length) / 3; - - const auto& playerCenter = pTrans.Translation(); - - const Math::float3 up = Math::float3(0.0f, 1.0f, 0.0f); +void Logic::CameraController::nextDialogueShot() { + VobTypes::NpcVobInformation player = VobTypes::asNpcVob(m_World, + m_World.getScriptEngine().getPlayerEntity()); + + EDialogueShotType nextShot = m_DialogueShotType; + bool playerTalking = m_dialogueTargetName == player.playerController->getScriptInstance().name[0]; + + // Rule: Use close-up and neutral only after at least two fulls or shoulders + // Rule: Only full or over-the-shoulder shot for PC_Hero + if (playerTalking || m_CameraSettings.dialogueCameraSettings.dialogueShotCounter <= + m_CameraSettings.dialogueCameraSettings.dialogueShotLimit) { + // Rule: don't always cut to PC_Hero when they speak. Leave chance for camera to stay on target NPC + m_dontShowHero = rand() % m_CameraSettings.dialogueCameraSettings.dontShowHeroChance != 0; + if (m_CameraSettings.dialogueCameraSettings.dialogueShotCounter == 0 || + m_CameraSettings.dialogueCameraSettings.dialogueShotCounter > + m_CameraSettings.dialogueCameraSettings.dialogueShotLimit) { + + // Only choose from first two (Full and OverTheShoulder) + nextShot = (EDialogueShotType) (rand() % 2); + } + } else { + // Rule: A close-up is the only possible option after a neutral shot + if (m_DialogueShotType == EDialogueShotType::Neutral && rand() % 4 == 0) + nextShot = EDialogueShotType::CloseUp; + // Rule: No shot should come after a close-up + else if (m_DialogueShotType != EDialogueShotType::CloseUp) + nextShot = (EDialogueShotType) (rand() % 4); + } - float angle = m_CameraSettings.thirdPersonCameraSettings.pitch; - const auto& elevation = m_CameraSettings.thirdPersonCameraSettings.cameraElevation; - auto actualCameraAngle = Math::radiansToDegree(angle + elevation); + m_DialogueShotType = nextShot; + m_CameraSettings.dialogueCameraSettings.dialogueShotCounter++; +} - auto rotationAxisDir = pTrans.Left(); +void Logic::CameraController::updateDialogueCamera() { + VobTypes::NpcVobInformation npc_vob = VobTypes::getVobFromScriptHandle(m_World, m_dialogueTargetNPCHandle); + + VobTypes::NpcVobInformation player = VobTypes::asNpcVob(m_World, + m_World.getScriptEngine().getPlayerEntity()); + + Math::Matrix pTrans = player.playerController->getEntityTransform(); + Math::Matrix npcTrans = npc_vob.playerController->getEntityTransform(); + Math::Matrix otherTrans, targetTrans; + + // Can be either 1 or -1, flip the camera based on which character is speaking + float reverseShotModifier; + + if (m_dialogueTargetName == player.playerController->getScriptInstance().name[0] && m_dontShowHero) { + // The PC_Hero is talking + otherTrans = npcTrans; + targetTrans = pTrans; + reverseShotModifier = -1.0; + } else { + // The other character is talking + otherTrans = pTrans; + targetTrans = npcTrans; + reverseShotModifier = 1.0; + } - // cardinalPoint around which the camera will rotate vertically - auto cameraRotationCenter = playerCenter; - const auto& zoomExponent = m_CameraSettings.thirdPersonCameraSettings.zoomExponent; - float zoom = std::exp(zoomExponent * playerDimension); + // Pull further back based on distance between characters + float distance = (pTrans.Translation() - npcTrans.Translation()).length(); + + switch (m_DialogueShotType) { + case EDialogueShotType::Full: { + m_ViewMatrix = targetTrans.RotatedAroundLine(targetTrans.Translation(), targetTrans.Right(), 0); + m_ViewMatrix *= Math::Matrix::CreateTranslation(-1.5 * reverseShotModifier, 0.5, distance + 0.3); + Math::Matrix targetLookAt = targetTrans * Math::Matrix::CreateTranslation(0.0, 0.6, 0.0); + m_ViewMatrix = Math::Matrix::CreateLookAt(m_ViewMatrix.Translation(), targetLookAt.Translation(), + otherTrans.Up()); + m_ViewMatrix = m_ViewMatrix.Invert(); + m_ViewMatrix = m_ViewMatrix.RotatedAroundLine(m_ViewMatrix.Translation(), m_ViewMatrix.Up(), + -0.3 * reverseShotModifier); + } + break; + case EDialogueShotType::OverTheShoulder: { + m_ViewMatrix = otherTrans.RotatedAroundLine(otherTrans.Translation(), otherTrans.Right(), 0.2); + m_ViewMatrix *= Math::Matrix::CreateTranslation(0.5 * reverseShotModifier, 0.8, -0.6); + m_ViewMatrix = m_ViewMatrix.RotatedAroundLine(m_ViewMatrix.Translation(), otherTrans.Up(), + -0.55 * reverseShotModifier); + } + break; + case EDialogueShotType::Neutral: { + m_ViewMatrix = npcTrans.RotatedAroundLine(npcTrans.Translation(), npcTrans.Up(), Math::PI / 2); + m_ViewMatrix *= Math::Matrix::CreateTranslation((distance / 2) * -1, 0.5, distance * -1); + } + break; + case EDialogueShotType::CloseUp: { + m_ViewMatrix = targetTrans.RotatedAroundLine(targetTrans.Translation(), targetTrans.Up(), Math::PI); + m_ViewMatrix *= Math::Matrix::CreateTranslation(-0.3 * reverseShotModifier, 0.8, -1.5); + m_ViewMatrix = m_ViewMatrix.RotatedAroundLine(otherTrans.Translation(), otherTrans.Right(), 0.2); + m_ViewMatrix = m_ViewMatrix.RotatedAroundLine(m_ViewMatrix.Translation(), otherTrans.Up(), + 0.2 * reverseShotModifier); + } + break; + } +} - Math::float3 newLookAt = cameraRotationCenter + verticalFactor * zoom * up; - Math::float3 newCamPos = newLookAt - horizontalFactor * zoom * pdir; +void Logic::CameraController::updateThirdPersonCamera(float deltaTime) { + VobTypes::NpcVobInformation player = VobTypes::asNpcVob(m_World, m_World.getScriptEngine().getPlayerEntity()); + + if (player.isValid()) { + const float verticalFactor = std::sin(m_CameraSettings.thirdPersonCameraSettings.cameraElevation); + const float horizontalFactor = std::cos(m_CameraSettings.thirdPersonCameraSettings.cameraElevation); + // TODO use movestate direction instead? (swimming not tested) + Math::Matrix pTrans = player.playerController->getEntityTransformFacing(); + Math::float3 pdir; + + // If player is currently using a mob check if camera should be locked + // If so, use last known position and finish rotating to it + VobTypes::MobVobInformation mob = VobTypes::asMobVob(m_World, player.playerController->getUsedMob()); + if (!mob.isValid()) { + pdir = pTrans.Forward(); + } else if (!mob.mobController->isCameraLocked()) { + pdir = pTrans.Forward(); + m_savedPdir = pdir; + } else + pdir = m_savedPdir; + + const float interpolationFraction = std::min(CAMERA_SMOOTHING * deltaTime, 1.0f); + m_CameraSettings.thirdPersonCameraSettings.currentOffsetDirection = Math::float3::lerp( + m_CameraSettings.thirdPersonCameraSettings.currentOffsetDirection, + pdir, + interpolationFraction); + + pdir = m_CameraSettings.thirdPersonCameraSettings.currentOffsetDirection; + + + Components::AnimationComponent &anim = Components::Actions::initComponent( + player.world->getComponentAllocator(), player.entity); + const auto &playerSize = anim.getAnimHandler().getMeshLib().getBBoxMax(); + const auto &width = playerSize.x; + const auto &height = playerSize.y; + const auto &length = playerSize.z; + float playerDimension = (width + height + length) / 3; + + const auto &playerCenter = pTrans.Translation(); + + const Math::float3 up = Math::float3(0.0f, 1.0f, 0.0f); + + float angle = m_CameraSettings.thirdPersonCameraSettings.pitch; + const auto &elevation = m_CameraSettings.thirdPersonCameraSettings.cameraElevation; + auto actualCameraAngle = Math::radiansToDegree(angle + elevation); + + auto rotationAxisDir = pTrans.Left(); + + // cardinalPoint around which the camera will rotate vertically + auto cameraRotationCenter = playerCenter; + const auto &zoomExponent = m_CameraSettings.thirdPersonCameraSettings.zoomExponent; + float zoom = std::exp(zoomExponent * playerDimension); + + Math::float3 newLookAt = cameraRotationCenter + verticalFactor * zoom * up; + Math::float3 newCamPos = newLookAt - horizontalFactor * zoom * pdir; + + auto &deltaPhi = m_CameraSettings.thirdPersonCameraSettings.deltaPhi; + for (auto p : {&newLookAt, &newCamPos}) { + *p = Math::Matrix::rotatedPointAroundLine(*p, cameraRotationCenter, rotationAxisDir, angle); + // rotate camera around y-axis + // *p = Math::Matrix::rotatedPointAroundLine(*pc, pTrans.Translation(), pTrans.Up(), deltaPhi); + } - auto& deltaPhi = m_CameraSettings.thirdPersonCameraSettings.deltaPhi; - for (auto p : {&newLookAt, &newCamPos}) - { - *p = Math::Matrix::rotatedPointAroundLine(*p, cameraRotationCenter, rotationAxisDir, angle); - // rotate camera around y-axis - // *p = Math::Matrix::rotatedPointAroundLine(*pc, pTrans.Translation(), pTrans.Up(), deltaPhi); - } + Math::float3 oldCamPos = getEntityTransform().Translation(); + Math::float3 intCamPos = Math::float3::lerp(oldCamPos, newCamPos, interpolationFraction); - Math::float3 oldCamPos = getEntityTransform().Translation(); - Math::float3 intCamPos = Math::float3::lerp(oldCamPos, newCamPos, interpolationFraction); + const Math::float3 &oldLookAt = m_CameraSettings.thirdPersonCameraSettings.currentLookAt; + m_CameraSettings.thirdPersonCameraSettings.currentLookAt = Math::float3::lerp(oldLookAt, newLookAt, + interpolationFraction); - const Math::float3& oldLookAt = m_CameraSettings.thirdPersonCameraSettings.currentLookAt; - m_CameraSettings.thirdPersonCameraSettings.currentLookAt = Math::float3::lerp(oldLookAt, newLookAt, - interpolationFraction); + m_ViewMatrix = Math::Matrix::CreateLookAt(intCamPos, + m_CameraSettings.thirdPersonCameraSettings.currentLookAt, + up); - m_ViewMatrix = Math::Matrix::CreateLookAt(intCamPos, - m_CameraSettings.thirdPersonCameraSettings.currentLookAt, - up); + m_ViewMatrix = m_ViewMatrix.Invert(); + } +} - setEntityTransform(m_ViewMatrix.Invert()); - } +void Logic::CameraController::updateFirstPersonCamera() +{ + VobTypes::NpcVobInformation player = VobTypes::asNpcVob(m_World, + m_World.getScriptEngine().getPlayerEntity()); + + if (player.isValid()) { + auto &settings = m_CameraSettings.firstPersonCameraSettings; + Math::Matrix pTrans = player.playerController->getEntityTransform(); + // TODO find position of player's head + m_ViewMatrix = pTrans.RotatedAroundLine(pTrans.Translation(), pTrans.Right(), settings.pitch); } +} - if (m_Active) { - switch (m_CameraMode) { - case ECameraMode::FirstPerson: { - VobTypes::NpcVobInformation player = VobTypes::asNpcVob(m_World, - m_World.getScriptEngine().getPlayerEntity()); - - if (player.isValid()) { - auto &settings = m_CameraSettings.firstPersonCameraSettings; - Math::Matrix pTrans = player.playerController->getEntityTransform(); - // TODO find position of player's head - m_ViewMatrix = pTrans.RotatedAroundLine(pTrans.Translation(), pTrans.Right(), settings.pitch); - setEntityTransform(m_ViewMatrix); - } - } - break; +void Logic::CameraController::updateFreeCamera(float deltaTime) +{ + auto &settings = m_CameraSettings.floatingCameraSettings; - case ECameraMode::Free: { - auto &settings = m_CameraSettings.floatingCameraSettings; + // Get forward/right vector + std::tie(settings.forward, settings.right) = getDirectionVectors(settings.yaw, settings.pitch); + settings.up = settings.right.cross(settings.forward); - // Get forward/right vector - std::tie(settings.forward, settings.right) = getDirectionVectors(settings.yaw, settings.pitch); - settings.up = settings.right.cross(settings.forward); + settings.forward *= deltaTime * 100.0f; + settings.right *= deltaTime * 100.0f; - settings.forward *= deltaTime * 100.0f; - settings.right *= deltaTime * 100.0f; + m_ViewMatrix = Math::Matrix::CreateView(settings.position, + settings.yaw, + settings.pitch); - m_ViewMatrix = Math::Matrix::CreateView(settings.position, - settings.yaw, - settings.pitch); + m_ViewMatrix = m_ViewMatrix.Invert(); +} - setEntityTransform(m_ViewMatrix.Invert()); - } - break; +void Logic::CameraController::updateViewerCamera() +{ + auto &settings = m_CameraSettings.viewerCameraSettings; + + // getDirectionVectors only returns 2 of 3 direction vectors + std::tie(settings.in, settings.right) = getDirectionVectors(settings.yaw, settings.pitch); + settings.up = settings.right.cross(settings.in); - case ECameraMode::Viewer: { - auto &settings = m_CameraSettings.viewerCameraSettings; + m_ViewMatrix = Math::Matrix::CreateLookAt( + settings.lookAt + settings.zoom * settings.in, settings.lookAt, settings.up); + m_ViewMatrix = m_ViewMatrix.Invert(); +} - // getDirectionVectors only returns 2 of 3 direction vectors - std::tie(settings.in, settings.right) = getDirectionVectors(settings.yaw, settings.pitch); - settings.up = settings.right.cross(settings.in); +void Logic::CameraController::updateKeyedAnimationCamera(float deltaTime) { + if (m_Keyframes.empty() && m_KeyframeActive == -1.0f) { + return; + } - m_ViewMatrix = Math::Matrix::CreateLookAt( - settings.lookAt + settings.zoom * settings.in, settings.lookAt, settings.up); - setEntityTransform(m_ViewMatrix.Invert()); - } - break; - - case ECameraMode::KeyedAnimation: { - if (!m_Keyframes.empty() && m_KeyframeActive != -1.0f) { - std::pair poslookat = updateKeyframedPlay(deltaTime); - m_ViewMatrix = Math::Matrix::CreateLookAt( - poslookat.first, poslookat.first + poslookat.second, Math::float3(0, 1, 0)); - setEntityTransform(m_ViewMatrix.Invert()); - } - } - break; + std::pair poslookat = updateKeyframedPlay(deltaTime); + m_ViewMatrix = Math::Matrix::CreateLookAt( + poslookat.first, poslookat.first + poslookat.second, Math::float3(0, 1, 0)); + m_ViewMatrix = m_ViewMatrix.Invert(); +} - case ECameraMode::Static: { - //TODO add handling there? - } - break; - } +void Logic::CameraController::onUpdateExplicit(float deltaTime) +{ + Math::Matrix nextViewMatrix; + switch (m_CameraMode) { + case ECameraMode::Dialogue: + updateDialogueCamera(); + break; + case ECameraMode::ThirdPerson: + updateThirdPersonCamera(deltaTime); + break; + case ECameraMode::FirstPerson: + updateFirstPersonCamera(); + break; + case ECameraMode::Free: + updateFreeCamera(deltaTime); + break; + case ECameraMode::Viewer: + updateViewerCamera(); + break; + case ECameraMode::KeyedAnimation: + updateKeyedAnimationCamera(deltaTime); + break; + case ECameraMode::Static: + //TODO add handling there? + break; } + setEntityTransform(m_ViewMatrix); } std::pair Logic::CameraController::getDirectionVectors(float yaw, float pitch) @@ -412,6 +525,7 @@ void Logic::CameraController::setTransforms(const Math::float3& position, float void Logic::CameraController::setCameraMode(Logic::CameraController::ECameraMode mode) { + m_savedCameraMode = m_CameraMode; m_CameraMode = mode; switchModeActions(mode); switch (mode) @@ -429,6 +543,9 @@ void Logic::CameraController::setCameraMode(Logic::CameraController::ECameraMode case ECameraMode::ThirdPerson: Engine::Input::setMouseLock(true); break; + case ECameraMode::Dialogue: + Engine::Input::setMouseLock(true); + break; case ECameraMode::KeyedAnimation: m_KeyframeActive = 0.0f; Engine::Input::setMouseLock(false); diff --git a/src/logic/CameraController.h b/src/logic/CameraController.h index 7e2c7797..680274e2 100644 --- a/src/logic/CameraController.h +++ b/src/logic/CameraController.h @@ -13,12 +13,21 @@ namespace Logic { ThirdPerson, FirstPerson, + Dialogue, Free, Viewer, // name is open to change Static, KeyedAnimation, }; + enum class EDialogueShotType + { + Full, + OverTheShoulder, + Neutral, + CloseUp, + }; + struct CameraSettings { /** @@ -93,6 +102,16 @@ namespace Logic Math::float3 up, right, in; float yaw, pitch, zoom; } viewerCameraSettings; + + struct + { + // Counter used for shot progression during dialog + int dialogueShotCounter; + // The counter limit after which more shot types can be used + int dialogueShotLimit; + // Likelihood of the camera staying on target NPC when PC_Hero speaks + int dontShowHeroChance; + } dialogueCameraSettings; }; /** @@ -123,11 +142,77 @@ namespace Logic return m_CameraMode; } + /** + * Sets camera mode to mode before last setCameraMode() call + */ + void restoreCameraMode() + { + setCameraMode(m_savedCameraMode); + } + + /** + * Reset m_neutralShotCounter to 0 in order to begin camera progression from start + */ + void resetCameraProgression() {m_CameraSettings.dialogueCameraSettings.dialogueShotCounter = 0;} + + /** + * Sets the name of the character that is speaking + * @param target name of NPC + */ + void setDialogueTargetName(std::string &target) + { + m_dialogueTargetName = target; + } + + /** + * Sets the NPC handle of the character the player is talking to + * @param npc NPCHandle of NPC + */ + void setDialogueTargetNPCHandle(Daedalus::GameState::NpcHandle npc) + { + m_dialogueTargetNPCHandle = npc; + } + + /** + * Randomly chooses one of the dialogue shot types to cut to + */ + void nextDialogueShot(); + /** * @brief Sets whether this controller should read input */ void setActive(bool active); + /** + * Updates the camera according to dialogue camera rules + */ + void updateDialogueCamera(); + + /** + * Updates the camera according to third person camera rules + */ + void updateThirdPersonCamera(float deltaTime); + + /** + * Updates the camera according to first person camera rules + */ + void updateFirstPersonCamera(); + + /** + * Updates the camera according to free camera rules + */ + void updateFreeCamera(float deltaTime); + /** + * Updates the camera according to viewer camera rules + */ + + void updateViewerCamera(); + + /** + * Updates the camera according to keyed animation camera rules + */ + void updateKeyedAnimationCamera(float deltaTime); + /** * Sets the entity to follow in the first/third person camera modes */ @@ -224,6 +309,31 @@ namespace Logic */ ECameraMode m_CameraMode; + /** + * What camera angle is used during dialogue + */ + EDialogueShotType m_DialogueShotType; + + /** + * Tracks whether camera should show PC_hero when talking, or other character + */ + bool m_dontShowHero; + + /** + * Remember camera mode (i.e. for dialogue) to restore it later + */ + ECameraMode m_savedCameraMode; + + /** + * Name of NPC the dialogue camera should point at + */ + std::string m_dialogueTargetName; + + /** + * Handle of NPC the camera might point at during dialogue + */ + Daedalus::GameState::NpcHandle m_dialogueTargetNPCHandle; + /** * Entity this is attached to */ diff --git a/src/logic/DialogManager.cpp b/src/logic/DialogManager.cpp index 1b6bb71a..9cbba6a1 100644 --- a/src/logic/DialogManager.cpp +++ b/src/logic/DialogManager.cpp @@ -3,6 +3,7 @@ // #include "DialogManager.h" +#include "CameraController.h" #include #include #include @@ -268,6 +269,8 @@ void DialogManager::performChoice(size_t choice) { m_Interaction.currentInfo = infoHandle; } + + m_World.getCameraController()->resetCameraProgression(); } void DialogManager::assessTalk(NpcHandle target) @@ -325,6 +328,9 @@ void DialogManager::endDialog() if (targetVob.isValid()) targetVob.playerController->getEM().onMessage(msg, playerVob.entity); + + m_World.getCameraController()->restoreCameraMode(); + m_World.getEngine()->getSession().enableActionBindings(true); } bool DialogManager::init() @@ -519,6 +525,10 @@ void DialogManager::startDialog(NpcHandle npc, NpcHandle player) m_Interaction.target = npc; m_ProcessInfos = true; m_DialogActive = true; + m_World.getCameraController()->setCameraMode(CameraController::ECameraMode::Dialogue); + m_World.getCameraController()->setDialogueTargetNPCHandle(npc); + m_World.getCameraController()->nextDialogueShot(); m_World.getEngine()->getHud().setGameplayHudVisible(false); + m_World.getEngine()->getSession().enableActionBindings(false); updateChoices(npc); } diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 2510a653..593c4a26 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -5,6 +5,7 @@ #include "PlayerController.h" #include "ItemController.h" #include "MobController.h" +#include "CameraController.h" #include #include #include "visuals/ModelVisual.h" @@ -1000,17 +1001,21 @@ bool PlayerController::EV_Conversation(std::shared_ptrsetDialogueTargetName(characterName); + m_World.getCameraController()->nextDialogueShot(); subtitleBox.setScaling(0.0); subtitleBox.setGrowDirection(+1.0f); } + + // Play the random dialog gesture + startDialogAnimation(); + // Play sound of this conv-message + message.soundTicket = m_World.getAudioWorld().playSound(message.name, getEntityTransform().Translation(), DEFAULT_CHARACTER_SOUND_RANGE); } if (message.status == ConversationMessage::Status::PLAYING)