From 1db51a9e083401dd64ba5414a1517ce8637d731e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 2 Feb 2020 11:02:19 +0400 Subject: [PATCH] Re-work wandering outside of initial cell (bug #5261, bug #5262) --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/aitravel.cpp | 3 ++- apps/openmw/mwmechanics/aiwander.cpp | 22 ++++------------------ apps/openmw/mwmechanics/aiwander.hpp | 8 ++------ 4 files changed, 9 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11145e61ba..09f7b83e59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -195,6 +195,7 @@ Bug #5249: Wandering NPCs start walking too soon after they hello Bug #5250: Creatures display shield ground mesh instead of shield body part Bug #5255: "GetTarget, player" doesn't return 1 during NPC hello + Bug #5261: Creatures can sometimes become stuck playing idles and never wander again Feature #1774: Handle AvoidNode Feature #2229: Improve pathfinding AI Feature #3025: Analogue gamepad movement controls diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 0f3b22e117..dba70316ba 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -54,8 +54,9 @@ namespace MWMechanics stats.setMovementFlag(CreatureStats::Flag_Run, false); stats.setDrawState(DrawState_Nothing); + // Note: we should cancel internal "return after combat" package, if original location is too far away if (!isWithinMaxRange(targetPos, actorPos)) - return false; + return mHidden; // Unfortunately, with vanilla assets destination is sometimes blocked by other actor. // If we got close to target, check for actors nearby. If they are, finish AI package. diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 120d6ca095..442ba0499d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -145,15 +145,6 @@ namespace MWMechanics // get or create temporary storage AiWanderStorage& storage = state.get(); - const MWWorld::CellStore*& currentCell = storage.mCell; - bool cellChange = currentCell && (actor.getCell() != currentCell); - if(!currentCell || cellChange) - { - stopWalking(actor, storage); - currentCell = actor.getCell(); - storage.mPopulateAvailableNodes = true; - mStoredInitialActorPosition = false; - } mRemainingDuration -= ((duration*MWBase::Environment::get().getWorld()->getTimeScaleFactor()) / 3600); @@ -200,14 +191,13 @@ namespace MWMechanics if (AI_REACTION_TIME <= lastReaction) { lastReaction = 0; - return reactionTimeActions(actor, storage, currentCell, cellChange, pos); + return reactionTimeActions(actor, storage, pos); } else return false; } - bool AiWander::reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, - const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos) + bool AiWander::reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos) { if (mDistance <= 0) storage.mCanWanderAlongPathGrid = false; @@ -229,7 +219,7 @@ namespace MWMechanics // Initialization to discover & store allowed node points for this actor. if (storage.mPopulateAvailableNodes) { - getAllowedNodes(actor, currentCell->getCell(), storage); + getAllowedNodes(actor, actor.getCell()->getCell(), storage); } if (canActorMoveByZAxis(actor) && mDistance > 0) { @@ -258,10 +248,6 @@ namespace MWMechanics completeManualWalking(actor, storage); } - // Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles. - if(mDistance && cellChange) - mDistance = 0; - AiWanderStorage::WanderState& wanderState = storage.mState; if ((wanderState == AiWanderStorage::Wander_MoveNow) && storage.mCanWanderAlongPathGrid) { @@ -529,7 +515,7 @@ namespace MWMechanics unsigned int randNode = Misc::Rng::rollDice(storage.mAllowedNodes.size()); ESM::Pathgrid::Point dest(storage.mAllowedNodes[randNode]); - ToWorldCoordinates(dest, storage.mCell->getCell()); + ToWorldCoordinates(dest, actor.getCell()->getCell()); // actor position is already in world coordinates const osg::Vec3f start = actorPos.asVec3(); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 72f9b32280..38123a970c 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -27,8 +27,6 @@ namespace MWMechanics { float mReaction; // update some actions infrequently - const MWWorld::CellStore* mCell; // for detecting cell change - // AiWander states enum WanderState { @@ -60,7 +58,6 @@ namespace MWMechanics AiWanderStorage(): mReaction(0), - mCell(nullptr), mState(Wander_ChooseAction), mIsWanderingManually(false), mCanWanderAlongPathGrid(true), @@ -125,8 +122,7 @@ namespace MWMechanics void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage); - bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, - const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos); + bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos); bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage); void wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance); bool destinationIsAtWater(const MWWorld::Ptr &actor, const osg::Vec3f& destination); @@ -141,7 +137,7 @@ namespace MWMechanics bool mRepeat; bool mStoredInitialActorPosition; - osg::Vec3f mInitialActorPosition; + osg::Vec3f mInitialActorPosition; // Note: an original engine does not reset coordinates even when actor changes a cell bool mHasDestination; osg::Vec3f mDestination;