Merge branch 'unawarenesstraining' into 'master'

Cache awareness rolls for 5 seconds to make sneaking easier

See merge request OpenMW/openmw!4434
This commit is contained in:
Evil Eye 2025-08-02 10:10:52 +00:00
commit 09b6fbf6f7
8 changed files with 35 additions and 6 deletions

View File

@ -104,7 +104,7 @@ namespace MWBase
///< Return the number of deaths for actors with the given ID. ///< 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! /// 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. /// Makes \a ptr fight \a target. Also shouts a combat taunt.
virtual void startCombat( virtual void startCombat(

View File

@ -410,6 +410,7 @@ namespace MWMechanics
void Actors::updateActor(const MWWorld::Ptr& ptr, float duration) const void Actors::updateActor(const MWWorld::Ptr& ptr, float duration) const
{ {
ptr.getClass().getCreatureStats(ptr).updateAwareness(duration);
// magic effects // magic effects
adjustMagicEffects(ptr, duration); adjustMagicEffects(ptr, duration);

View File

@ -433,7 +433,7 @@ namespace MWMechanics
ESM::Position enemyPos = enemy.getRefData().getPosition(); ESM::Position enemyPos = enemy.getRefData().getPosition();
if (isTargetMagicallyHidden(enemy) if (isTargetMagicallyHidden(enemy)
&& !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(enemy, actor)) && !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(enemy, actor, false))
{ {
return false; return false;
} }

View File

@ -42,7 +42,7 @@ namespace MWMechanics
return true; return true;
if (isTargetMagicallyHidden(target) if (isTargetMagicallyHidden(target)
&& !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(target, actor)) && !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(target, actor, false))
return false; return false;
if (target.getClass().getCreatureStats(target).isDead()) if (target.getClass().getCreatureStats(target).isDead())

View File

@ -686,4 +686,24 @@ namespace MWMechanics
{ {
return mSummonGraveyard; 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;
}
} }

View File

@ -90,6 +90,9 @@ namespace MWMechanics
// This may be necessary when the creature is in an inactive cell. // This may be necessary when the creature is in an inactive cell.
std::vector<int> mSummonGraveyard; std::vector<int> mSummonGraveyard;
float mAwarenessTimer = 0.f;
int mAwarenessRoll = -1;
protected: protected:
std::string mAttackType; std::string mAttackType;
int mLevel = 0; int mLevel = 0;
@ -300,6 +303,9 @@ namespace MWMechanics
void setTeleported(bool v) { mTeleported = v; } void setTeleported(bool v) { mTeleported = v; }
const std::map<ESM::RefId, AttributeValue>& getAttributes() const { return mAttributes; } const std::map<ESM::RefId, AttributeValue>& getAttributes() const { return mAttributes; }
void updateAwareness(float duration);
int getAwarenessRoll();
}; };
} }

View File

@ -1609,7 +1609,7 @@ namespace MWMechanics
commitCrime(player, victim, MWBase::MechanicsManager::OT_Murder); 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()) if (observer.getClass().getCreatureStats(observer).isDead() || !observer.getRefData().isEnabled())
return false; return false;
@ -1676,8 +1676,10 @@ namespace MWMechanics
} }
float target = x - y; float target = x - y;
if (useCache)
return observerStats.getAwarenessRoll() >= target;
auto& prng = MWBase::Environment::get().getWorld()->getPrng(); auto& prng = MWBase::Environment::get().getWorld()->getPrng();
return (Misc::Rng::roll0to99(prng) >= target); return Misc::Rng::roll0to99(prng) >= target;
} }
void MechanicsManager::startCombat( void MechanicsManager::startCombat(

View File

@ -102,7 +102,7 @@ namespace MWMechanics
///< Perform a persuasion action on NPC ///< Perform a persuasion action on NPC
/// Check if \a observer is potentially aware of \a ptr. Does not do a line of sight check! /// 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. /// Makes \a ptr fight \a target. Also shouts a combat taunt.
void startCombat( void startCombat(