Merged pull request #1866

pull/540/head
Marc Zinnschlag 6 years ago
commit 3489951410

@ -41,6 +41,7 @@
Bug #4286: Scripted animations can be interrupted
Bug #4291: Non-persistent actors that started the game as dead do not play death animations
Bug #4293: Faction members are not aware of faction ownerships in barter
Bug #4304: "Follow" not working as a second AI package
Bug #4307: World cleanup should remove dead bodies only if death animation is finished
Bug #4311: OpenMW does not handle RootCollisionNode correctly
Bug #4327: Missing animations during spell/weapon stance switching

@ -2,7 +2,6 @@
#include <typeinfo>
#include <iostream>
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
#include <components/esm/loadnpc.hpp>
@ -404,7 +403,7 @@ namespace MWMechanics
std::set<MWWorld::Ptr> playerAllies;
getActorsSidingWith(MWMechanics::getPlayer(), playerAllies, cachedAllies);
bool isPlayerFollowerOrEscorter = std::find(playerAllies.begin(), playerAllies.end(), actor1) != playerAllies.end();
bool isPlayerFollowerOrEscorter = playerAllies.find(actor1) != playerAllies.end();
// 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
@ -458,7 +457,7 @@ namespace MWMechanics
// Do aggression check if actor2 is the player or a player follower or escorter
if (!aggressive)
{
if (againstPlayer || std::find(playerAllies.begin(), playerAllies.end(), actor2) != playerAllies.end())
if (againstPlayer || playerAllies.find(actor2) != playerAllies.end())
{
// Player followers and escorters with high fight should not initiate combat with the player or with
// other player followers or escorters
@ -1777,38 +1776,35 @@ namespace MWMechanics
std::list<MWWorld::Ptr> Actors::getActorsSidingWith(const MWWorld::Ptr& actor)
{
std::list<MWWorld::Ptr> list;
for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
for(PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
{
const MWWorld::Class &cls = iter->first.getClass();
const CreatureStats &stats = cls.getCreatureStats(iter->first);
const MWWorld::Ptr &iteratedActor = iter->first;
if (iteratedActor == getPlayer())
continue;
const CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor);
if (stats.isDead())
continue;
// An actor counts as siding with this actor if Follow or Escort is the current AI package, or there are only Combat packages before the Follow/Escort package
for (std::list<MWMechanics::AiPackage*>::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it)
{
if ((*it)->sideWithTarget() && (*it)->getTarget() == actor)
{
list.push_back(iter->first);
break;
}
else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
break;
}
// An actor counts as siding with this actor if Follow or Escort is the current AI package, or there are only Combat and Wander packages before the Follow/Escort package
// Actors that are targeted by this actor's Follow or Escort packages also side with them
if (actor != getPlayer())
for (auto package = stats.getAiSequence().begin(); package != stats.getAiSequence().end(); ++package)
{
const CreatureStats &stats2 = actor.getClass().getCreatureStats(actor);
for (std::list<MWMechanics::AiPackage*>::const_iterator it2 = stats2.getAiSequence().begin(); it2 != stats2.getAiSequence().end(); ++it2)
const MWWorld::Ptr &target = (*package)->getTarget();
if ((*package)->sideWithTarget() && !target.isEmpty())
{
if ((*it2)->sideWithTarget() && !(*it2)->getTarget().isEmpty())
if (iteratedActor == actor)
{
list.push_back((*it2)->getTarget());
break;
list.push_back(target);
}
else if ((*it2)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
break;
else if (target == actor)
{
list.push_back(iteratedActor);
}
break;
}
else if ((*package)->getTypeId() != AiPackage::TypeIdCombat && (*package)->getTypeId() != AiPackage::TypeIdWander)
break;
}
}
return list;
@ -1819,17 +1815,21 @@ namespace MWMechanics
std::list<MWWorld::Ptr> list;
for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
{
const MWWorld::Class &cls = iter->first.getClass();
CreatureStats &stats = cls.getCreatureStats(iter->first);
const MWWorld::Ptr &iteratedActor = iter->first;
if (iteratedActor == getPlayer())
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 packages before the AiFollow package
for (std::list<MWMechanics::AiPackage*>::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it)
// An actor counts as following if AiFollow is the current AiPackage,
// or there are only Combat and Wander packages before the AiFollow package
for (auto package = stats.getAiSequence().begin(); package != stats.getAiSequence().end(); ++package)
{
if ((*it)->followTargetThroughDoors() && (*it)->getTarget() == actor)
list.push_back(iter->first);
else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
if ((*package)->followTargetThroughDoors() && (*package)->getTarget() == actor)
list.push_back(iteratedActor);
else if ((*package)->getTypeId() != AiPackage::TypeIdCombat && (*package)->getTypeId() != AiPackage::TypeIdWander)
break;
}
}
@ -1878,24 +1878,24 @@ namespace MWMechanics
std::list<int> list;
for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
{
const MWWorld::Class &cls = iter->first.getClass();
CreatureStats &stats = cls.getCreatureStats(iter->first);
const MWWorld::Ptr &iteratedActor = iter->first;
if (iteratedActor == getPlayer())
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 packages before the AiFollow package
for (std::list<MWMechanics::AiPackage*>::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it)
// An actor counts as following if AiFollow is the current AiPackage,
// or there are only Combat and Wander packages before the AiFollow package
for (auto package = stats.getAiSequence().begin(); package != stats.getAiSequence().end(); ++package)
{
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow)
if ((*package)->followTargetThroughDoors() && (*package)->getTarget() == actor)
{
MWWorld::Ptr followTarget = (*it)->getTarget();
if (followTarget.isEmpty())
continue;
if (followTarget == actor)
list.push_back(static_cast<MWMechanics::AiFollow*>(*it)->getFollowIndex());
list.push_back(static_cast<AiFollow*>(*package)->getFollowIndex());
break;
}
else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
else if ((*package)->getTypeId() != AiPackage::TypeIdCombat && (*package)->getTypeId() != AiPackage::TypeIdWander)
break;
}
}
@ -1907,14 +1907,14 @@ namespace MWMechanics
std::vector<MWWorld::Ptr> neighbors;
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
getObjectsInRange(position, aiProcessingDistance, neighbors);
for(std::vector<MWWorld::Ptr>::const_iterator iter(neighbors.begin());iter != neighbors.end();++iter)
for(auto neighbor = neighbors.begin(); neighbor != neighbors.end(); ++neighbor)
{
const MWWorld::Class &cls = iter->getClass();
const CreatureStats &stats = cls.getCreatureStats(*iter);
if (stats.isDead() || *iter == actor)
const CreatureStats &stats = neighbor->getClass().getCreatureStats(*neighbor);
if (stats.isDead() || *neighbor == actor)
continue;
if (stats.getAiSequence().isInCombat(actor))
list.push_front(*iter);
list.push_front(*neighbor);
}
return list;
}
@ -1926,15 +1926,18 @@ namespace MWMechanics
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
getObjectsInRange(position, aiProcessingDistance, neighbors);
std::list<MWWorld::Ptr> followers = getActorsFollowing(actor);
for(std::vector<MWWorld::Ptr>::const_iterator iter(neighbors.begin());iter != neighbors.end();++iter)
std::set<MWWorld::Ptr> followers;
getActorsFollowing(actor, followers);
for (auto neighbor = neighbors.begin(); neighbor != neighbors.end(); ++neighbor)
{
const CreatureStats &stats = iter->getClass().getCreatureStats(*iter);
if (stats.isDead() || *iter == actor || iter->getClass().isPureWaterCreature(*iter))
const CreatureStats &stats = neighbor->getClass().getCreatureStats(*neighbor);
if (stats.isDead() || *neighbor == actor || neighbor->getClass().isPureWaterCreature(*neighbor))
continue;
const bool isFollower = std::find(followers.begin(), followers.end(), *iter) != followers.end();
if (stats.getAiSequence().isInCombat(actor) || (MWBase::Environment::get().getMechanicsManager()->isAggressive(*iter, actor) && !isFollower))
list.push_back(*iter);
const bool isFollower = followers.find(*neighbor) != followers.end();
if (stats.getAiSequence().isInCombat(actor) || (MWBase::Environment::get().getMechanicsManager()->isAggressive(*neighbor, actor) && !isFollower))
list.push_back(*neighbor);
}
return list;
}

@ -1,6 +1,7 @@
#include "mechanicsmanagerimp.hpp"
#include <limits.h>
#include <set>
#include <components/misc/rng.hpp>
@ -1445,11 +1446,12 @@ namespace MWMechanics
if (target == getPlayer() || !attacker.getClass().isActor())
return false;
std::list<MWWorld::Ptr> followersAttacker = getActorsSidingWith(attacker);
std::set<MWWorld::Ptr> followersAttacker;
getActorsSidingWith(attacker, followersAttacker);
MWMechanics::CreatureStats& statsTarget = target.getClass().getCreatureStats(target);
if (std::find(followersAttacker.begin(), followersAttacker.end(), target) != followersAttacker.end())
if (followersAttacker.find(target) != followersAttacker.end())
{
statsTarget.friendlyHit();

Loading…
Cancel
Save