mirror of
https://github.com/OpenMW/openmw.git
synced 2025-05-31 00:11:31 +00:00
Move the caching getActorsSidingWith to its own type
This commit is contained in:
parent
bdc6119b31
commit
a8ee3dfae8
3 changed files with 65 additions and 56 deletions
|
@ -577,8 +577,8 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
void Actors::engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2,
|
||||
std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr>>& cachedAllies, bool againstPlayer) const
|
||||
void Actors::engageCombat(
|
||||
const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, SidingCache& cachedAllies, bool againstPlayer) const
|
||||
{
|
||||
// No combat for totally static creatures
|
||||
if (!actor1.getClass().isMobile(actor1))
|
||||
|
@ -606,9 +606,8 @@ namespace MWMechanics
|
|||
|
||||
// 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
|
||||
std::set<MWWorld::Ptr> allies1;
|
||||
|
||||
getActorsSidingWith(actor1, allies1, cachedAllies);
|
||||
const std::set<MWWorld::Ptr> allies1 = cachedAllies.getActorsSidingWith(actor1);
|
||||
const std::set<MWWorld::Ptr> allies2 = cachedAllies.getActorsSidingWith(actor2);
|
||||
|
||||
const auto mechanicsManager = MWBase::Environment::get().getMechanicsManager();
|
||||
// If an ally of actor1 has been attacked by actor2 or has attacked actor2, start combat between actor1 and
|
||||
|
@ -620,7 +619,7 @@ namespace MWMechanics
|
|||
|
||||
if (creatureStats2.matchesActorId(ally.getClass().getCreatureStats(ally).getHitAttemptActorId()))
|
||||
{
|
||||
mechanicsManager->startCombat(actor1, actor2, nullptr);
|
||||
mechanicsManager->startCombat(actor1, actor2, &allies2);
|
||||
// Also set the same hit attempt actor. Otherwise, if fighting the player, they may stop combat
|
||||
// if the player gets out of reach, while the ally would continue combat with the player
|
||||
creatureStats1.setHitAttemptActorId(ally.getClass().getCreatureStats(ally).getHitAttemptActorId());
|
||||
|
@ -633,9 +632,8 @@ namespace MWMechanics
|
|||
aggressive = true;
|
||||
}
|
||||
|
||||
std::set<MWWorld::Ptr> playerAllies;
|
||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||
getActorsSidingWith(player, playerAllies, cachedAllies);
|
||||
const std::set<MWWorld::Ptr>& playerAllies = cachedAllies.getActorsSidingWith(player);
|
||||
|
||||
bool isPlayerFollowerOrEscorter = playerAllies.find(actor1) != playerAllies.end();
|
||||
|
||||
|
@ -646,10 +644,6 @@ namespace MWMechanics
|
|||
// Check that actor2 is in combat with actor1
|
||||
if (creatureStats2.getAiSequence().isInCombat(actor1))
|
||||
{
|
||||
std::set<MWWorld::Ptr> allies2;
|
||||
|
||||
getActorsSidingWith(actor2, allies2, cachedAllies);
|
||||
|
||||
// Check that an ally of actor2 is also in combat with actor1
|
||||
for (const MWWorld::Ptr& ally2 : allies2)
|
||||
{
|
||||
|
@ -747,7 +741,7 @@ namespace MWMechanics
|
|||
bool LOS = world->getLOS(actor1, actor2) && mechanicsManager->awarenessCheck(actor2, actor1);
|
||||
|
||||
if (LOS)
|
||||
mechanicsManager->startCombat(actor1, actor2, nullptr);
|
||||
mechanicsManager->startCombat(actor1, actor2, &allies2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1093,7 +1087,7 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
void Actors::updateCrimePursuit(const MWWorld::Ptr& ptr, float duration) const
|
||||
void Actors::updateCrimePursuit(const MWWorld::Ptr& ptr, float duration, SidingCache& cachedAllies) const
|
||||
{
|
||||
const MWWorld::Ptr player = getPlayer();
|
||||
if (ptr == player)
|
||||
|
@ -1133,7 +1127,7 @@ namespace MWMechanics
|
|||
= esmStore.get<ESM::GameSetting>().find("iCrimeThresholdMultiplier")->mValue.getInteger();
|
||||
if (playerStats.getBounty() >= cutoff * iCrimeThresholdMultiplier)
|
||||
{
|
||||
mechanicsManager->startCombat(ptr, player, nullptr);
|
||||
mechanicsManager->startCombat(ptr, player, &cachedAllies.getActorsSidingWith(player));
|
||||
creatureStats.setHitAttemptActorId(
|
||||
playerClass.getCreatureStats(player)
|
||||
.getActorId()); // Stops the guard from quitting combat if player is unreachable
|
||||
|
@ -1508,8 +1502,7 @@ namespace MWMechanics
|
|||
|
||||
/// \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
|
||||
SidingCache cachedAllies{ *this, true }; // will be filled as engageCombat iterates
|
||||
|
||||
const bool aiActive = MWBase::Environment::get().getMechanicsManager()->isAIActive();
|
||||
const int attackedByPlayerId = player.getClass().getCreatureStats(player).getHitAttemptActorId();
|
||||
|
@ -1597,7 +1590,7 @@ namespace MWMechanics
|
|||
updateHeadTracking(actor.getPtr(), mActors, isPlayer, ctrl);
|
||||
|
||||
if (actor.getPtr().getClass().isNpc() && !isPlayer)
|
||||
updateCrimePursuit(actor.getPtr(), duration);
|
||||
updateCrimePursuit(actor.getPtr(), duration, cachedAllies);
|
||||
|
||||
if (!isPlayer)
|
||||
{
|
||||
|
@ -2156,32 +2149,6 @@ namespace MWMechanics
|
|||
getActorsSidingWith(follower, out, excludeInfighting);
|
||||
}
|
||||
|
||||
void Actors::getActorsSidingWith(const MWWorld::Ptr& actor, std::set<MWWorld::Ptr>& out,
|
||||
std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr>>& cachedAllies) const
|
||||
{
|
||||
// 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.insert(search->second.begin(), search->second.end());
|
||||
else
|
||||
{
|
||||
for (const MWWorld::Ptr& follower : getActorsSidingWith(actor, true))
|
||||
if (out.insert(follower).second && follower != actor)
|
||||
getActorsSidingWith(follower, out, cachedAllies);
|
||||
|
||||
// Cache ptrs and their sets of allies
|
||||
cachedAllies.insert(std::make_pair(actor, out));
|
||||
for (const MWWorld::Ptr& iter : out)
|
||||
{
|
||||
if (iter == actor)
|
||||
continue;
|
||||
search = cachedAllies.find(iter);
|
||||
if (search == cachedAllies.end())
|
||||
cachedAllies.insert(std::make_pair(iter, out));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> Actors::getActorsFollowingIndices(const MWWorld::Ptr& actor) const
|
||||
{
|
||||
std::vector<int> list;
|
||||
|
@ -2380,4 +2347,32 @@ namespace MWMechanics
|
|||
seq.fastForward(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
const std::set<MWWorld::Ptr>& SidingCache::getActorsSidingWith(const MWWorld::Ptr& actor)
|
||||
{
|
||||
// If we have already found actor's allies, use the cache
|
||||
auto search = mCache.find(actor);
|
||||
if (search != mCache.end())
|
||||
return search->second;
|
||||
std::set<MWWorld::Ptr>& out = mCache[actor];
|
||||
for (const MWWorld::Ptr& follower : mActors.getActorsSidingWith(actor, mExcludeInfighting))
|
||||
{
|
||||
if (out.insert(follower).second && follower != actor)
|
||||
{
|
||||
const auto& allies = getActorsSidingWith(follower);
|
||||
out.insert(allies.begin(), allies.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Cache ptrs and their sets of allies
|
||||
for (const MWWorld::Ptr& iter : out)
|
||||
{
|
||||
if (iter == actor)
|
||||
continue;
|
||||
search = mCache.find(iter);
|
||||
if (search == mCache.end())
|
||||
mCache.emplace(iter, out);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ namespace MWMechanics
|
|||
class Actor;
|
||||
class CharacterController;
|
||||
class CreatureStats;
|
||||
class SidingCache;
|
||||
|
||||
class Actors
|
||||
{
|
||||
|
@ -182,7 +183,7 @@ namespace MWMechanics
|
|||
|
||||
void calculateRestoration(const MWWorld::Ptr& ptr, float duration) const;
|
||||
|
||||
void updateCrimePursuit(const MWWorld::Ptr& ptr, float duration) const;
|
||||
void updateCrimePursuit(const MWWorld::Ptr& ptr, float duration, SidingCache& cachedAllies) const;
|
||||
|
||||
void killDeadActors();
|
||||
|
||||
|
@ -194,13 +195,25 @@ namespace MWMechanics
|
|||
@Notes: If againstPlayer = true then actor2 should be the Player.
|
||||
If one of the combatants is creature it should be actor1.
|
||||
*/
|
||||
void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2,
|
||||
std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr>>& cachedAllies, bool againstPlayer) const;
|
||||
void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, SidingCache& cachedAllies,
|
||||
bool againstPlayer) const;
|
||||
};
|
||||
|
||||
/// Recursive version of getActorsSidingWith that takes, adds to and returns a cache of
|
||||
/// actors mapped to their allies. Excludes infighting
|
||||
void getActorsSidingWith(const MWWorld::Ptr& actor, std::set<MWWorld::Ptr>& out,
|
||||
std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr>>& cachedAllies) const;
|
||||
class SidingCache
|
||||
{
|
||||
const Actors& mActors;
|
||||
const bool mExcludeInfighting;
|
||||
std::map<MWWorld::Ptr, std::set<MWWorld::Ptr>> mCache;
|
||||
|
||||
public:
|
||||
SidingCache(const Actors& actors, bool excludeInfighting)
|
||||
: mActors(actors)
|
||||
, mExcludeInfighting(excludeInfighting)
|
||||
{
|
||||
}
|
||||
|
||||
/// Recursive version of getActorsSidingWith that takes, returns a cached set of allies
|
||||
const std::set<MWWorld::Ptr>& getActorsSidingWith(const MWWorld::Ptr& actor);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "actor.hpp"
|
||||
#include "actors.hpp"
|
||||
#include "actorutil.hpp"
|
||||
#include "aicombat.hpp"
|
||||
#include "aipursue.hpp"
|
||||
|
@ -1508,14 +1509,14 @@ namespace MWMechanics
|
|||
|
||||
if (!peaceful)
|
||||
{
|
||||
startCombat(target, attacker, nullptr);
|
||||
SidingCache cachedAllies{ mActors, false };
|
||||
const std::set<MWWorld::Ptr>& attackerAllies = cachedAllies.getActorsSidingWith(attacker);
|
||||
startCombat(target, attacker, &attackerAllies);
|
||||
// Force friendly actors into combat to prevent infighting between followers
|
||||
std::set<MWWorld::Ptr> followersTarget;
|
||||
getActorsSidingWith(target, followersTarget);
|
||||
for (const auto& follower : followersTarget)
|
||||
for (const auto& follower : cachedAllies.getActorsSidingWith(target))
|
||||
{
|
||||
if (follower != attacker && follower != player)
|
||||
startCombat(follower, attacker, nullptr);
|
||||
startCombat(follower, attacker, &attackerAllies);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue