From 9d27eb197fceb00cf37b836bdfd649088f64635c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 28 Nov 2017 12:05:05 +0400 Subject: [PATCH 01/11] AiWander: return to initial position only after combat --- apps/openmw/mwmechanics/aiwander.cpp | 68 +++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 1 - .../mwmechanics/mechanicsmanagerimp.cpp | 18 ++++- 3 files changed, 41 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 8199170dc..3ad45e2c3 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -59,7 +59,7 @@ namespace MWMechanics float mTargetAngleRadians; bool mTurnActorGivingGreetingToFacePlayer; float mReaction; // update some actions infrequently - + AiWander::GreetingState mSaidGreeting; int mGreetingTimer; @@ -70,7 +70,7 @@ namespace MWMechanics bool mIsWanderingManually; bool mCanWanderAlongPathGrid; - + unsigned short mIdleAnimation; std::vector mBadIdles; // Idle animations that when called cause errors @@ -86,7 +86,7 @@ namespace MWMechanics float mDoorCheckDuration; int mStuckCount; - + AiWanderStorage(): mTargetAngleRadians(0), mTurnActorGivingGreetingToFacePlayer(false), @@ -111,7 +111,7 @@ namespace MWMechanics mIsWanderingManually = isManualWander; } }; - + AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector& idle, bool repeat): mDistance(distance), mDuration(duration), mRemainingDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat), mStoredInitialActorPosition(false), mInitialActorPosition(osg::Vec3f(0, 0, 0)), mHasDestination(false), mDestination(osg::Vec3f(0, 0, 0)) @@ -201,7 +201,18 @@ namespace MWMechanics stopWalking(actor, storage); currentCell = actor.getCell(); storage.mPopulateAvailableNodes = true; - mStoredInitialActorPosition = false; + } + + // Here we should reset an initial position, if a current cell was REALLY changed + // We do not store AiStorage in a savegame, so cellChange is not help us in this case + // TODO: find a more simple and fast solution, or do not store the mInitialActorPosition at all + if (mStoredInitialActorPosition) + { + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(mInitialActorPosition.x(),mInitialActorPosition.y(),cx,cy); + MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + if (cell != currentCell) + mStoredInitialActorPosition = false; } mRemainingDuration -= ((duration*MWBase::Environment::get().getWorld()->getTimeScaleFactor()) / 3600); @@ -223,7 +234,7 @@ namespace MWMechanics if (mPathFinder.isPathConstructed()) storage.setState(Wander_Walking); } - + doPerFrameActionsForState(actor, duration, storage, pos); playIdleDialogueRandomly(actor); @@ -298,13 +309,6 @@ namespace MWMechanics if(mDistance && cellChange) mDistance = 0; - // For stationary NPCs, move back to the starting location if another AiPackage moved us elsewhere - if (mDistance == 0 && !cellChange - && (pos.asVec3() - mInitialActorPosition).length2() > (DESTINATION_TOLERANCE * DESTINATION_TOLERANCE)) - { - returnToStartLocation(actor, storage, pos); - } - // Allow interrupting a walking actor to trigger a greeting WanderState& wanderState = storage.mState; if ((wanderState == Wander_IdleNow) || (wanderState == Wander_Walking)) @@ -321,7 +325,7 @@ namespace MWMechanics { setPathToAnAllowedNode(actor, storage, pos); } - } + } } else if (storage.mIsWanderingManually && mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) { completeManualWalking(actor, storage); } @@ -330,8 +334,8 @@ namespace MWMechanics } bool AiWander::getRepeat() const - { - return mRepeat; + { + return mRepeat; } @@ -350,27 +354,6 @@ namespace MWMechanics return false; } - void AiWander::returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos) - { - if (!mPathFinder.isPathConstructed()) - { - mDestination = mInitialActorPosition; - ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mDestination)); - - // actor position is already in world coordinates - ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); - - // don't take shortcuts for wandering - mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell())); - - if (mPathFinder.isPathConstructed()) - { - storage.setState(Wander_Walking); - mHasDestination = true; - } - } - } - /* * Commands actor to walk to a random location near original spawn location. */ @@ -497,7 +480,7 @@ namespace MWMechanics } } - void AiWander::onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, + void AiWander::onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) { // Is there no destination or are we there yet? @@ -873,7 +856,7 @@ namespace MWMechanics state.moveIn(new AiWanderStorage()); - MWBase::Environment::get().getWorld()->moveObject(actor, static_cast(dest.mX), + MWBase::Environment::get().getWorld()->moveObject(actor, static_cast(dest.mX), static_cast(dest.mY), static_cast(dest.mZ)); actor.getClass().adjustPosition(actor, false); } @@ -914,7 +897,7 @@ namespace MWMechanics // get NPC's position in local (i.e. cell) coordinates osg::Vec3f npcPos(mInitialActorPosition); CoordinateConverter(cell).toLocal(npcPos); - + // Find closest pathgrid point int closestPointIndex = PathFinder::GetClosestPoint(pathgrid, npcPos); @@ -945,7 +928,7 @@ namespace MWMechanics storage.mPopulateAvailableNodes = false; } - // When only one path grid point in wander distance, + // When only one path grid point in wander distance, // additional points for NPC to wander to are: // 1. NPC's initial location // 2. Partway along the path between the point and its connected points. @@ -969,7 +952,7 @@ namespace MWMechanics delta.normalize(); int distance = std::max(mDistance / 2, MINIMUM_WANDER_DISTANCE); - + // must not travel longer than distance between waypoints or NPC goes past waypoint distance = std::min(distance, static_cast(length)); delta *= distance; @@ -1041,4 +1024,3 @@ namespace MWMechanics init(); } } - diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 6266a7708..3f69d107d 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -85,7 +85,6 @@ namespace MWMechanics bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos, float duration); bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage); - void returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos); void wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance); bool destinationIsAtWater(const MWWorld::Ptr &actor, const osg::Vec3f& destination); bool destinationThroughGround(const osg::Vec3f& startPoint, const osg::Vec3f& destination); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 94317bbf2..bddcf83d6 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -22,6 +22,7 @@ #include "aicombat.hpp" #include "aipursue.hpp" +#include "aitravel.hpp" #include "spellcasting.hpp" #include "autocalcspell.hpp" #include "npcstats.hpp" @@ -1598,9 +1599,22 @@ namespace MWMechanics void MechanicsManager::startCombat(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) { - if (ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(target)) + MWMechanics::AiSequence& aiSequence = ptr.getClass().getCreatureStats(ptr).getAiSequence(); + + if (aiSequence.isInCombat(target)) return; - ptr.getClass().getCreatureStats(ptr).getAiSequence().stack(MWMechanics::AiCombat(target), ptr); + + // we should return a wandering actor back after combat + // TODO: only for stationary wander? + if (!aiSequence.isInCombat() && aiSequence.getLastRunTypeId() == MWMechanics::AiPackage::TypeIdWander) + { + osg::Vec3f pos = ptr.getRefData().getPosition().asVec3(); + + MWMechanics::AiTravel travelPackage(pos.x(), pos.y(), pos.z()); + aiSequence.stack(travelPackage, ptr); + } + + aiSequence.stack(MWMechanics::AiCombat(target), ptr); if (target == getPlayer()) { // if guard starts combat with player, guards pursuing player should do the same From 18ff097e4a2ab38bb3d46e3164e26fa89de8317e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 28 Nov 2017 12:06:09 +0400 Subject: [PATCH 02/11] Add the parameter to AiSequence::stack() to control ability to cancel other AI packages --- apps/openmw/mwmechanics/aisequence.cpp | 4 ++-- apps/openmw/mwmechanics/aisequence.hpp | 2 +- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 2a2d598f5..b38111f7b 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -298,7 +298,7 @@ void AiSequence::clear() mPackages.clear(); } -void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) +void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, bool cancelOther) { if (actor == getPlayer()) throw std::runtime_error("Can't add AI packages to player"); @@ -308,7 +308,7 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) stopCombat(); // remove previous packages if required - if (package.shouldCancelPreviousAi()) + if (cancelOther && package.shouldCancelPreviousAi()) { for(std::list::iterator it = mPackages.begin(); it != mPackages.end();) { diff --git a/apps/openmw/mwmechanics/aisequence.hpp b/apps/openmw/mwmechanics/aisequence.hpp index 41d204ee2..d725409de 100644 --- a/apps/openmw/mwmechanics/aisequence.hpp +++ b/apps/openmw/mwmechanics/aisequence.hpp @@ -115,7 +115,7 @@ namespace MWMechanics ///< Add \a package to the front of the sequence /** Suspends current package @param actor The actor that owns this AiSequence **/ - void stack (const AiPackage& package, const MWWorld::Ptr& actor); + void stack (const AiPackage& package, const MWWorld::Ptr& actor, bool cancelOther=true); /// Return the current active package. /** If there is no active package, it will throw an exception **/ diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index bddcf83d6..d032ed632 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1611,7 +1611,7 @@ namespace MWMechanics osg::Vec3f pos = ptr.getRefData().getPosition().asVec3(); MWMechanics::AiTravel travelPackage(pos.x(), pos.y(), pos.z()); - aiSequence.stack(travelPackage, ptr); + aiSequence.stack(travelPackage, ptr, false); } aiSequence.stack(MWMechanics::AiCombat(target), ptr); From 81f29d8dcd131bc123fbed5858f49fa049c060d9 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Dec 2017 18:53:31 +0400 Subject: [PATCH 03/11] AiWander: resume moving to destination after combat --- apps/openmw/mwmechanics/aipackage.hpp | 3 +++ apps/openmw/mwmechanics/aiwander.cpp | 15 ++++++++++++--- apps/openmw/mwmechanics/aiwander.hpp | 6 ++++-- .../openmw/mwmechanics/mechanicsmanagerimp.cpp | 18 ++++++++++++++---- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 06b4adf61..d9a7fa386 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -79,6 +79,9 @@ namespace MWMechanics /// Get the target actor the AI is targeted at (not applicable to all AI packages, default return empty Ptr) virtual MWWorld::Ptr getTarget() const; + /// Get the destination point of the AI package (not applicable to all AI packages, default return (0, 0, 0)) + virtual osg::Vec3f getDestination(const MWWorld::Ptr& actor) const { return osg::Vec3f(0, 0, 0); }; + /// Return true if having this AiPackage makes the actor side with the target in fights (default false) virtual bool sideWithTarget() const; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 3ad45e2c3..2e832dc3f 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -335,9 +335,18 @@ namespace MWMechanics bool AiWander::getRepeat() const { - return mRepeat; + return mRepeat; } + osg::Vec3f AiWander::getDestination(const MWWorld::Ptr& actor) const + { + if (mHasDestination) + return mDestination; + + const ESM::Pathgrid::Point currentPosition = actor.getRefData().getPosition().pos; + const osg::Vec3f currentPositionVec3f = osg::Vec3f(currentPosition.mX, currentPosition.mY, currentPosition.mZ); + return currentPositionVec3f; + } bool AiWander::isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage) { @@ -346,8 +355,8 @@ namespace MWMechanics // End package if duration is complete if (mRemainingDuration <= 0) { - stopWalking(actor, storage); - return true; + stopWalking(actor, storage); + return true; } } // if get here, not yet completed diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 3f69d107d..d96d93165 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -47,9 +47,11 @@ namespace MWMechanics virtual void writeState(ESM::AiSequence::AiSequence &sequence) const; virtual void fastForward(const MWWorld::Ptr& actor, AiState& state); - + bool getRepeat() const; - + + osg::Vec3f getDestination(const MWWorld::Ptr& actor) const; + enum GreetingState { Greet_None, Greet_InProgress, diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index d032ed632..55aace8e7 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1605,12 +1605,22 @@ namespace MWMechanics return; // we should return a wandering actor back after combat - // TODO: only for stationary wander? - if (!aiSequence.isInCombat() && aiSequence.getLastRunTypeId() == MWMechanics::AiPackage::TypeIdWander) + // the same thing for actors without AI packages + if (!aiSequence.isInCombat() && aiSequence.getTypeId() <= MWMechanics::AiPackage::TypeIdWander) { - osg::Vec3f pos = ptr.getRefData().getPosition().asVec3(); + int typeId = aiSequence.getTypeId(); + osg::Vec3f dest; + if (typeId == MWMechanics::AiPackage::TypeIdNone) + { + dest = ptr.getRefData().getPosition().asVec3(); + } + else if (typeId == MWMechanics::AiPackage::TypeIdWander) + { + AiPackage* activePackage = aiSequence.getActivePackage(); + dest = activePackage->getDestination(ptr); + } - MWMechanics::AiTravel travelPackage(pos.x(), pos.y(), pos.z()); + MWMechanics::AiTravel travelPackage(dest.x(), dest.y(), dest.z()); aiSequence.stack(travelPackage, ptr, false); } From 5105c676422fa2664d4605717a04d9aea500e157 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Dec 2017 19:58:42 +0400 Subject: [PATCH 04/11] Add mHidden field to AiTravel --- apps/openmw/mwmechanics/aipackage.hpp | 3 ++- apps/openmw/mwmechanics/aitravel.cpp | 8 ++++---- apps/openmw/mwmechanics/aitravel.hpp | 4 +++- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index d9a7fa386..829bbe898 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -48,7 +48,8 @@ namespace MWMechanics TypeIdPursue = 6, TypeIdAvoidDoor = 7, TypeIdFace = 8, - TypeIdBreathe = 9 + TypeIdBreathe = 9, + TypeIdInternalTravel = 10 }; ///Default constructor diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 36b96101f..ea14407ca 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -28,15 +28,14 @@ bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2) namespace MWMechanics { - AiTravel::AiTravel(float x, float y, float z) - : mX(x),mY(y),mZ(z) + AiTravel::AiTravel(float x, float y, float z, bool hidden) + : mX(x),mY(y),mZ(z),mHidden(hidden) { } AiTravel::AiTravel(const ESM::AiSequence::AiTravel *travel) : mX(travel->mData.mX), mY(travel->mData.mY), mZ(travel->mData.mZ) { - } AiTravel *MWMechanics::AiTravel::clone() const @@ -64,7 +63,8 @@ namespace MWMechanics int AiTravel::getTypeId() const { - return TypeIdTravel; + // TODO: store mHidden in the savegame? + return mHidden ? TypeIdInternalTravel : TypeIdTravel; } void AiTravel::fastForward(const MWWorld::Ptr& actor, AiState& state) diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index 8c75bded1..c297771d0 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -20,7 +20,7 @@ namespace MWMechanics { public: /// Default constructor - AiTravel(float x, float y, float z); + AiTravel(float x, float y, float z, bool hidden = false); AiTravel(const ESM::AiSequence::AiTravel* travel); /// Simulates the passing of time @@ -38,6 +38,8 @@ namespace MWMechanics float mX; float mY; float mZ; + + bool mHidden; }; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 55aace8e7..dc3695239 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1620,7 +1620,7 @@ namespace MWMechanics dest = activePackage->getDestination(ptr); } - MWMechanics::AiTravel travelPackage(dest.x(), dest.y(), dest.z()); + MWMechanics::AiTravel travelPackage(dest.x(), dest.y(), dest.z(), true); aiSequence.stack(travelPackage, ptr, false); } From 57d686131e89ec4f18ab97bcab7fa7443d7df20e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Dec 2017 20:01:15 +0400 Subject: [PATCH 05/11] Remove redundant condition --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index dc3695239..fbf989d05 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1606,7 +1606,7 @@ namespace MWMechanics // we should return a wandering actor back after combat // the same thing for actors without AI packages - if (!aiSequence.isInCombat() && aiSequence.getTypeId() <= MWMechanics::AiPackage::TypeIdWander) + if (aiSequence.getTypeId() <= MWMechanics::AiPackage::TypeIdWander) { int typeId = aiSequence.getTypeId(); osg::Vec3f dest; From 2f5beb885371aa2daed3b999b78cda24ec3abcfc Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Dec 2017 20:38:10 +0400 Subject: [PATCH 06/11] Remove unnecessary hack --- apps/openmw/mwmechanics/aiwander.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 2e832dc3f..ee680159e 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -201,18 +201,7 @@ namespace MWMechanics stopWalking(actor, storage); currentCell = actor.getCell(); storage.mPopulateAvailableNodes = true; - } - - // Here we should reset an initial position, if a current cell was REALLY changed - // We do not store AiStorage in a savegame, so cellChange is not help us in this case - // TODO: find a more simple and fast solution, or do not store the mInitialActorPosition at all - if (mStoredInitialActorPosition) - { - int cx,cy; - MWBase::Environment::get().getWorld()->positionToIndex(mInitialActorPosition.x(),mInitialActorPosition.y(),cx,cy); - MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); - if (cell != currentCell) - mStoredInitialActorPosition = false; + mStoredInitialActorPosition = false; } mRemainingDuration -= ((duration*MWBase::Environment::get().getWorld()->getTimeScaleFactor()) / 3600); From 3a0ee78d2b300301a16e4739cd11de14195f9d0d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 25 May 2018 19:31:31 +0400 Subject: [PATCH 07/11] AiTravel: store mHidden flag in savegame --- apps/openmw/mwmechanics/aisequence.cpp | 3 ++- apps/openmw/mwmechanics/aitravel.cpp | 4 ++-- components/esm/aisequence.cpp | 2 ++ components/esm/aisequence.hpp | 1 + components/esm/savedgame.cpp | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index b38111f7b..2c48eacf8 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -184,7 +184,8 @@ bool isActualAiPackage(int packageTypeId) && packageTypeId != AiPackage::TypeIdPursue && packageTypeId != AiPackage::TypeIdAvoidDoor && packageTypeId != AiPackage::TypeIdFace - && packageTypeId != AiPackage::TypeIdBreathe); + && packageTypeId != AiPackage::TypeIdBreathe + && packageTypeId != AiPackage::TypeIdInternalTravel); } void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index ea14407ca..72e6ced19 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -34,7 +34,7 @@ namespace MWMechanics } AiTravel::AiTravel(const ESM::AiSequence::AiTravel *travel) - : mX(travel->mData.mX), mY(travel->mData.mY), mZ(travel->mData.mZ) + : mX(travel->mData.mX), mY(travel->mData.mY), mZ(travel->mData.mZ), mHidden(travel->mHidden) { } @@ -63,7 +63,6 @@ namespace MWMechanics int AiTravel::getTypeId() const { - // TODO: store mHidden in the savegame? return mHidden ? TypeIdInternalTravel : TypeIdTravel; } @@ -83,6 +82,7 @@ namespace MWMechanics travel->mData.mX = mX; travel->mData.mY = mY; travel->mData.mZ = mZ; + travel->mHidden = mHidden; ESM::AiSequence::AiPackageContainer package; package.mType = ESM::AiSequence::Ai_Travel; diff --git a/components/esm/aisequence.cpp b/components/esm/aisequence.cpp index c39ef8269..196c1754f 100644 --- a/components/esm/aisequence.cpp +++ b/components/esm/aisequence.cpp @@ -35,11 +35,13 @@ namespace AiSequence void AiTravel::load(ESMReader &esm) { esm.getHNT (mData, "DATA"); + esm.getHNOT (mHidden, "HIDD"); } void AiTravel::save(ESMWriter &esm) const { esm.writeHNT ("DATA", mData); + esm.writeHNT ("HIDD", mHidden); } void AiEscort::load(ESMReader &esm) diff --git a/components/esm/aisequence.hpp b/components/esm/aisequence.hpp index 52446d38f..d4315062b 100644 --- a/components/esm/aisequence.hpp +++ b/components/esm/aisequence.hpp @@ -80,6 +80,7 @@ namespace ESM struct AiTravel : AiPackage { AiTravelData mData; + bool mHidden; void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index 3220f496e..c96261c64 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -5,7 +5,7 @@ #include "defs.hpp" unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE; -int ESM::SavedGame::sCurrentFormat = 3; +int ESM::SavedGame::sCurrentFormat = 4; void ESM::SavedGame::load (ESMReader &esm) { From 3d0631cfcc01fdb5032ac3df2be00a1beadd1e6a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 25 May 2018 20:07:08 +0400 Subject: [PATCH 08/11] Store last AI package in savegame --- apps/openmw/mwmechanics/aisequence.cpp | 6 +++++- components/esm/aisequence.cpp | 4 ++++ components/esm/aisequence.hpp | 6 +++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 2c48eacf8..51c82f6ed 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -393,6 +393,8 @@ void AiSequence::writeState(ESM::AiSequence::AiSequence &sequence) const { (*iter)->writeState(sequence); } + + sequence.mLastAiPackage = mLastAiPackage; } void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence) @@ -404,7 +406,7 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence) int count = 0; for (std::vector::const_iterator it = sequence.mPackages.begin(); it != sequence.mPackages.end(); ++it) - { + { if (isActualAiPackage(it->mType)) count++; } @@ -463,6 +465,8 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence) mPackages.push_back(package.release()); } + + mLastAiPackage = sequence.mLastAiPackage; } void AiSequence::fastForward(const MWWorld::Ptr& actor, AiState& state) diff --git a/components/esm/aisequence.cpp b/components/esm/aisequence.cpp index 196c1754f..43712d9ea 100644 --- a/components/esm/aisequence.cpp +++ b/components/esm/aisequence.cpp @@ -156,6 +156,8 @@ namespace AiSequence break; } } + + esm.writeHNT ("LAST", mLastAiPackage); } void AiSequence::load(ESMReader &esm) @@ -223,6 +225,8 @@ namespace AiSequence return; } } + + esm.getHNOT (mLastAiPackage, "LAST"); } } } diff --git a/components/esm/aisequence.hpp b/components/esm/aisequence.hpp index d4315062b..0cbde1b8e 100644 --- a/components/esm/aisequence.hpp +++ b/components/esm/aisequence.hpp @@ -148,10 +148,14 @@ namespace ESM struct AiSequence { - AiSequence() {} + AiSequence() + { + mLastAiPackage = -1; + } ~AiSequence(); std::vector mPackages; + int mLastAiPackage; void load (ESMReader &esm); void save (ESMWriter &esm) const; From 74a2cbe6960ce178fb426f86430532c561cb0da7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Jun 2018 09:30:44 +0400 Subject: [PATCH 09/11] AI: return back after pursuit --- apps/openmw/mwmechanics/aisequence.cpp | 23 +++++++++++++++++++ .../mwmechanics/mechanicsmanagerimp.cpp | 20 ---------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 51c82f6ed..84ddf8fdf 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -308,6 +308,29 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo if (isActualAiPackage(package.getTypeId())) stopCombat(); + // we should return a wandering actor back after combat or pursuit + // the same thing for actors without AI packages + int currentTypeId = getTypeId(); + int newTypeId = package.getTypeId(); + if (currentTypeId <= MWMechanics::AiPackage::TypeIdWander + && (newTypeId <= MWMechanics::AiPackage::TypeIdCombat + || newTypeId == MWMechanics::AiPackage::TypeIdPursue)) + { + osg::Vec3f dest; + if (currentTypeId == MWMechanics::AiPackage::TypeIdWander) + { + AiPackage* activePackage = getActivePackage(); + dest = activePackage->getDestination(actor); + } + else + { + dest = actor.getRefData().getPosition().asVec3(); + } + + MWMechanics::AiTravel travelPackage(dest.x(), dest.y(), dest.z(), true); + stack(travelPackage, actor, false); + } + // remove previous packages if required if (cancelOther && package.shouldCancelPreviousAi()) { diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index fbf989d05..89e1bef06 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1604,26 +1604,6 @@ namespace MWMechanics if (aiSequence.isInCombat(target)) return; - // we should return a wandering actor back after combat - // the same thing for actors without AI packages - if (aiSequence.getTypeId() <= MWMechanics::AiPackage::TypeIdWander) - { - int typeId = aiSequence.getTypeId(); - osg::Vec3f dest; - if (typeId == MWMechanics::AiPackage::TypeIdNone) - { - dest = ptr.getRefData().getPosition().asVec3(); - } - else if (typeId == MWMechanics::AiPackage::TypeIdWander) - { - AiPackage* activePackage = aiSequence.getActivePackage(); - dest = activePackage->getDestination(ptr); - } - - MWMechanics::AiTravel travelPackage(dest.x(), dest.y(), dest.z(), true); - aiSequence.stack(travelPackage, ptr, false); - } - aiSequence.stack(MWMechanics::AiCombat(target), ptr); if (target == getPlayer()) { From 6ed27732995c2a87f2e62c4966c24a729a60b158 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Jun 2018 12:05:10 +0400 Subject: [PATCH 10/11] Do not stack return packages --- apps/openmw/mwmechanics/aisequence.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 84ddf8fdf..85afbc453 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -308,11 +308,13 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo if (isActualAiPackage(package.getTypeId())) stopCombat(); - // we should return a wandering actor back after combat or pursuit - // the same thing for actors without AI packages + // We should return a wandering actor back after combat or pursuit. + // The same thing for actors without AI packages. + // Also there is no point to stack return packages. int currentTypeId = getTypeId(); int newTypeId = package.getTypeId(); if (currentTypeId <= MWMechanics::AiPackage::TypeIdWander + && !hasPackage(MWMechanics::AiPackage::TypeIdInternalTravel) && (newTypeId <= MWMechanics::AiPackage::TypeIdCombat || newTypeId == MWMechanics::AiPackage::TypeIdPursue)) { From 2e6cf2a4149ae87ca932833c70f594725475c5a1 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 8 Jun 2018 20:39:59 +0400 Subject: [PATCH 11/11] Add changelog entries --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb72c7cac..82410813e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,15 @@ 0.45.0 ------ + Bug #2835: Player able to slowly move when overencumbered + Bug #3997: Almalexia doesn't pace Bug #4221: Characters get stuck in V-shaped terrain + Bug #4251: Stationary NPCs do not return to their position after combat Bug #4293: Faction members are not aware of faction ownerships in barter Bug #4327: Missing animations during spell/weapon stance switching Bug #4426: RotateWorld behavior is incorrect Bug #4429: [Windows] Error on build INSTALL.vcxproj project (debug) with cmake 3.7.2 + Bug #4432: Guards behaviour is incorrect if they do not have AI packages Bug #4433: Guard behaviour is incorrect with Alarm = 0 Bug #4443: Goodbye option and dialogue choices are not mutually exclusive Feature #4444: Per-group KF-animation files support