diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 84d43156e..d9068b285 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -225,6 +225,10 @@ namespace MWBase virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0; virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const = 0; + /// Check if the target actor was detected by an observer + /// If the observer is a non-NPC, check all actors in AI processing distance as observers + virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) = 0; + virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer) = 0; /// List the owners that the player has stolen this item from (the owner can be an NPC or a faction). diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 0cb7619db..1f9515417 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1086,6 +1086,39 @@ namespace MWMechanics } } + bool Actors::isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) + { + if (!actor.getClass().isActor()) + return false; + + // If an observer is NPC, check if he detected an actor + if (!observer.isEmpty() && observer.getClass().isNpc()) + { + return + MWBase::Environment::get().getWorld()->getLOS(observer, actor) && + MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor, observer); + } + + // Otherwise check if any actor in AI processing range sees the target actor + std::vector actors; + osg::Vec3f position (actor.getRefData().getPosition().asVec3()); + getObjectsInRange(position, aiProcessingDistance, actors); + for(std::vector::iterator it = actors.begin(); it != actors.end(); ++it) + { + if (*it == actor) + continue; + + bool result = + MWBase::Environment::get().getWorld()->getLOS(*it, actor) && + MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor, *it); + + if (result) + return true; + } + + return false; + } + void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { PtrActorMap::iterator iter = mActors.find(old); diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 6eb3a2955..e433434a5 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -57,6 +57,10 @@ namespace MWMechanics PtrActorMap::const_iterator begin() { return mActors.begin(); } PtrActorMap::const_iterator end() { return mActors.end(); } + /// Check if the target actor was detected by an observer + /// If the observer is a non-NPC, check all actors in AI processing distance as observers + bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer); + /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently /// paused we may want to do it manually (after equipping permanent enchantment) void updateMagicEffects (const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 5f3dd58af..5d9ef726a 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -423,6 +423,11 @@ namespace MWMechanics mObjects.update(duration, paused); } + bool MechanicsManager::isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) + { + return mActors.isActorDetected(actor, observer); + } + bool MechanicsManager::isAttackPrepairing(const MWWorld::Ptr& ptr) { return mActors.isAttackPrepairing(ptr); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index adad21916..1bf3a8d22 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -191,6 +191,10 @@ namespace MWMechanics /// Is \a ptr casting spell or using weapon now? virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const; + /// Check if the target actor was detected by an observer + /// If the observer is a non-NPC, check all actors in AI processing distance as observers + virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer); + virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer); /// List the owners that the player has stolen this item from (the owner can be an NPC or a faction). diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 76130be24..c98e0fc5a 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -372,21 +372,14 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWWorld::Ptr observer = R()(runtime); + MWWorld::Ptr observer = R()(runtime, false); // required=false + std::string actorID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPtr(actorID, true); - if(!actor.getClass().isActor() || !observer.getClass().isActor()) - { - runtime.push(0); - return; - } - - Interpreter::Type_Integer value = - MWBase::Environment::get().getWorld()->getLOS(observer, actor) && - MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor, observer); + Interpreter::Type_Integer value = MWBase::Environment::get().getMechanicsManager()->isActorDetected(actor, observer); runtime.push (value); }