mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-04 08:15:33 +00:00
Simplify some actor loops and avoid some redundant calculations
This commit is contained in:
parent
33535eb1bd
commit
39f8637e95
2 changed files with 123 additions and 144 deletions
|
@ -309,6 +309,12 @@ namespace MWMechanics
|
||||||
void Actors::updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor,
|
void Actors::updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor,
|
||||||
MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance)
|
MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance)
|
||||||
{
|
{
|
||||||
|
if (!actor.getRefData().getBaseNode())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (targetActor.getClass().getCreatureStats(targetActor).isDead())
|
||||||
|
return;
|
||||||
|
|
||||||
static const float fMaxHeadTrackDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
static const float fMaxHeadTrackDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
.find("fMaxHeadTrackDistance")->mValue.getFloat();
|
.find("fMaxHeadTrackDistance")->mValue.getFloat();
|
||||||
static const float fInteriorHeadTrackMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
static const float fInteriorHeadTrackMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
|
@ -318,22 +324,16 @@ namespace MWMechanics
|
||||||
if (!currentCell->isExterior() && !(currentCell->mData.mFlags & ESM::Cell::QuasiEx))
|
if (!currentCell->isExterior() && !(currentCell->mData.mFlags & ESM::Cell::QuasiEx))
|
||||||
maxDistance *= fInteriorHeadTrackMult;
|
maxDistance *= fInteriorHeadTrackMult;
|
||||||
|
|
||||||
const ESM::Position& actor1Pos = actor.getRefData().getPosition();
|
const osg::Vec3f actor1Pos(actor.getRefData().getPosition().asVec3());
|
||||||
const ESM::Position& actor2Pos = targetActor.getRefData().getPosition();
|
const osg::Vec3f actor2Pos(targetActor.getRefData().getPosition().asVec3());
|
||||||
float sqrDist = (actor1Pos.asVec3() - actor2Pos.asVec3()).length2();
|
float sqrDist = (actor1Pos - actor2Pos).length2();
|
||||||
|
|
||||||
if (sqrDist > maxDistance*maxDistance)
|
if (sqrDist > maxDistance*maxDistance)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (targetActor.getClass().getCreatureStats(targetActor).isDead())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!actor.getRefData().getBaseNode())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// stop tracking when target is behind the actor
|
// stop tracking when target is behind the actor
|
||||||
osg::Vec3f actorDirection = actor.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0);
|
osg::Vec3f actorDirection = actor.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0);
|
||||||
osg::Vec3f targetDirection (actor2Pos.asVec3() - actor1Pos.asVec3());
|
osg::Vec3f targetDirection(actor2Pos - actor1Pos);
|
||||||
actorDirection.z() = 0;
|
actorDirection.z() = 0;
|
||||||
targetDirection.z() = 0;
|
targetDirection.z() = 0;
|
||||||
actorDirection.normalize();
|
actorDirection.normalize();
|
||||||
|
@ -350,25 +350,25 @@ 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)
|
void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies, bool againstPlayer)
|
||||||
{
|
{
|
||||||
|
// No combat for totally static creatures
|
||||||
|
if (!actor1.getClass().isMobile(actor1))
|
||||||
|
return;
|
||||||
|
|
||||||
CreatureStats& creatureStats1 = actor1.getClass().getCreatureStats(actor1);
|
CreatureStats& creatureStats1 = actor1.getClass().getCreatureStats(actor1);
|
||||||
if (creatureStats1.getAiSequence().isInCombat(actor2))
|
if (creatureStats1.isDead() || creatureStats1.getAiSequence().isInCombat(actor2))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const CreatureStats& creatureStats2 = actor2.getClass().getCreatureStats(actor2);
|
const CreatureStats& creatureStats2 = actor2.getClass().getCreatureStats(actor2);
|
||||||
if (creatureStats1.isDead() || creatureStats2.isDead())
|
if (creatureStats2.isDead())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const ESM::Position& actor1Pos = actor1.getRefData().getPosition();
|
const osg::Vec3f actor1Pos(actor1.getRefData().getPosition().asVec3());
|
||||||
const ESM::Position& actor2Pos = actor2.getRefData().getPosition();
|
const osg::Vec3f actor2Pos(actor2.getRefData().getPosition().asVec3());
|
||||||
float sqrDist = (actor1Pos.asVec3() - actor2Pos.asVec3()).length2();
|
float sqrDist = (actor1Pos - actor2Pos).length2();
|
||||||
|
|
||||||
if (sqrDist > mActorsProcessingRange*mActorsProcessingRange)
|
if (sqrDist > mActorsProcessingRange*mActorsProcessingRange)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// No combat for totally static creatures
|
|
||||||
if (!actor1.getClass().isMobile(actor1))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// If this is set to true, actor1 will start combat with actor2 if the awareness check at the end of the method returns true
|
// If this is set to true, actor1 will start combat with actor2 if the awareness check at the end of the method returns true
|
||||||
bool aggressive = false;
|
bool aggressive = false;
|
||||||
|
|
||||||
|
@ -379,22 +379,22 @@ namespace MWMechanics
|
||||||
getActorsSidingWith(actor1, allies1, cachedAllies);
|
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 (const MWWorld::Ptr &ally : allies1)
|
||||||
{
|
{
|
||||||
if (creatureStats1.getAiSequence().isInCombat(*it))
|
if (creatureStats1.getAiSequence().isInCombat(ally))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (creatureStats2.matchesActorId(it->getClass().getCreatureStats(*it).getHitAttemptActorId()))
|
if (creatureStats2.matchesActorId(ally.getClass().getCreatureStats(ally).getHitAttemptActorId()))
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getMechanicsManager()->startCombat(actor1, actor2);
|
MWBase::Environment::get().getMechanicsManager()->startCombat(actor1, actor2);
|
||||||
// Also set the same hit attempt actor. Otherwise, if fighting the player, they may stop combat
|
// 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
|
// if the player gets out of reach, while the ally would continue combat with the player
|
||||||
creatureStats1.setHitAttemptActorId(it->getClass().getCreatureStats(*it).getHitAttemptActorId());
|
creatureStats1.setHitAttemptActorId(ally.getClass().getCreatureStats(ally).getHitAttemptActorId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's been no attack attempt yet but an ally of actor1 is in combat with actor2, become aggressive to actor2
|
// If there's been no attack attempt yet but an ally of actor1 is in combat with actor2, become aggressive to actor2
|
||||||
if (it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(actor2))
|
if (ally.getClass().getCreatureStats(ally).getAiSequence().isInCombat(actor2))
|
||||||
aggressive = true;
|
aggressive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,20 +415,24 @@ namespace MWMechanics
|
||||||
getActorsSidingWith(actor2, allies2, cachedAllies);
|
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 (const MWWorld::Ptr &ally2 : allies2)
|
||||||
{
|
{
|
||||||
if ((it)->getClass().getCreatureStats(*it).getAiSequence().isInCombat(actor1))
|
if (ally2.getClass().getCreatureStats(ally2).getAiSequence().isInCombat(actor1))
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getMechanicsManager()->startCombat(actor1, actor2);
|
MWBase::Environment::get().getMechanicsManager()->startCombat(actor1, actor2);
|
||||||
// Also have actor1's allies start combat
|
// Also have actor1's allies start combat
|
||||||
for (std::set<MWWorld::Ptr>::const_iterator it2 = allies1.begin(); it2 != allies1.end(); ++it2)
|
for (const MWWorld::Ptr ally1 : allies1)
|
||||||
MWBase::Environment::get().getMechanicsManager()->startCombat(*it2, actor2);
|
MWBase::Environment::get().getMechanicsManager()->startCombat(ally1, actor2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop here if target is unreachable
|
||||||
|
if (!canFight(actor1, actor2))
|
||||||
|
return;
|
||||||
|
|
||||||
// If set in the settings file, player followers and escorters will become aggressive toward enemies in combat with them or the player
|
// If set in the settings file, player followers and escorters will become aggressive toward enemies in combat with them or the player
|
||||||
static const bool followersAttackOnSight = Settings::Manager::getBool("followers attack on sight", "Game");
|
static const bool followersAttackOnSight = Settings::Manager::getBool("followers attack on sight", "Game");
|
||||||
if (!aggressive && isPlayerFollowerOrEscorter && followersAttackOnSight)
|
if (!aggressive && isPlayerFollowerOrEscorter && followersAttackOnSight)
|
||||||
|
@ -437,9 +441,9 @@ namespace MWMechanics
|
||||||
aggressive = true;
|
aggressive = true;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (std::set<MWWorld::Ptr>::const_iterator it = allies1.begin(); it != allies1.end(); ++it)
|
for (const MWWorld::Ptr &ally : allies1)
|
||||||
{
|
{
|
||||||
if (actor2.getClass().getCreatureStats(actor2).getAiSequence().isInCombat(*it))
|
if (actor2.getClass().getCreatureStats(actor2).getAiSequence().isInCombat(ally))
|
||||||
{
|
{
|
||||||
aggressive = true;
|
aggressive = true;
|
||||||
break;
|
break;
|
||||||
|
@ -448,10 +452,6 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop here if target is unreachable
|
|
||||||
if (!MWMechanics::canFight(actor1, actor2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// 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)
|
||||||
{
|
{
|
||||||
|
@ -465,7 +465,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make guards go aggressive with creatures that are in combat, unless the creature is a follower or escorter
|
// Make guards go aggressive with creatures that are in combat, unless the creature is a follower or escorter
|
||||||
if (actor1.getClass().isClass(actor1, "Guard") && !actor2.getClass().isNpc())
|
if (!aggressive && actor1.getClass().isClass(actor1, "Guard") && !actor2.getClass().isNpc() && creatureStats2.getAiSequence().isInCombat())
|
||||||
{
|
{
|
||||||
// Check if the creature is too far
|
// Check if the creature is too far
|
||||||
static const float fAlarmRadius = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fAlarmRadius")->mValue.getFloat();
|
static const float fAlarmRadius = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fAlarmRadius")->mValue.getFloat();
|
||||||
|
@ -473,18 +473,18 @@ namespace MWMechanics
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool followerOrEscorter = false;
|
bool followerOrEscorter = false;
|
||||||
for (std::list<MWMechanics::AiPackage*>::const_iterator it = creatureStats2.getAiSequence().begin(); it != creatureStats2.getAiSequence().end(); ++it)
|
for (const AiPackage* package : creatureStats2.getAiSequence())
|
||||||
{
|
{
|
||||||
// The follow package must be first or have nothing but combat before it
|
// The follow package must be first or have nothing but combat before it
|
||||||
if ((*it)->sideWithTarget())
|
if (package->sideWithTarget())
|
||||||
{
|
{
|
||||||
followerOrEscorter = true;
|
followerOrEscorter = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
|
else if (package->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!followerOrEscorter && creatureStats2.getAiSequence().isInCombat())
|
if (!followerOrEscorter)
|
||||||
aggressive = true;
|
aggressive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -927,14 +927,11 @@ namespace MWMechanics
|
||||||
if (stats.getTimeToStartDrowning() == -1.f)
|
if (stats.getTimeToStartDrowning() == -1.f)
|
||||||
stats.setTimeToStartDrowning(fHoldBreathTime);
|
stats.setTimeToStartDrowning(fHoldBreathTime);
|
||||||
|
|
||||||
if (stats.getTimeToStartDrowning() < fHoldBreathTime / 2)
|
if (!isPlayer && stats.getTimeToStartDrowning() < fHoldBreathTime / 2)
|
||||||
{
|
{
|
||||||
if(!isPlayer)
|
AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence();
|
||||||
{
|
if (seq.getTypeId() != AiPackage::TypeIdBreathe) //Only add it once
|
||||||
MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence();
|
seq.stack(AiBreathe(), ptr);
|
||||||
if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdBreathe) //Only add it once
|
|
||||||
seq.stack(MWMechanics::AiBreathe(), ptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
|
@ -1200,17 +1197,16 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise check if any actor in AI processing range sees the target actor
|
// Otherwise check if any actor in AI processing range sees the target actor
|
||||||
std::vector<MWWorld::Ptr> actors;
|
std::vector<MWWorld::Ptr> neighbors;
|
||||||
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
|
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
|
||||||
getObjectsInRange(position, mActorsProcessingRange, actors);
|
getObjectsInRange(position, mActorsProcessingRange, neighbors);
|
||||||
for(std::vector<MWWorld::Ptr>::iterator it = actors.begin(); it != actors.end(); ++it)
|
for (const MWWorld::Ptr &neighbor : neighbors)
|
||||||
{
|
{
|
||||||
if (*it == actor)
|
if (neighbor == actor)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bool result =
|
bool result = MWBase::Environment::get().getWorld()->getLOS(neighbor, actor);
|
||||||
MWBase::Environment::get().getWorld()->getLOS(*it, actor) &&
|
result &= MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor, neighbor);
|
||||||
MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor, *it);
|
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
return true;
|
return true;
|
||||||
|
@ -1830,21 +1826,21 @@ namespace MWMechanics
|
||||||
|
|
||||||
// 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
|
// 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
|
// Actors that are targeted by this actor's Follow or Escort packages also side with them
|
||||||
for (auto package = stats.getAiSequence().begin(); package != stats.getAiSequence().end(); ++package)
|
for (const AiPackage* package : stats.getAiSequence())
|
||||||
{
|
{
|
||||||
if ((*package)->sideWithTarget() && !(*package)->getTarget().isEmpty())
|
if (package->sideWithTarget() && !package->getTarget().isEmpty())
|
||||||
{
|
{
|
||||||
if (sameActor)
|
if (sameActor)
|
||||||
{
|
{
|
||||||
list.push_back((*package)->getTarget());
|
list.push_back(package->getTarget());
|
||||||
}
|
}
|
||||||
else if ((*package)->getTarget() == actor)
|
else if (package->getTarget() == actor)
|
||||||
{
|
{
|
||||||
list.push_back(iteratedActor);
|
list.push_back(iteratedActor);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if ((*package)->getTypeId() != AiPackage::TypeIdCombat && (*package)->getTypeId() != AiPackage::TypeIdWander)
|
else if (package->getTypeId() != AiPackage::TypeIdCombat && package->getTypeId() != AiPackage::TypeIdWander)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1866,11 +1862,11 @@ namespace MWMechanics
|
||||||
|
|
||||||
// An actor counts as following if AiFollow is the current AiPackage,
|
// An actor counts as following if AiFollow is the current AiPackage,
|
||||||
// or there are only Combat and Wander packages before the AiFollow package
|
// or there are only Combat and Wander packages before the AiFollow package
|
||||||
for (auto package = stats.getAiSequence().begin(); package != stats.getAiSequence().end(); ++package)
|
for (const AiPackage* package : stats.getAiSequence())
|
||||||
{
|
{
|
||||||
if ((*package)->followTargetThroughDoors() && (*package)->getTarget() == actor)
|
if (package->followTargetThroughDoors() && package->getTarget() == actor)
|
||||||
list.push_back(iteratedActor);
|
list.push_back(iteratedActor);
|
||||||
else if ((*package)->getTypeId() != AiPackage::TypeIdCombat && (*package)->getTypeId() != AiPackage::TypeIdWander)
|
else if (package->getTypeId() != AiPackage::TypeIdCombat && package->getTypeId() != AiPackage::TypeIdWander)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1879,16 +1875,16 @@ namespace MWMechanics
|
||||||
|
|
||||||
void Actors::getActorsFollowing(const MWWorld::Ptr &actor, std::set<MWWorld::Ptr>& out) {
|
void Actors::getActorsFollowing(const MWWorld::Ptr &actor, std::set<MWWorld::Ptr>& out) {
|
||||||
std::list<MWWorld::Ptr> followers = getActorsFollowing(actor);
|
std::list<MWWorld::Ptr> followers = getActorsFollowing(actor);
|
||||||
for(std::list<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();++it)
|
for(const MWWorld::Ptr &follower : followers)
|
||||||
if (out.insert(*it).second)
|
if (out.insert(follower).second)
|
||||||
getActorsFollowing(*it, out);
|
getActorsFollowing(follower, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::getActorsSidingWith(const MWWorld::Ptr &actor, std::set<MWWorld::Ptr>& out) {
|
void Actors::getActorsSidingWith(const MWWorld::Ptr &actor, std::set<MWWorld::Ptr>& out) {
|
||||||
std::list<MWWorld::Ptr> followers = getActorsSidingWith(actor);
|
std::list<MWWorld::Ptr> followers = getActorsSidingWith(actor);
|
||||||
for(std::list<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();++it)
|
for(const MWWorld::Ptr &follower : followers)
|
||||||
if (out.insert(*it).second)
|
if (out.insert(follower).second)
|
||||||
getActorsSidingWith(*it, out);
|
getActorsSidingWith(follower, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::getActorsSidingWith(const MWWorld::Ptr &actor, std::set<MWWorld::Ptr>& out, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies) {
|
void Actors::getActorsSidingWith(const MWWorld::Ptr &actor, std::set<MWWorld::Ptr>& out, std::map<const MWWorld::Ptr, const std::set<MWWorld::Ptr> >& cachedAllies) {
|
||||||
|
@ -1899,17 +1895,17 @@ namespace MWMechanics
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::list<MWWorld::Ptr> followers = getActorsSidingWith(actor);
|
std::list<MWWorld::Ptr> followers = getActorsSidingWith(actor);
|
||||||
for (std::list<MWWorld::Ptr>::iterator it = followers.begin(); it != followers.end(); ++it)
|
for (const MWWorld::Ptr &follower : followers)
|
||||||
if (out.insert(*it).second)
|
if (out.insert(follower).second)
|
||||||
getActorsSidingWith(*it, out, cachedAllies);
|
getActorsSidingWith(follower, out, cachedAllies);
|
||||||
|
|
||||||
// Cache ptrs and their sets of allies
|
// Cache ptrs and their sets of allies
|
||||||
cachedAllies.insert(std::make_pair(actor, out));
|
cachedAllies.insert(std::make_pair(actor, out));
|
||||||
for (std::set<MWWorld::Ptr>::const_iterator it = out.begin(); it != out.end(); ++it)
|
for (const MWWorld::Ptr &iter : out)
|
||||||
{
|
{
|
||||||
search = cachedAllies.find(*it);
|
search = cachedAllies.find(iter);
|
||||||
if (search == cachedAllies.end())
|
if (search == cachedAllies.end())
|
||||||
cachedAllies.insert(std::make_pair(*it, out));
|
cachedAllies.insert(std::make_pair(iter, out));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1929,14 +1925,14 @@ namespace MWMechanics
|
||||||
|
|
||||||
// An actor counts as following if AiFollow is the current AiPackage,
|
// An actor counts as following if AiFollow is the current AiPackage,
|
||||||
// or there are only Combat and Wander packages before the AiFollow package
|
// or there are only Combat and Wander packages before the AiFollow package
|
||||||
for (auto package = stats.getAiSequence().begin(); package != stats.getAiSequence().end(); ++package)
|
for (AiPackage* package : stats.getAiSequence())
|
||||||
{
|
{
|
||||||
if ((*package)->followTargetThroughDoors() && (*package)->getTarget() == actor)
|
if (package->followTargetThroughDoors() && package->getTarget() == actor)
|
||||||
{
|
{
|
||||||
list.push_back(static_cast<AiFollow*>(*package)->getFollowIndex());
|
list.push_back(static_cast<AiFollow*>(package)->getFollowIndex());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if ((*package)->getTypeId() != AiPackage::TypeIdCombat && (*package)->getTypeId() != AiPackage::TypeIdWander)
|
else if (package->getTypeId() != AiPackage::TypeIdCombat && package->getTypeId() != AiPackage::TypeIdWander)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1948,17 +1944,17 @@ namespace MWMechanics
|
||||||
std::vector<MWWorld::Ptr> neighbors;
|
std::vector<MWWorld::Ptr> neighbors;
|
||||||
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
|
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
|
||||||
getObjectsInRange(position, mActorsProcessingRange, neighbors);
|
getObjectsInRange(position, mActorsProcessingRange, neighbors);
|
||||||
for(auto neighbor = neighbors.begin(); neighbor != neighbors.end(); ++neighbor)
|
for(const MWWorld::Ptr neighbor : neighbors)
|
||||||
{
|
{
|
||||||
if (*neighbor == actor)
|
if (neighbor == actor)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const CreatureStats &stats = neighbor->getClass().getCreatureStats(*neighbor);
|
const CreatureStats &stats = neighbor.getClass().getCreatureStats(neighbor);
|
||||||
if (stats.isDead())
|
if (stats.isDead())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (stats.getAiSequence().isInCombat(actor))
|
if (stats.getAiSequence().isInCombat(actor))
|
||||||
list.push_front(*neighbor);
|
list.push_front(neighbor);
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,10 +129,9 @@ namespace MWMechanics
|
||||||
npcStats.getSkill (i).setBase (5 + bonus);
|
npcStats.getSkill (i).setBase (5 + bonus);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator iter (race->mPowers.mList.begin());
|
for (const std::string power : race->mPowers.mList)
|
||||||
iter!=race->mPowers.mList.end(); ++iter)
|
|
||||||
{
|
{
|
||||||
creatureStats.getSpells().add (*iter);
|
creatureStats.getSpells().add(power);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,10 +144,9 @@ namespace MWMechanics
|
||||||
const ESM::BirthSign *sign =
|
const ESM::BirthSign *sign =
|
||||||
esmStore.get<ESM::BirthSign>().find(signId);
|
esmStore.get<ESM::BirthSign>().find(signId);
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator iter (sign->mPowers.mList.begin());
|
for (const std::string power : sign->mPowers.mList)
|
||||||
iter!=sign->mPowers.mList.end(); ++iter)
|
|
||||||
{
|
{
|
||||||
creatureStats.getSpells().add (*iter);
|
creatureStats.getSpells().add(power);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,8 +216,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
std::vector<std::string> selectedSpells = autoCalcPlayerSpells(skills, attributes, race);
|
std::vector<std::string> selectedSpells = autoCalcPlayerSpells(skills, attributes, race);
|
||||||
|
|
||||||
for (std::vector<std::string>::iterator it = selectedSpells.begin(); it != selectedSpells.end(); ++it)
|
for (const std::string spell : selectedSpells)
|
||||||
creatureStats.getSpells().add(*it);
|
creatureStats.getSpells().add(spell);
|
||||||
|
|
||||||
// forced update and current value adjustments
|
// forced update and current value adjustments
|
||||||
mActors.updateActor (ptr, 0);
|
mActors.updateActor (ptr, 0);
|
||||||
|
@ -887,9 +885,8 @@ namespace MWMechanics
|
||||||
// Build a list of known bound item ID's
|
// Build a list of known bound item ID's
|
||||||
const MWWorld::Store<ESM::GameSetting> &gameSettings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
const MWWorld::Store<ESM::GameSetting> &gameSettings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
for (MWWorld::Store<ESM::GameSetting>::iterator currentIteration = gameSettings.begin(); currentIteration != gameSettings.end(); ++currentIteration)
|
for (const ESM::GameSetting ¤tSetting : gameSettings)
|
||||||
{
|
{
|
||||||
const ESM::GameSetting ¤tSetting = *currentIteration;
|
|
||||||
std::string currentGMSTID = currentSetting.mId;
|
std::string currentGMSTID = currentSetting.mId;
|
||||||
Misc::StringUtils::lowerCaseInPlace(currentGMSTID);
|
Misc::StringUtils::lowerCaseInPlace(currentGMSTID);
|
||||||
|
|
||||||
|
@ -1209,36 +1206,20 @@ namespace MWMechanics
|
||||||
|
|
||||||
// Did anyone see it?
|
// Did anyone see it?
|
||||||
bool crimeSeen = false;
|
bool crimeSeen = false;
|
||||||
for (std::vector<MWWorld::Ptr>::iterator it = neighbors.begin(); it != neighbors.end(); ++it)
|
for (const MWWorld::Ptr &neighbor : neighbors)
|
||||||
{
|
{
|
||||||
if (*it == player)
|
if (!canReportCrime(neighbor, victim, playerFollowers))
|
||||||
continue; // skip player
|
|
||||||
if (it->getClass().getCreatureStats(*it).isDead())
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Unconsious actor can not report about crime
|
if ((neighbor == victim && victimAware)
|
||||||
if (it->getClass().getCreatureStats(*it).getKnockedDown())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((*it == victim && victimAware)
|
|
||||||
|| (MWBase::Environment::get().getWorld()->getLOS(player, *it) && awarenessCheck(player, *it) )
|
|
||||||
// Murder crime can be reported even if no one saw it (hearing is enough, I guess).
|
// Murder crime can be reported even if no one saw it (hearing is enough, I guess).
|
||||||
// TODO: Add mod support for stealth executions!
|
// TODO: Add mod support for stealth executions!
|
||||||
|| (type == OT_Murder && *it != victim))
|
|| (type == OT_Murder && neighbor != victim)
|
||||||
|
|| (MWBase::Environment::get().getWorld()->getLOS(player, neighbor) && awarenessCheck(player, neighbor)))
|
||||||
{
|
{
|
||||||
// Crime reporting only applies to NPCs
|
|
||||||
if (!it->getClass().isNpc())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(victim))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (playerFollowers.find(*it) != playerFollowers.end())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// NPC will complain about theft even if he will do nothing about it
|
// NPC will complain about theft even if he will do nothing about it
|
||||||
if (type == OT_Theft || type == OT_Pickpocket)
|
if (type == OT_Theft || type == OT_Pickpocket)
|
||||||
MWBase::Environment::get().getDialogueManager()->say(*it, "thief");
|
MWBase::Environment::get().getDialogueManager()->say(neighbor, "thief");
|
||||||
|
|
||||||
crimeSeen = true;
|
crimeSeen = true;
|
||||||
}
|
}
|
||||||
|
@ -1361,66 +1342,66 @@ namespace MWMechanics
|
||||||
getActorsSidingWith(player, playerFollowers);
|
getActorsSidingWith(player, playerFollowers);
|
||||||
|
|
||||||
// Tell everyone (including the original reporter) in alarm range
|
// Tell everyone (including the original reporter) in alarm range
|
||||||
for (std::vector<MWWorld::Ptr>::iterator it = neighbors.begin(); it != neighbors.end(); ++it)
|
for (const MWWorld::Ptr &actor : neighbors)
|
||||||
{
|
{
|
||||||
if (!canReportCrime(*it, victim, playerFollowers))
|
if (!canReportCrime(actor, victim, playerFollowers))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Will the witness report the crime?
|
// Will the witness report the crime?
|
||||||
if (it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase() >= 100)
|
if (actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Alarm).getBase() >= 100)
|
||||||
{
|
{
|
||||||
reported = true;
|
reported = true;
|
||||||
|
|
||||||
if (type == OT_Trespassing)
|
if (type == OT_Trespassing)
|
||||||
MWBase::Environment::get().getDialogueManager()->say(*it, "intruder");
|
MWBase::Environment::get().getDialogueManager()->say(actor, "intruder");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::vector<MWWorld::Ptr>::iterator it = neighbors.begin(); it != neighbors.end(); ++it)
|
for (const MWWorld::Ptr &actor : neighbors)
|
||||||
{
|
{
|
||||||
if (!canReportCrime(*it, victim, playerFollowers))
|
if (!canReportCrime(actor, victim, playerFollowers))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (it->getClass().isClass(*it, "guard") && reported)
|
if (reported && actor.getClass().isClass(actor, "guard"))
|
||||||
{
|
{
|
||||||
// Mark as Alarmed for dialogue
|
// Mark as Alarmed for dialogue
|
||||||
it->getClass().getCreatureStats(*it).setAlarmed(true);
|
actor.getClass().getCreatureStats(actor).setAlarmed(true);
|
||||||
|
|
||||||
// Set the crime ID, which we will use to calm down participants
|
// Set the crime ID, which we will use to calm down participants
|
||||||
// once the bounty has been paid.
|
// once the bounty has been paid.
|
||||||
it->getClass().getNpcStats(*it).setCrimeId(id);
|
actor.getClass().getNpcStats(actor).setCrimeId(id);
|
||||||
|
|
||||||
if (!it->getClass().getCreatureStats(*it).getAiSequence().hasPackage(AiPackage::TypeIdPursue))
|
if (!actor.getClass().getCreatureStats(actor).getAiSequence().hasPackage(AiPackage::TypeIdPursue))
|
||||||
{
|
{
|
||||||
it->getClass().getCreatureStats(*it).getAiSequence().stack(AiPursue(player), *it);
|
actor.getClass().getCreatureStats(actor).getAiSequence().stack(AiPursue(player), actor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float dispTerm = (*it == victim) ? dispVictim : disp;
|
float dispTerm = (actor == victim) ? dispVictim : disp;
|
||||||
|
|
||||||
float alarmTerm = 0.01f * it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase();
|
float alarmTerm = 0.01f * actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Alarm).getBase();
|
||||||
if (type == OT_Pickpocket && alarmTerm <= 0)
|
if (type == OT_Pickpocket && alarmTerm <= 0)
|
||||||
alarmTerm = 1.0;
|
alarmTerm = 1.0;
|
||||||
|
|
||||||
if (*it != victim)
|
if (actor != victim)
|
||||||
dispTerm *= alarmTerm;
|
dispTerm *= alarmTerm;
|
||||||
|
|
||||||
float fightTerm = static_cast<float>((*it == victim) ? fightVictim : fight);
|
float fightTerm = static_cast<float>((actor == victim) ? fightVictim : fight);
|
||||||
fightTerm += getFightDispositionBias(dispTerm);
|
fightTerm += getFightDispositionBias(dispTerm);
|
||||||
fightTerm += getFightDistanceBias(*it, player);
|
fightTerm += getFightDistanceBias(actor, player);
|
||||||
fightTerm *= alarmTerm;
|
fightTerm *= alarmTerm;
|
||||||
|
|
||||||
int observerFightRating = it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Fight).getBase();
|
int observerFightRating = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Fight).getBase();
|
||||||
if (observerFightRating + fightTerm > 100)
|
if (observerFightRating + fightTerm > 100)
|
||||||
fightTerm = static_cast<float>(100 - observerFightRating);
|
fightTerm = static_cast<float>(100 - observerFightRating);
|
||||||
fightTerm = std::max(0.f, fightTerm);
|
fightTerm = std::max(0.f, fightTerm);
|
||||||
|
|
||||||
if (observerFightRating + fightTerm >= 100)
|
if (observerFightRating + fightTerm >= 100)
|
||||||
{
|
{
|
||||||
startCombat(*it, player);
|
startCombat(actor, player);
|
||||||
|
|
||||||
NpcStats& observerStats = it->getClass().getNpcStats(*it);
|
NpcStats& observerStats = actor.getClass().getNpcStats(actor);
|
||||||
// Apply aggression value to the base Fight rating, so that the actor can continue fighting
|
// Apply aggression value to the base Fight rating, so that the actor can continue fighting
|
||||||
// after a Calm spell wears off
|
// after a Calm spell wears off
|
||||||
observerStats.setAiSetting(CreatureStats::AI_Fight, observerFightRating + static_cast<int>(fightTerm));
|
observerStats.setAiSetting(CreatureStats::AI_Fight, observerFightRating + static_cast<int>(fightTerm));
|
||||||
|
@ -1527,7 +1508,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool MechanicsManager::canCommitCrimeAgainst(const MWWorld::Ptr &target, const MWWorld::Ptr &attacker)
|
bool MechanicsManager::canCommitCrimeAgainst(const MWWorld::Ptr &target, const MWWorld::Ptr &attacker)
|
||||||
{
|
{
|
||||||
MWMechanics::AiSequence seq = target.getClass().getCreatureStats(target).getAiSequence();
|
const MWMechanics::AiSequence& seq = target.getClass().getCreatureStats(target).getAiSequence();
|
||||||
return target.getClass().isNpc() && !attacker.isEmpty() && !seq.isInCombat(attacker)
|
return target.getClass().isNpc() && !attacker.isEmpty() && !seq.isInCombat(attacker)
|
||||||
&& !isAggressive(target, attacker) && !seq.isEngagedWithActor()
|
&& !isAggressive(target, attacker) && !seq.isEngagedWithActor()
|
||||||
&& !target.getClass().getCreatureStats(target).getAiSequence().hasPackage(AiPackage::TypeIdPursue);
|
&& !target.getClass().getCreatureStats(target).getAiSequence().hasPackage(AiPackage::TypeIdPursue);
|
||||||
|
@ -1871,23 +1852,25 @@ namespace MWMechanics
|
||||||
windowManager->setWerewolfOverlay(werewolf);
|
windowManager->setWerewolfOverlay(werewolf);
|
||||||
|
|
||||||
// Witnesses of the player's transformation will make them a globally known werewolf
|
// Witnesses of the player's transformation will make them a globally known werewolf
|
||||||
std::vector<MWWorld::Ptr> closeActors;
|
std::vector<MWWorld::Ptr> neighbors;
|
||||||
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
getActorsInRange(actor.getRefData().getPosition().asVec3(), gmst.find("fAlarmRadius")->mValue.getFloat(), closeActors);
|
getActorsInRange(actor.getRefData().getPosition().asVec3(), gmst.find("fAlarmRadius")->mValue.getFloat(), neighbors);
|
||||||
|
|
||||||
bool detected = false, reported = false;
|
bool detected = false, reported = false;
|
||||||
for (std::vector<MWWorld::Ptr>::const_iterator it = closeActors.begin(); it != closeActors.end(); ++it)
|
for (const MWWorld::Ptr& neighbor : neighbors)
|
||||||
{
|
{
|
||||||
if (*it == actor)
|
if (neighbor == actor || !neighbor.getClass().isNpc())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!it->getClass().isNpc())
|
if (MWBase::Environment::get().getWorld()->getLOS(neighbor, actor) && awarenessCheck(actor, neighbor))
|
||||||
continue;
|
{
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWorld()->getLOS(*it, actor) && awarenessCheck(actor, *it))
|
|
||||||
detected = true;
|
detected = true;
|
||||||
if (it->getClass().getCreatureStats(*it).getAiSetting(MWMechanics::CreatureStats::AI_Alarm).getModified() > 0)
|
if (neighbor.getClass().getCreatureStats(neighbor).getAiSetting(MWMechanics::CreatureStats::AI_Alarm).getModified() > 0)
|
||||||
reported = true;
|
{
|
||||||
|
reported = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (detected)
|
if (detected)
|
||||||
|
|
Loading…
Reference in a new issue