|
|
@ -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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -800,6 +803,12 @@ namespace MWMechanics
|
|
|
|
CharacterController* ctrl = it->second->getCharacterController();
|
|
|
|
CharacterController* ctrl = it->second->getCharacterController();
|
|
|
|
|
|
|
|
|
|
|
|
NpcStats &stats = ptr.getClass().getNpcStats(ptr);
|
|
|
|
NpcStats &stats = ptr.getClass().getNpcStats(ptr);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// When npc stats are just initialized, mTimeToStartDrowning == -1 and we should get value from GMST
|
|
|
|
|
|
|
|
static const int fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fHoldBreathTime")->getFloat();
|
|
|
|
|
|
|
|
if (stats.getTimeToStartDrowning() == -1.f)
|
|
|
|
|
|
|
|
stats.setTimeToStartDrowning(fHoldBreathTime);
|
|
|
|
|
|
|
|
|
|
|
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
|
|
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
|
|
|
bool knockedOutUnderwater = (ctrl->isKnockedOut() && world->isUnderwater(ptr.getCell(), osg::Vec3f(ptr.getRefData().getPosition().asVec3())));
|
|
|
|
bool knockedOutUnderwater = (ctrl->isKnockedOut() && world->isUnderwater(ptr.getCell(), osg::Vec3f(ptr.getRefData().getPosition().asVec3())));
|
|
|
|
if((world->isSubmerged(ptr) || knockedOutUnderwater)
|
|
|
|
if((world->isSubmerged(ptr) || knockedOutUnderwater)
|
|
|
@ -1075,6 +1084,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 +1137,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 +1602,29 @@ 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) {
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
std::list<MWWorld::Ptr> followers = getActorsSidingWith(actor);
|
|
|
|
|
|
|
|
for (std::list<MWWorld::Ptr>::iterator it = followers.begin(); it != followers.end(); ++it)
|
|
|
|
|
|
|
|
if (out.insert(*it).second)
|
|
|
|
|
|
|
|
getActorsSidingWith(*it, out, cachedAllies);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|