From cec55119cab14b874adf6e4a7cdd6b975629935b Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 14 Dec 2018 18:29:56 +0300 Subject: [PATCH] Move idle dialogue playback from AiWander (bug #4594) --- apps/openmw/mwmechanics/actors.cpp | 31 ++++++++++++++++++++++++++ apps/openmw/mwmechanics/actors.hpp | 2 ++ apps/openmw/mwmechanics/aiwander.cpp | 33 ---------------------------- apps/openmw/mwmechanics/aiwander.hpp | 1 - 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 4166ece11..191b02809 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include "../mwworld/esmstore.hpp" @@ -348,6 +349,33 @@ namespace MWMechanics } } + void Actors::playIdleDialogue(const MWWorld::Ptr& actor) + { + if (!actor.getClass().isActor() || actor == getPlayer() || !MWBase::Environment::get().getSoundManager()->sayDone(actor)) + return; + + const CreatureStats &stats = actor.getClass().getCreatureStats(actor); + if (stats.getAiSetting(CreatureStats::AI_Hello).getModified() == 0) + return; + + const MWMechanics::AiSequence& seq = stats.getAiSequence(); + if (seq.isInCombat() || seq.hasPackage(AiPackage::TypeIdFollow) || seq.hasPackage(AiPackage::TypeIdEscort)) + return; + + const osg::Vec3f playerPos(getPlayer().getRefData().getPosition().asVec3()); + const osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); + MWBase::World* world = MWBase::Environment::get().getWorld(); + if (world->isSwimming(actor) || (playerPos - actorPos).length2() >= 3000 * 3000) + return; + + // Our implementation is not FPS-dependent unlike Morrowind's so it needs to be recalibrated. + // We chose to use the chance MW would have when run at 60 FPS with the default value of the GMST. + const float delta = MWBase::Environment::get().getFrameDuration() * 6.f; + static const float fVoiceIdleOdds = world->getStore().get().find("fVoiceIdleOdds")->mValue.getFloat(); + if (Misc::Rng::rollProbability() * 10000.f < fVoiceIdleOdds * delta && world->getLOS(getPlayer(), actor)) + MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); + } + void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map >& cachedAllies, bool againstPlayer) { // No combat for totally static creatures @@ -1408,7 +1436,10 @@ namespace MWMechanics { CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); if (isConscious(iter->first)) + { stats.getAiSequence().execute(iter->first, *ctrl, duration); + playIdleDialogue(iter->first); + } } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 61879c432..79e35a8d1 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -102,6 +102,8 @@ namespace MWMechanics */ void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map >& cachedAllies, bool againstPlayer); + void playIdleDialogue(const MWWorld::Ptr& actor); + void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor, MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance); diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index d2a57c354..05465c6b0 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -8,7 +8,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -167,8 +166,6 @@ namespace MWMechanics doPerFrameActionsForState(actor, duration, storage); - playIdleDialogueRandomly(actor); - float& lastReaction = storage.mReaction; lastReaction += duration; if (AI_REACTION_TIME <= lastReaction) @@ -492,36 +489,6 @@ namespace MWMechanics } } - void AiWander::playIdleDialogueRandomly(const MWWorld::Ptr& actor) - { - int hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified(); - if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor) - && MWBase::Environment::get().getSoundManager()->sayDone(actor)) - { - MWWorld::Ptr player = getPlayer(); - - static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() - .get().find("fVoiceIdleOdds")->mValue.getFloat(); - - float roll = Misc::Rng::rollProbability() * 10000.0f; - - // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds - // due to the roll being an integer. - // Our implementation does not have these issues, so needs to be recalibrated. We chose to - // use the chance MW would have when run at 60 FPS with the default value of the GMST for calibration. - float x = fVoiceIdleOdds * 0.6f * (MWBase::Environment::get().getFrameDuration() / 0.1f); - - // Only say Idle voices when player is in LOS - // A bit counterintuitive, likely vanilla did this to reduce the appearance of - // voices going through walls? - const osg::Vec3f playerPos(player.getRefData().getPosition().asVec3()); - const osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); - if (roll < x && (playerPos - actorPos).length2() < 3000 * 3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead - && MWBase::Environment::get().getWorld()->getLOS(player, actor)) - MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); - } - } - void AiWander::playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage) { // Play a random voice greeting if the player gets too close diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index bba6f7113..d586bb0bc 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -138,7 +138,6 @@ namespace MWMechanics void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage); - void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage);