diff --git a/CHANGELOG.md b/CHANGELOG.md index d4649c46d0..3178c609bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -180,6 +180,7 @@ Bug #5209: Spellcasting ignores race height Bug #5210: AiActivate allows actors to open dialogue and inventory windows Bug #5211: Screen fades in if the first loaded save is in interior cell + Bug #5212: AiTravel does not work for actors outside of AI processing range Bug #5213: SameFaction script function is broken Bug #5218: Crash when disabling ToggleBorders Bug #5220: GetLOS crashes when actor isn't loaded diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 35a48710dd..b49dcd4694 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1695,6 +1695,11 @@ namespace MWMechanics } } } + else if (aiActive && iter->first != player && isConscious(iter->first)) + { + CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); + stats.getAiSequence().execute(iter->first, *ctrl, duration, /*outOfRange*/true); + } if(iter->first.getClass().isNpc()) { @@ -1722,7 +1727,15 @@ namespace MWMechanics { const float dist = (playerPos - iter->first.getRefData().getPosition().asVec3()).length(); bool isPlayer = iter->first == player; - bool inRange = isPlayer || dist <= mActorsProcessingRange; + CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); + // 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 e022403526..5760069e77 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -198,7 +198,7 @@ bool isActualAiPackage(int packageTypeId) packageTypeId <= AiPackage::TypeIdActivate); } -void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, float duration) +void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, float duration, bool outOfRange) { if(actor != getPlayer()) { @@ -209,6 +209,9 @@ 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)) diff --git a/apps/openmw/mwmechanics/aisequence.hpp b/apps/openmw/mwmechanics/aisequence.hpp index 5df4404074..7f07d5aae3 100644 --- a/apps/openmw/mwmechanics/aisequence.hpp +++ b/apps/openmw/mwmechanics/aisequence.hpp @@ -110,7 +110,7 @@ namespace MWMechanics void stopPursuit(); /// Execute current package, switching if needed. - void execute (const MWWorld::Ptr& actor, CharacterController& characterController, float duration); + void execute (const MWWorld::Ptr& actor, CharacterController& characterController, float duration, bool outOfRange=false); /// Simulate the passing of time using the currently active AI package void fastForward(const MWWorld::Ptr &actor); 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 ----------------------------------------