mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-31 21:45:35 +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> getActorsFollowing(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
|
||||
/** 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();
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -2512,26 +2535,14 @@ namespace MWMechanics
|
|||
std::list<MWWorld::Ptr> Actors::getActorsFollowing(const MWWorld::Ptr& actor)
|
||||
{
|
||||
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)
|
||||
list.push_back(iteratedActor);
|
||||
else if (package->getTypeId() != AiPackageTypeId::Combat && package->getTypeId() != AiPackageTypeId::Wander)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (package->followTargetThroughDoors() && package->getTarget() == actor)
|
||||
list.push_back(iter.first);
|
||||
else if (package->getTypeId() != AiPackageTypeId::Combat && package->getTypeId() != AiPackageTypeId::Wander)
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
|
@ -2575,32 +2586,38 @@ namespace MWMechanics
|
|||
std::list<int> Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor)
|
||||
{
|
||||
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());
|
||||
break;
|
||||
}
|
||||
else if (package->getTypeId() != AiPackageTypeId::Combat && package->getTypeId() != AiPackageTypeId::Wander)
|
||||
break;
|
||||
list.push_back(static_cast<const AiFollow*>(package.get())->getFollowIndex());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (package->getTypeId() != AiPackageTypeId::Combat && package->getTypeId() != AiPackageTypeId::Wander)
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
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> list;
|
||||
std::vector<MWWorld::Ptr> neighbors;
|
||||
|
|
|
@ -181,6 +181,7 @@ namespace MWMechanics
|
|||
|
||||
/// Get the list of AiFollow::mFollowIndex for all actors following this target
|
||||
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
|
||||
/**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)
|
||||
return false;
|
||||
|
||||
// The distances below are approximations based on observations of the original engine.
|
||||
// If only one actor is following the target, it uses 186.
|
||||
// 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.
|
||||
|
||||
short followDistance = 186;
|
||||
std::list<int> followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowingIndices(target);
|
||||
if (followers.size() >= 2)
|
||||
// In the original engine the first follower stays closer to the player than any subsequent followers.
|
||||
// Followers beyond the first usually attempt to stand inside each other.
|
||||
osg::Vec3f::value_type floatingDistance = 0;
|
||||
auto followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowingByIndex(target);
|
||||
if (followers.size() >= 2 && followers.cbegin()->first != mFollowIndex)
|
||||
{
|
||||
followDistance = 313;
|
||||
short i = 0;
|
||||
followers.sort();
|
||||
for (int followIndex : followers)
|
||||
osg::Vec3f::value_type maxSize = 0;
|
||||
for(auto& follower : followers)
|
||||
{
|
||||
if (followIndex == mFollowIndex)
|
||||
followDistance += 130 * i;
|
||||
++i;
|
||||
auto halfExtent = MWBase::Environment::get().getWorld()->getHalfExtents(follower.second).y();
|
||||
if(halfExtent > floatingDistance)
|
||||
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
|
||||
{
|
||||
|
|
|
@ -1654,6 +1654,11 @@ namespace MWMechanics
|
|||
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) {
|
||||
return mActors.getActorsFighting(actor);
|
||||
}
|
||||
|
|
|
@ -150,6 +150,7 @@ namespace MWMechanics
|
|||
std::list<MWWorld::Ptr> getActorsSidingWith(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::map<int, MWWorld::Ptr> getActorsFollowingByIndex(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;
|
||||
|
|
Loading…
Reference in a new issue