Cache allies found while iterating engageCombat

(Fixes #3814)
0.6.1
Allofich 8 years ago
parent 993860a4b1
commit 6272e1c674

@ -280,7 +280,7 @@ namespace MWMechanics
} }
} }
void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer) void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies, bool againstPlayer)
{ {
CreatureStats& creatureStats1 = actor1.getClass().getCreatureStats(actor1); CreatureStats& creatureStats1 = actor1.getClass().getCreatureStats(actor1);
if (creatureStats1.getAiSequence().isInCombat(actor2)) if (creatureStats1.getAiSequence().isInCombat(actor2))
@ -306,7 +306,8 @@ namespace MWMechanics
// Get actors allied with actor1. Includes those following or escorting actor1, actors following or escorting those actors, (recursive) // Get actors allied with actor1. Includes those following or escorting actor1, actors following or escorting those actors, (recursive)
// and any actor currently being followed or escorted by actor1 // and any actor currently being followed or escorted by actor1
std::set<MWWorld::Ptr> allies1; std::set<MWWorld::Ptr> allies1;
getActorsSidingWith(actor1, allies1);
getActorsSidingWith(actor1, allies1, cachedAllies);
// If an ally of actor1 has been attacked by actor2 or has attacked actor2, start combat between actor1 and actor2 // If an ally of actor1 has been attacked by actor2 or has attacked actor2, start combat between actor1 and actor2
for (std::set<MWWorld::Ptr>::const_iterator it = allies1.begin(); it != allies1.end(); ++it) for (std::set<MWWorld::Ptr>::const_iterator it = allies1.begin(); it != allies1.end(); ++it)
@ -328,10 +329,10 @@ namespace MWMechanics
aggressive = true; aggressive = true;
} }
std::set<MWWorld::Ptr> playerFollowersAndEscorters; std::set<MWWorld::Ptr> playerAllies;
getActorsSidingWith(MWMechanics::getPlayer(), playerFollowersAndEscorters); getActorsSidingWith(MWMechanics::getPlayer(), playerAllies, cachedAllies);
bool isPlayerFollowerOrEscorter = std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor1) != playerFollowersAndEscorters.end(); bool isPlayerFollowerOrEscorter = std::find(playerAllies.begin(), playerAllies.end(), actor1) != playerAllies.end();
// If actor2 and at least one actor2 are in combat with actor1, actor1 and its allies start combat with them // If actor2 and at least one actor2 are in combat with actor1, actor1 and its allies start combat with them
// Doesn't apply for player followers/escorters // Doesn't apply for player followers/escorters
@ -341,7 +342,9 @@ namespace MWMechanics
if (actor2.getClass().getCreatureStats(actor2).getAiSequence().isInCombat(actor1)) if (actor2.getClass().getCreatureStats(actor2).getAiSequence().isInCombat(actor1))
{ {
std::set<MWWorld::Ptr> allies2; std::set<MWWorld::Ptr> allies2;
getActorsSidingWith(actor2, allies2);
getActorsSidingWith(actor2, allies2, cachedAllies);
// Check that an ally of actor2 is also in combat with actor1 // Check that an ally of actor2 is also in combat with actor1
for (std::set<MWWorld::Ptr>::const_iterator it = allies2.begin(); it != allies2.end(); ++it) for (std::set<MWWorld::Ptr>::const_iterator it = allies2.begin(); it != allies2.end(); ++it)
{ {
@ -383,11 +386,11 @@ namespace MWMechanics
// Do aggression check if actor2 is the player or a player follower or escorter // Do aggression check if actor2 is the player or a player follower or escorter
if (!aggressive) if (!aggressive)
{ {
if (againstPlayer || std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor2) != playerFollowersAndEscorters.end()) if (againstPlayer || std::find(playerAllies.begin(), playerAllies.end(), actor2) != playerAllies.end())
{ {
// Player followers and escorters with high fight should not initiate combat with the player or with // Player followers and escorters with high fight should not initiate combat with the player or with
// other player followers or escorters // other player followers or escorters
if (std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor1) == playerFollowersAndEscorters.end()) if (std::find(playerAllies.begin(), playerAllies.end(), actor1) == playerAllies.end())
aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2); aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2);
} }
} }
@ -1075,6 +1078,8 @@ namespace MWMechanics
/// \todo move update logic to Actor class where appropriate /// \todo move update logic to Actor class where appropriate
std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> > cachedAllies; // will be filled as engageCombat iterates
// AI and magic effects update // AI and magic effects update
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{ {
@ -1126,7 +1131,7 @@ namespace MWMechanics
{ {
if (it->first == iter->first || iter->first == player) // player is not AI-controlled if (it->first == iter->first || iter->first == player) // player is not AI-controlled
continue; continue;
engageCombat(iter->first, it->first, it->first == player); engageCombat(iter->first, it->first, cachedAllies, it->first == player);
} }
} }
if (timerUpdateHeadTrack == 0) if (timerUpdateHeadTrack == 0)
@ -1591,6 +1596,30 @@ namespace MWMechanics
getActorsSidingWith(*it, out); getActorsSidingWith(*it, out);
} }
void Actors::getActorsSidingWith(const MWWorld::Ptr &actor, std::set<MWWorld::Ptr>& out, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies) {
std::list<MWWorld::Ptr> followers = getActorsSidingWith(actor);
// If we have already found actor's allies, use the cache
std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >::const_iterator search = cachedAllies.find(actor);
if (search != cachedAllies.end())
out = search->second;
else
{
for (std::list<MWWorld::Ptr>::iterator it = followers.begin(); it != followers.end(); ++it)
if (out.insert(*it).second)
getActorsSidingWith(*it, out);
// Cache ptrs and their sets of allies
cachedAllies.insert(std::make_pair(actor, out));
for (std::set<MWWorld::Ptr>::const_iterator it = out.begin(); it != out.end(); ++it)
{
search = cachedAllies.find(*it);
if (search == cachedAllies.end())
cachedAllies.insert(std::make_pair(*it, out));
}
}
}
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;

@ -88,7 +88,7 @@ namespace MWMechanics
@Notes: If againstPlayer = true then actor2 should be the Player. @Notes: If againstPlayer = true then actor2 should be the Player.
If one of the combatants is creature it should be actor1. If one of the combatants is creature it should be actor1.
*/ */
void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer); void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies, bool againstPlayer);
void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor, void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor,
MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance); MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance);
@ -127,6 +127,8 @@ namespace MWMechanics
void getActorsFollowing(const MWWorld::Ptr &actor, std::set<MWWorld::Ptr>& out); void getActorsFollowing(const MWWorld::Ptr &actor, std::set<MWWorld::Ptr>& out);
/// Recursive version of getActorsSidingWith /// Recursive version of getActorsSidingWith
void getActorsSidingWith(const MWWorld::Ptr &actor, std::set<MWWorld::Ptr>& out); void getActorsSidingWith(const MWWorld::Ptr &actor, std::set<MWWorld::Ptr>& out);
/// Recursive version of getActorsSidingWith that takes, adds to and returns a cache of actors mapped to their allies
void getActorsSidingWith(const MWWorld::Ptr &actor, std::set<MWWorld::Ptr>& out, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies);
/// 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);

Loading…
Cancel
Save