diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index cbe058a00d..b49dcd4694 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1728,9 +1728,14 @@ namespace MWMechanics const float dist = (playerPos - iter->first.getRefData().getPosition().asVec3()).length(); bool isPlayer = iter->first == player; CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); - int packageId = stats.getAiSequence().getTypeId(); - bool travelling = (packageId == AiPackage::TypeIdTravel) || (packageId == AiPackage::TypeIdInternalTravel); - bool inRange = isPlayer || dist <= mActorsProcessingRange || travelling; + // Actors with active AI should be able to move. + bool alwaysActive = false; + if (!isPlayer && isConscious(iter->first) && !stats.isParalyzed()) + { + MWMechanics::AiSequence& seq = stats.getAiSequence(); + alwaysActive = !seq.isEmpty() && seq.getActivePackage()->alwaysActive(); + } + bool inRange = isPlayer || dist <= mActorsProcessingRange || alwaysActive; int activeFlag = 1; // Can be changed back to '2' to keep updating bounding boxes off screen (more accurate, but slower) if (isPlayer) activeFlag = 2; diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 0e628388de..b9b3baf643 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -104,6 +104,9 @@ namespace MWMechanics virtual osg::Vec3f getDestination() { return osg::Vec3f(0, 0, 0); } + // Return true if any loaded actor with this AI package must be active. + virtual bool alwaysActive() const { return false; } + /// Reset pathfinding state void reset(); diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 0c675bfc1f..5760069e77 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -209,12 +209,15 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac } MWMechanics::AiPackage* package = mPackages.front(); + if (!package->alwaysActive() && outOfRange) + return; + int packageTypeId = package->getTypeId(); // workaround ai packages not being handled as in the vanilla engine if (isActualAiPackage(packageTypeId)) mLastAiPackage = packageTypeId; // if active package is combat one, choose nearest target - if (!outOfRange && packageTypeId == AiPackage::TypeIdCombat) + if (packageTypeId == AiPackage::TypeIdCombat) { std::list::iterator itActualCombat; @@ -272,10 +275,6 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac try { - if (outOfRange && packageTypeId != AiPackage::TypeIdTravel - && packageTypeId != AiPackage::TypeIdInternalTravel) - return; - if (package->execute (actor, characterController, mAiState, duration)) { // Put repeating noncombat AI packages on the end of the stack so they can be used again diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index ea69b5d745..a333c83fd0 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -34,6 +34,8 @@ namespace MWMechanics virtual bool useVariableSpeed() const { return true;} + virtual bool alwaysActive() const { return true; } + virtual osg::Vec3f getDestination() { return osg::Vec3f(mX, mY, mZ); } private: diff --git a/docs/source/reference/modding/settings/game.rst b/docs/source/reference/modding/settings/game.rst index 162cb0e2ff..9a3e9c84d8 100644 --- a/docs/source/reference/modding/settings/game.rst +++ b/docs/source/reference/modding/settings/game.rst @@ -103,13 +103,13 @@ actors processing range :Range: 3584 to 7168 :Default: 7168 -This setting allows to specify a distance from player in game units, in which OpenMW updates actor's state. +This setting specifies the actor state update distance from the player in game units. Actor state update includes AI, animations, and physics processing. -Actors near that border start softly fade out instead of just appearing/disapperaing. -It is not recommended to change this value from default if you use mods with -long-range AiTravel packages (e.g. patrols, caravans and travellers). +Actors close to this distance softly fade in and out instead of appearing or disappearing abruptly. +Keep in mind that actors running Travel AI packages are always active to avoid +issues in mods with long-range AiTravel packages (for example, patrols, caravans and travellers). -This setting can be controlled in game with the "Actors processing range slider" in the Prefs panel of the Options menu. +This setting can be controlled in game with the "Actors Processing Range" slider in the Prefs panel of the Options menu. classic reflected absorb spells behavior ----------------------------------------