From e0c6f845464f211fc7f87a11e5b2b9c9a3b3d554 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Dec 2014 22:25:28 +0100 Subject: [PATCH] AiFollow: target has to be seen in order to start following (Fixes #1637) --- apps/openmw/mwmechanics/aifollow.cpp | 77 +++++++++++++++++++++------- apps/openmw/mwmechanics/aifollow.hpp | 1 + components/esm/aisequence.cpp | 4 ++ components/esm/aisequence.hpp | 2 + 4 files changed, 66 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index 8f3e19b46..161f4bb90 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -13,39 +13,51 @@ #include "movement.hpp" #include +#include #include "steering.hpp" -int MWMechanics::AiFollow::mFollowIndexCounter = 0; +namespace MWMechanics +{ + + +struct AiFollowStorage : AiTemporaryBase +{ + float mTimer; + + AiFollowStorage() : mTimer(0.f) {} +}; -MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z) +int AiFollow::mFollowIndexCounter = 0; + +AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z) : mAlwaysFollow(false), mCommanded(false), mRemainingDuration(duration), mX(x), mY(y), mZ(z) -, mActorRefId(actorId), mCellId(""), mActorId(-1), mFollowIndex(mFollowIndexCounter++) +, mActorRefId(actorId), mCellId(""), mActorId(-1), mFollowIndex(mFollowIndexCounter++), mActive(false) { } -MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z) +AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z) : mAlwaysFollow(false), mCommanded(false), mRemainingDuration(duration), mX(x), mY(y), mZ(z) -, mActorRefId(actorId), mCellId(cellId), mActorId(-1), mFollowIndex(mFollowIndexCounter++) +, mActorRefId(actorId), mCellId(cellId), mActorId(-1), mFollowIndex(mFollowIndexCounter++), mActive(false) { } -MWMechanics::AiFollow::AiFollow(const std::string &actorId, bool commanded) +AiFollow::AiFollow(const std::string &actorId, bool commanded) : mAlwaysFollow(true), mCommanded(commanded), mRemainingDuration(0), mX(0), mY(0), mZ(0) -, mActorRefId(actorId), mCellId(""), mActorId(-1), mFollowIndex(mFollowIndexCounter++) +, mActorRefId(actorId), mCellId(""), mActorId(-1), mFollowIndex(mFollowIndexCounter++), mActive(false) { } -MWMechanics::AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow) +AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow) : mAlwaysFollow(follow->mAlwaysFollow), mRemainingDuration(follow->mRemainingDuration) , mX(follow->mData.mX), mY(follow->mData.mY), mZ(follow->mData.mZ) , mActorRefId(follow->mTargetId), mActorId(-1), mCellId(follow->mCellId) - , mCommanded(follow->mCommanded), mFollowIndex(mFollowIndexCounter++) + , mCommanded(follow->mCommanded), mFollowIndex(mFollowIndexCounter++), mActive(follow->mActive) { } -bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor, AiState& state, float duration) +bool AiFollow::execute (const MWWorld::Ptr& actor, AiState& state, float duration) { MWWorld::Ptr target = getTarget(); @@ -56,6 +68,24 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor, AiState& state, actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing); + // AiFollow requires the target to be in range and within sight for the initial activation + if (!mActive) + { + AiFollowStorage& storage = state.get(); + storage.mTimer -= duration; + + if (storage.mTimer < 0) + { + if (Ogre::Vector3(actor.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(target.getRefData().getPosition().pos)) + < 500*500 + && MWBase::Environment::get().getWorld()->getLOS(actor, target)) + mActive = true; + storage.mTimer = 0.5f; + } + } + if (!mActive) + return false; + ESM::Position pos = actor.getRefData().getPosition(); //position of the actor float followDistance = 180; @@ -101,8 +131,16 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor, AiState& state, ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos; if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < followDistance) //Stop when you get close + { actor.getClass().getMovementSettings(actor).mPosition[1] = 0; - else { + + // turn towards target anyway + float directionX = target.getRefData().getPosition().pos[0] - actor.getRefData().getPosition().pos[0]; + float directionY = target.getRefData().getPosition().pos[1] - actor.getRefData().getPosition().pos[1]; + zTurn(actor, Ogre::Math::ATan2(directionX,directionY), Ogre::Degree(5)); + } + else + { pathTo(actor, dest, duration); //Go to the destination } @@ -115,27 +153,27 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor, AiState& state, return false; } -std::string MWMechanics::AiFollow::getFollowedActor() +std::string AiFollow::getFollowedActor() { return mActorRefId; } -MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const +AiFollow *MWMechanics::AiFollow::clone() const { return new AiFollow(*this); } -int MWMechanics::AiFollow::getTypeId() const +int AiFollow::getTypeId() const { return TypeIdFollow; } -bool MWMechanics::AiFollow::isCommanded() const +bool AiFollow::isCommanded() const { return mCommanded; } -void MWMechanics::AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) const +void AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) const { std::auto_ptr follow(new ESM::AiSequence::AiFollow()); follow->mData.mX = mX; @@ -146,6 +184,7 @@ void MWMechanics::AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) co follow->mCellId = mCellId; follow->mAlwaysFollow = mAlwaysFollow; follow->mCommanded = mCommanded; + follow->mActive = mActive; ESM::AiSequence::AiPackageContainer package; package.mType = ESM::AiSequence::Ai_Follow; @@ -153,7 +192,7 @@ void MWMechanics::AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) co sequence.mPackages.push_back(package); } -MWWorld::Ptr MWMechanics::AiFollow::getTarget() +MWWorld::Ptr AiFollow::getTarget() { if (mActorId == -2) return MWWorld::Ptr(); @@ -176,7 +215,9 @@ MWWorld::Ptr MWMechanics::AiFollow::getTarget() return MWWorld::Ptr(); } -int MWMechanics::AiFollow::getFollowIndex() const +int AiFollow::getFollowIndex() const { return mFollowIndex; } + +} diff --git a/apps/openmw/mwmechanics/aifollow.hpp b/apps/openmw/mwmechanics/aifollow.hpp index 23b159b88..68a1f0ea5 100644 --- a/apps/openmw/mwmechanics/aifollow.hpp +++ b/apps/openmw/mwmechanics/aifollow.hpp @@ -60,6 +60,7 @@ namespace MWMechanics std::string mActorRefId; int mActorId; std::string mCellId; + bool mActive; // have we spotted the target? int mFollowIndex; static int mFollowIndexCounter; diff --git a/components/esm/aisequence.cpp b/components/esm/aisequence.cpp index 0e3e54102..339b390d7 100644 --- a/components/esm/aisequence.cpp +++ b/components/esm/aisequence.cpp @@ -60,6 +60,8 @@ namespace AiSequence esm.getHNT (mAlwaysFollow, "ALWY"); mCommanded = false; esm.getHNOT (mCommanded, "CMND"); + mActive = false; + esm.getHNOT (mActive, "ACTV"); } void AiFollow::save(ESMWriter &esm) const @@ -71,6 +73,8 @@ namespace AiSequence esm.writeHNString ("CELL", mCellId); esm.writeHNT ("ALWY", mAlwaysFollow); esm.writeHNT ("CMND", mCommanded); + if (mActive) + esm.writeHNT("ACTV", mActive); } void AiActivate::load(ESMReader &esm) diff --git a/components/esm/aisequence.hpp b/components/esm/aisequence.hpp index da16bf867..fbf83c245 100644 --- a/components/esm/aisequence.hpp +++ b/components/esm/aisequence.hpp @@ -98,6 +98,8 @@ namespace ESM bool mAlwaysFollow; bool mCommanded; + bool mActive; + void load(ESMReader &esm); void save(ESMWriter &esm) const; };