diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index f56f68b780..091b851261 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -104,7 +104,7 @@ namespace MWBase ///< Return the number of deaths for actors with the given ID. /// Check if \a observer is potentially aware of \a ptr. Does not do a line of sight check! - virtual bool awarenessCheck(const MWWorld::Ptr& ptr, const MWWorld::Ptr& observer) = 0; + virtual bool awarenessCheck(const MWWorld::Ptr& ptr, const MWWorld::Ptr& observer, bool useCache = true) = 0; /// Makes \a ptr fight \a target. Also shouts a combat taunt. virtual void startCombat( diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index fd70671e85..04f4e12b65 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -410,6 +410,7 @@ namespace MWMechanics void Actors::updateActor(const MWWorld::Ptr& ptr, float duration) const { + ptr.getClass().getCreatureStats(ptr).updateAwareness(duration); // magic effects adjustMagicEffects(ptr, duration); diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 91d2a9bbb8..ac59de0426 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -433,7 +433,7 @@ namespace MWMechanics ESM::Position enemyPos = enemy.getRefData().getPosition(); if (isTargetMagicallyHidden(enemy) - && !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(enemy, actor)) + && !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(enemy, actor, false)) { return false; } diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index 461db45133..1dbbddd218 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -42,7 +42,7 @@ namespace MWMechanics return true; if (isTargetMagicallyHidden(target) - && !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(target, actor)) + && !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(target, actor, false)) return false; if (target.getClass().getCreatureStats(target).isDead()) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 41af96a630..0a14d46097 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -686,4 +686,24 @@ namespace MWMechanics { return mSummonGraveyard; } + + void CreatureStats::updateAwareness(float duration) + { + mAwarenessTimer += duration; + // Only reroll for awareness every 5 seconds + if (mAwarenessTimer >= 5.f) + { + mAwarenessTimer = 0.f; + mAwarenessRoll = -1; + } + } + + int CreatureStats::getAwarenessRoll() + { + if (mAwarenessRoll >= 0) + return mAwarenessRoll; + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); + mAwarenessRoll = Misc::Rng::roll0to99(prng); + return mAwarenessRoll; + } } diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 02312385d7..aa46e9504f 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -90,6 +90,9 @@ namespace MWMechanics // This may be necessary when the creature is in an inactive cell. std::vector mSummonGraveyard; + float mAwarenessTimer = 0.f; + int mAwarenessRoll = -1; + protected: std::string mAttackType; int mLevel = 0; @@ -300,6 +303,9 @@ namespace MWMechanics void setTeleported(bool v) { mTeleported = v; } const std::map& getAttributes() const { return mAttributes; } + + void updateAwareness(float duration); + int getAwarenessRoll(); }; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 4cfe1027c5..df6ba53e35 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1609,7 +1609,7 @@ namespace MWMechanics commitCrime(player, victim, MWBase::MechanicsManager::OT_Murder); } - bool MechanicsManager::awarenessCheck(const MWWorld::Ptr& ptr, const MWWorld::Ptr& observer) + bool MechanicsManager::awarenessCheck(const MWWorld::Ptr& ptr, const MWWorld::Ptr& observer, bool useCache) { if (observer.getClass().getCreatureStats(observer).isDead() || !observer.getRefData().isEnabled()) return false; @@ -1676,8 +1676,10 @@ namespace MWMechanics } float target = x - y; + if (useCache) + return observerStats.getAwarenessRoll() >= target; auto& prng = MWBase::Environment::get().getWorld()->getPrng(); - return (Misc::Rng::roll0to99(prng) >= target); + return Misc::Rng::roll0to99(prng) >= target; } void MechanicsManager::startCombat( diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 247bae1a5b..11ef21852c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -102,7 +102,7 @@ namespace MWMechanics ///< Perform a persuasion action on NPC /// Check if \a observer is potentially aware of \a ptr. Does not do a line of sight check! - bool awarenessCheck(const MWWorld::Ptr& ptr, const MWWorld::Ptr& observer) override; + bool awarenessCheck(const MWWorld::Ptr& ptr, const MWWorld::Ptr& observer, bool useCache = true) override; /// Makes \a ptr fight \a target. Also shouts a combat taunt. void startCombat(