mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-21 07:23:54 +00:00
Make followers keep a distance dependant on the fattest party member
This commit is contained in:
parent
a4f6448f34
commit
7cac7fa870
6 changed files with 77 additions and 53 deletions
|
@ -199,6 +199,7 @@ namespace MWBase
|
||||||
virtual std::list<MWWorld::Ptr> getActorsSidingWith(const MWWorld::Ptr& actor) = 0;
|
virtual std::list<MWWorld::Ptr> getActorsSidingWith(const MWWorld::Ptr& actor) = 0;
|
||||||
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor) = 0;
|
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor) = 0;
|
||||||
virtual std::list<int> getActorsFollowingIndices(const MWWorld::Ptr& actor) = 0;
|
virtual std::list<int> getActorsFollowingIndices(const MWWorld::Ptr& actor) = 0;
|
||||||
|
virtual std::map<int, MWWorld::Ptr> getActorsFollowingByIndex(const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
||||||
///Returns a list of actors who are fighting the given actor within the fAlarmDistance
|
///Returns a list of actors who are fighting the given actor within the fAlarmDistance
|
||||||
/** ie AiCombat is active and the target is the actor **/
|
/** ie AiCombat is active and the target is the actor **/
|
||||||
|
|
|
@ -142,6 +142,29 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float
|
||||||
magicka = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified();
|
magicka = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void forEachFollowingPackage(MWMechanics::Actors::PtrActorMap& actors, const MWWorld::Ptr& actor, const MWWorld::Ptr& player, T&& func)
|
||||||
|
{
|
||||||
|
for(auto& iter : actors)
|
||||||
|
{
|
||||||
|
const MWWorld::Ptr &iteratedActor = iter.first;
|
||||||
|
if (iteratedActor == player || iteratedActor == actor)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const MWMechanics::CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor);
|
||||||
|
if (stats.isDead())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// An actor counts as following if AiFollow is the current AiPackage,
|
||||||
|
// or there are only Combat and Wander packages before the AiFollow package
|
||||||
|
for (const auto& package : stats.getAiSequence())
|
||||||
|
{
|
||||||
|
if(!func(iter, package))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
|
@ -2512,26 +2535,14 @@ namespace MWMechanics
|
||||||
std::list<MWWorld::Ptr> Actors::getActorsFollowing(const MWWorld::Ptr& actor)
|
std::list<MWWorld::Ptr> Actors::getActorsFollowing(const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
std::list<MWWorld::Ptr> list;
|
std::list<MWWorld::Ptr> list;
|
||||||
for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
forEachFollowingPackage(mActors, actor, getPlayer(), [&] (auto& iter, const std::unique_ptr<AiPackage>& package)
|
||||||
{
|
|
||||||
const MWWorld::Ptr &iteratedActor = iter->first;
|
|
||||||
if (iteratedActor == getPlayer() || iteratedActor == actor)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor);
|
|
||||||
if (stats.isDead())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// An actor counts as following if AiFollow is the current AiPackage,
|
|
||||||
// or there are only Combat and Wander packages before the AiFollow package
|
|
||||||
for (const auto& package : stats.getAiSequence())
|
|
||||||
{
|
{
|
||||||
if (package->followTargetThroughDoors() && package->getTarget() == actor)
|
if (package->followTargetThroughDoors() && package->getTarget() == actor)
|
||||||
list.push_back(iteratedActor);
|
list.push_back(iter.first);
|
||||||
else if (package->getTypeId() != AiPackageTypeId::Combat && package->getTypeId() != AiPackageTypeId::Wander)
|
else if (package->getTypeId() != AiPackageTypeId::Combat && package->getTypeId() != AiPackageTypeId::Wander)
|
||||||
break;
|
return false;
|
||||||
}
|
return true;
|
||||||
}
|
});
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2575,32 +2586,38 @@ namespace MWMechanics
|
||||||
std::list<int> Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor)
|
std::list<int> Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor)
|
||||||
{
|
{
|
||||||
std::list<int> list;
|
std::list<int> list;
|
||||||
for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
forEachFollowingPackage(mActors, actor, getPlayer(), [&] (auto& iter, const std::unique_ptr<AiPackage>& package)
|
||||||
{
|
|
||||||
const MWWorld::Ptr &iteratedActor = iter->first;
|
|
||||||
if (iteratedActor == getPlayer() || iteratedActor == actor)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor);
|
|
||||||
if (stats.isDead())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// An actor counts as following if AiFollow is the current AiPackage,
|
|
||||||
// or there are only Combat and Wander packages before the AiFollow package
|
|
||||||
for (const auto& package : stats.getAiSequence())
|
|
||||||
{
|
{
|
||||||
if (package->followTargetThroughDoors() && package->getTarget() == actor)
|
if (package->followTargetThroughDoors() && package->getTarget() == actor)
|
||||||
{
|
{
|
||||||
list.push_back(static_cast<const AiFollow*>(package.get())->getFollowIndex());
|
list.push_back(static_cast<const AiFollow*>(package.get())->getFollowIndex());
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
else if (package->getTypeId() != AiPackageTypeId::Combat && package->getTypeId() != AiPackageTypeId::Wander)
|
else if (package->getTypeId() != AiPackageTypeId::Combat && package->getTypeId() != AiPackageTypeId::Wander)
|
||||||
break;
|
return false;
|
||||||
}
|
return true;
|
||||||
}
|
});
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::map<int, MWWorld::Ptr> Actors::getActorsFollowingByIndex(const MWWorld::Ptr &actor)
|
||||||
|
{
|
||||||
|
std::map<int, MWWorld::Ptr> map;
|
||||||
|
forEachFollowingPackage(mActors, actor, getPlayer(), [&] (auto& iter, const std::unique_ptr<AiPackage>& package)
|
||||||
|
{
|
||||||
|
if (package->followTargetThroughDoors() && package->getTarget() == actor)
|
||||||
|
{
|
||||||
|
int index = static_cast<const AiFollow*>(package.get())->getFollowIndex();
|
||||||
|
map[index] = iter.first;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (package->getTypeId() != AiPackageTypeId::Combat && package->getTypeId() != AiPackageTypeId::Wander)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
std::list<MWWorld::Ptr> Actors::getActorsFighting(const MWWorld::Ptr& actor) {
|
std::list<MWWorld::Ptr> Actors::getActorsFighting(const MWWorld::Ptr& actor) {
|
||||||
std::list<MWWorld::Ptr> list;
|
std::list<MWWorld::Ptr> list;
|
||||||
std::vector<MWWorld::Ptr> neighbors;
|
std::vector<MWWorld::Ptr> neighbors;
|
||||||
|
|
|
@ -181,6 +181,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
/// Get the list of AiFollow::mFollowIndex for all actors following this target
|
/// Get the list of AiFollow::mFollowIndex for all actors following this target
|
||||||
std::list<int> getActorsFollowingIndices(const MWWorld::Ptr& actor);
|
std::list<int> getActorsFollowingIndices(const MWWorld::Ptr& actor);
|
||||||
|
std::map<int, MWWorld::Ptr> getActorsFollowingByIndex(const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
///Returns the list of actors which are fighting the given actor
|
///Returns the list of actors which are fighting the given actor
|
||||||
/**ie AiCombat is active and the target is the actor **/
|
/**ie AiCombat is active and the target is the actor **/
|
||||||
|
|
|
@ -113,24 +113,23 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
||||||
if (!mActive)
|
if (!mActive)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// The distances below are approximations based on observations of the original engine.
|
// In the original engine the first follower stays closer to the player than any subsequent followers.
|
||||||
// If only one actor is following the target, it uses 186.
|
// Followers beyond the first usually attempt to stand inside each other.
|
||||||
// If there are multiple actors following the same target, they form a group with each group member at 313 + (130 * i) distance to the target.
|
osg::Vec3f::value_type floatingDistance = 0;
|
||||||
|
auto followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowingByIndex(target);
|
||||||
short followDistance = 186;
|
if (followers.size() >= 2 && followers.cbegin()->first != mFollowIndex)
|
||||||
std::list<int> followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowingIndices(target);
|
|
||||||
if (followers.size() >= 2)
|
|
||||||
{
|
{
|
||||||
followDistance = 313;
|
osg::Vec3f::value_type maxSize = 0;
|
||||||
short i = 0;
|
for(auto& follower : followers)
|
||||||
followers.sort();
|
|
||||||
for (int followIndex : followers)
|
|
||||||
{
|
{
|
||||||
if (followIndex == mFollowIndex)
|
auto halfExtent = MWBase::Environment::get().getWorld()->getHalfExtents(follower.second).y();
|
||||||
followDistance += 130 * i;
|
if(halfExtent > floatingDistance)
|
||||||
++i;
|
floatingDistance = halfExtent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
floatingDistance += MWBase::Environment::get().getWorld()->getHalfExtents(target).y();
|
||||||
|
floatingDistance += MWBase::Environment::get().getWorld()->getHalfExtents(actor).y() * 2;
|
||||||
|
short followDistance = static_cast<short>(floatingDistance);
|
||||||
|
|
||||||
if (!mAlwaysFollow) //Update if you only follow for a bit
|
if (!mAlwaysFollow) //Update if you only follow for a bit
|
||||||
{
|
{
|
||||||
|
|
|
@ -1654,6 +1654,11 @@ namespace MWMechanics
|
||||||
return mActors.getActorsFollowingIndices(actor);
|
return mActors.getActorsFollowingIndices(actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::map<int, MWWorld::Ptr> MechanicsManager::getActorsFollowingByIndex(const MWWorld::Ptr& actor)
|
||||||
|
{
|
||||||
|
return mActors.getActorsFollowingByIndex(actor);
|
||||||
|
}
|
||||||
|
|
||||||
std::list<MWWorld::Ptr> MechanicsManager::getActorsFighting(const MWWorld::Ptr& actor) {
|
std::list<MWWorld::Ptr> MechanicsManager::getActorsFighting(const MWWorld::Ptr& actor) {
|
||||||
return mActors.getActorsFighting(actor);
|
return mActors.getActorsFighting(actor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,6 +150,7 @@ namespace MWMechanics
|
||||||
std::list<MWWorld::Ptr> getActorsSidingWith(const MWWorld::Ptr& actor) override;
|
std::list<MWWorld::Ptr> getActorsSidingWith(const MWWorld::Ptr& actor) override;
|
||||||
std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor) override;
|
std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor) override;
|
||||||
std::list<int> getActorsFollowingIndices(const MWWorld::Ptr& actor) override;
|
std::list<int> getActorsFollowingIndices(const MWWorld::Ptr& actor) override;
|
||||||
|
std::map<int, MWWorld::Ptr> getActorsFollowingByIndex(const MWWorld::Ptr& actor) override;
|
||||||
|
|
||||||
std::list<MWWorld::Ptr> getActorsFighting(const MWWorld::Ptr& actor) override;
|
std::list<MWWorld::Ptr> getActorsFighting(const MWWorld::Ptr& actor) override;
|
||||||
std::list<MWWorld::Ptr> getEnemiesNearby(const MWWorld::Ptr& actor) override;
|
std::list<MWWorld::Ptr> getEnemiesNearby(const MWWorld::Ptr& actor) override;
|
||||||
|
|
Loading…
Reference in a new issue