Adjust AiFollow distance for groups of multiple followers (Fixes #1637)

This commit is contained in:
scrawl 2014-12-09 16:02:07 +01:00
parent 3ad0189982
commit 109a3f78a1
7 changed files with 73 additions and 7 deletions

View file

@ -183,6 +183,7 @@ namespace MWBase
///return the list of actors which are following the given actor
/**ie AiFollow is active and the target is the actor**/
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor) = 0;
virtual std::list<int> getActorsFollowingIndices(const MWWorld::Ptr& actor) = 0;
///Returns a list of actors who are fighting the given actor within the fAlarmDistance
/** ie AiCombat is active and the target is the actor **/

View file

@ -1470,6 +1470,36 @@ namespace MWMechanics
return list;
}
std::list<int> Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor)
{
std::list<int> list;
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
{
const MWWorld::Class &cls = iter->first.getClass();
CreatureStats &stats = cls.getCreatureStats(iter->first);
if (stats.isDead())
continue;
// An actor counts as following if AiFollow is the current AiPackage, or there are only Combat packages before the AiFollow package
for (std::list<MWMechanics::AiPackage*>::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it)
{
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow)
{
MWWorld::Ptr followTarget = dynamic_cast<MWMechanics::AiFollow*>(*it)->getTarget();
if (followTarget.isEmpty())
continue;
if (followTarget == actor)
list.push_back(dynamic_cast<MWMechanics::AiFollow*>(*it)->getFollowIndex());
else
break;
}
else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
break;
}
}
return list;
}
std::list<MWWorld::Ptr> Actors::getActorsFighting(const MWWorld::Ptr& actor) {
std::list<MWWorld::Ptr> list;
std::vector<MWWorld::Ptr> neighbors;

View file

@ -112,6 +112,9 @@ namespace MWMechanics
/**ie AiFollow is active and the target is the actor **/
std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor);
/// Get the list of AiFollow::mFollowIndex for all actors following this target
std::list<int> getActorsFollowingIndices(const MWWorld::Ptr& actor);
///Returns the list of actors which are fighting the given actor
/**ie AiCombat is active and the target is the actor **/
std::list<MWWorld::Ptr> getActorsFighting(const MWWorld::Ptr& actor);

View file

@ -6,6 +6,7 @@
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/cellstore.hpp"
#include "creaturestats.hpp"
@ -15,28 +16,31 @@
#include "steering.hpp"
int MWMechanics::AiFollow::mFollowIndexCounter = 0;
MWMechanics::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)
, mActorRefId(actorId), mCellId(""), mActorId(-1), mFollowIndex(mFollowIndexCounter++)
{
}
MWMechanics::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)
, mActorRefId(actorId), mCellId(cellId), mActorId(-1), mFollowIndex(mFollowIndexCounter++)
{
}
MWMechanics::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)
, mActorRefId(actorId), mCellId(""), mActorId(-1), mFollowIndex(mFollowIndexCounter++)
{
}
MWMechanics::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)
, mCommanded(follow->mCommanded), mFollowIndex(mFollowIndexCounter++)
{
}
@ -48,12 +52,24 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor, AiState& state,
if (target.isEmpty() || !target.getRefData().getCount() || !target.getRefData().isEnabled() // Really we should be checking whether the target is currently registered
// with the MechanicsManager
)
return true; //Target doesn't exist
return false; // Target is not here right now, wait for it to return
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
float followDistance = 180;
// When there are multiple actors following the same target, they form a group with each group member at 180*(i+1) distance to the target
int i=0;
std::list<int> followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowingIndices(target);
followers.sort();
for (std::list<int>::iterator it = followers.begin(); it != followers.end(); ++it)
{
if (*it == mFollowIndex)
followDistance *= (i+1);
++i;
}
if(!mAlwaysFollow) //Update if you only follow for a bit
{
//Check if we've run out of time
@ -66,7 +82,7 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor, AiState& state,
if((pos.pos[0]-mX)*(pos.pos[0]-mX) +
(pos.pos[1]-mY)*(pos.pos[1]-mY) +
(pos.pos[2]-mZ)*(pos.pos[2]-mZ) < 100*100) //Close-ish to final position
(pos.pos[2]-mZ)*(pos.pos[2]-mZ) < followDistance*followDistance) //Close-ish to final position
{
if(actor.getCell()->isExterior()) //Outside?
{
@ -84,7 +100,7 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor, AiState& state,
//Set the target destination from the actor
ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos;
if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 100) //Stop when you get close
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 {
pathTo(actor, dest, duration); //Go to the destination
@ -159,3 +175,8 @@ MWWorld::Ptr MWMechanics::AiFollow::getTarget()
else
return MWWorld::Ptr();
}
int MWMechanics::AiFollow::getFollowIndex() const
{
return mFollowIndex;
}

View file

@ -46,6 +46,8 @@ namespace MWMechanics
bool isCommanded() const;
int getFollowIndex() const;
private:
/// This will make the actor always follow.
/** Thus ignoring mDuration and mX,mY,mZ (used for summoned creatures). **/
@ -58,6 +60,9 @@ namespace MWMechanics
std::string mActorRefId;
int mActorId;
std::string mCellId;
int mFollowIndex;
static int mFollowIndexCounter;
};
}
#endif

View file

@ -1268,6 +1268,11 @@ namespace MWMechanics
return mActors.getActorsFollowing(actor);
}
std::list<int> MechanicsManager::getActorsFollowingIndices(const MWWorld::Ptr& actor)
{
return mActors.getActorsFollowingIndices(actor);
}
std::list<MWWorld::Ptr> MechanicsManager::getActorsFighting(const MWWorld::Ptr& actor) {
return mActors.getActorsFighting(actor);
}

View file

@ -147,6 +147,7 @@ namespace MWMechanics
virtual void getActorsInRange(const Ogre::Vector3 &position, float radius, std::vector<MWWorld::Ptr> &objects);
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor);
virtual std::list<int> getActorsFollowingIndices(const MWWorld::Ptr& actor);
virtual std::list<MWWorld::Ptr> getActorsFighting(const MWWorld::Ptr& actor);