mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-31 14:36:39 +00:00
Use std::list to store mechanics actors
To make the order of elements deterministic. Using memory address based objects as map key makes order of elements there nondeterministic. Later it can be replaced with vector when there are no indirect munipulations with container inside iteration loops. Change map key to const MWWorld::LiveCellRefBase* to avoid erasing and inserting elements on MWWorld::Ptr update.
This commit is contained in:
parent
58207fc1e3
commit
e2c44d13f3
5 changed files with 193 additions and 204 deletions
|
@ -10,6 +10,11 @@ namespace MWMechanics
|
||||||
mCharacterController.reset(new CharacterController(ptr, animation));
|
mCharacterController.reset(new CharacterController(ptr, animation));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MWWorld::Ptr& Actor::getPtr() const
|
||||||
|
{
|
||||||
|
return mCharacterController->getPtr();
|
||||||
|
}
|
||||||
|
|
||||||
void Actor::updatePtr(const MWWorld::Ptr &newPtr)
|
void Actor::updatePtr(const MWWorld::Ptr &newPtr)
|
||||||
{
|
{
|
||||||
mCharacterController->updatePtr(newPtr);
|
mCharacterController->updatePtr(newPtr);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "../mwmechanics/actorutil.hpp"
|
#include "actorutil.hpp"
|
||||||
|
|
||||||
#include <components/misc/timer.hpp>
|
#include <components/misc/timer.hpp>
|
||||||
|
|
||||||
|
@ -26,6 +26,8 @@ namespace MWMechanics
|
||||||
public:
|
public:
|
||||||
Actor(const MWWorld::Ptr& ptr, MWRender::Animation* animation);
|
Actor(const MWWorld::Ptr& ptr, MWRender::Animation* animation);
|
||||||
|
|
||||||
|
const MWWorld::Ptr& getPtr() const;
|
||||||
|
|
||||||
/// Notify this actor of its new base object Ptr, use when the object changed cells
|
/// Notify this actor of its new base object Ptr, use when the object changed cells
|
||||||
void updatePtr(const MWWorld::Ptr& newPtr);
|
void updatePtr(const MWWorld::Ptr& newPtr);
|
||||||
|
|
||||||
|
|
|
@ -105,12 +105,12 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void forEachFollowingPackage(MWMechanics::Actors::PtrActorMap& actors, const MWWorld::Ptr& actor, const MWWorld::Ptr& player, T&& func)
|
void forEachFollowingPackage(std::list<MWMechanics::Actor>& actors, const MWWorld::Ptr& actorPtr, const MWWorld::Ptr& player, T&& func)
|
||||||
{
|
{
|
||||||
for(auto& iter : actors)
|
for (const MWMechanics::Actor& actor : actors)
|
||||||
{
|
{
|
||||||
const MWWorld::Ptr &iteratedActor = iter.first;
|
const MWWorld::Ptr &iteratedActor = actor.getPtr();
|
||||||
if (iteratedActor == player || iteratedActor == actor)
|
if (iteratedActor == player || iteratedActor == actorPtr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const MWMechanics::CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor);
|
const MWMechanics::CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor);
|
||||||
|
@ -121,7 +121,7 @@ void forEachFollowingPackage(MWMechanics::Actors::PtrActorMap& actors, const MWW
|
||||||
// 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 (const auto& package : stats.getAiSequence())
|
for (const auto& package : stats.getAiSequence())
|
||||||
{
|
{
|
||||||
if(!func(iter, package))
|
if (!func(actor, package))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -771,8 +771,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool Actors::isAttackPreparing(const MWWorld::Ptr& ptr)
|
bool Actors::isAttackPreparing(const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
PtrActorMap::iterator it = mActors.find(ptr);
|
const auto it = mIndex.find(ptr.mRef);
|
||||||
if (it == mActors.end())
|
if (it == mIndex.end())
|
||||||
return false;
|
return false;
|
||||||
CharacterController* ctrl = it->second->getCharacterController();
|
CharacterController* ctrl = it->second->getCharacterController();
|
||||||
|
|
||||||
|
@ -781,8 +781,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool Actors::isRunning(const MWWorld::Ptr& ptr)
|
bool Actors::isRunning(const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
PtrActorMap::iterator it = mActors.find(ptr);
|
const auto it = mIndex.find(ptr.mRef);
|
||||||
if (it == mActors.end())
|
if (it == mIndex.end())
|
||||||
return false;
|
return false;
|
||||||
CharacterController* ctrl = it->second->getCharacterController();
|
CharacterController* ctrl = it->second->getCharacterController();
|
||||||
|
|
||||||
|
@ -791,8 +791,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool Actors::isSneaking(const MWWorld::Ptr& ptr)
|
bool Actors::isSneaking(const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
PtrActorMap::iterator it = mActors.find(ptr);
|
const auto it = mIndex.find(ptr.mRef);
|
||||||
if (it == mActors.end())
|
if (it == mIndex.end())
|
||||||
return false;
|
return false;
|
||||||
CharacterController* ctrl = it->second->getCharacterController();
|
CharacterController* ctrl = it->second->getCharacterController();
|
||||||
|
|
||||||
|
@ -1031,11 +1031,6 @@ namespace MWMechanics
|
||||||
updateProcessingRange();
|
updateProcessingRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
Actors::~Actors()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
float Actors::getProcessingRange() const
|
float Actors::getProcessingRange() const
|
||||||
{
|
{
|
||||||
return mActorsProcessingRange;
|
return mActorsProcessingRange;
|
||||||
|
@ -1057,9 +1052,10 @@ namespace MWMechanics
|
||||||
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
|
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
|
||||||
if (!anim)
|
if (!anim)
|
||||||
return;
|
return;
|
||||||
mActors.emplace(ptr, new Actor(ptr, anim));
|
const auto it = mActors.emplace(mActors.end(), ptr, anim);
|
||||||
|
mIndex.emplace(ptr.mRef, it);
|
||||||
|
|
||||||
CharacterController* ctrl = mActors[ptr]->getCharacterController();
|
CharacterController* ctrl = it->getCharacterController();
|
||||||
if (updateImmediately)
|
if (updateImmediately)
|
||||||
ctrl->update(0);
|
ctrl->update(0);
|
||||||
|
|
||||||
|
@ -1102,20 +1098,20 @@ namespace MWMechanics
|
||||||
|
|
||||||
void Actors::removeActor (const MWWorld::Ptr& ptr, bool keepActive)
|
void Actors::removeActor (const MWWorld::Ptr& ptr, bool keepActive)
|
||||||
{
|
{
|
||||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
const auto iter = mIndex.find(ptr.mRef);
|
||||||
if(iter != mActors.end())
|
if (iter != mIndex.end())
|
||||||
{
|
{
|
||||||
if(!keepActive)
|
if(!keepActive)
|
||||||
removeTemporaryEffects(iter->first);
|
removeTemporaryEffects(iter->second->getPtr());
|
||||||
delete iter->second;
|
mActors.erase(iter->second);
|
||||||
mActors.erase(iter);
|
mIndex.erase(iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::castSpell(const MWWorld::Ptr& ptr, const std::string& spellId, bool manualSpell)
|
void Actors::castSpell(const MWWorld::Ptr& ptr, const std::string& spellId, bool manualSpell)
|
||||||
{
|
{
|
||||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
const auto iter = mIndex.find(ptr.mRef);
|
||||||
if(iter != mActors.end())
|
if (iter != mIndex.end())
|
||||||
iter->second->getCharacterController()->castSpell(spellId, manualSpell);
|
iter->second->getCharacterController()->castSpell(spellId, manualSpell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1153,27 +1149,20 @@ namespace MWMechanics
|
||||||
|
|
||||||
void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
|
void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
|
||||||
{
|
{
|
||||||
PtrActorMap::iterator iter = mActors.find(old);
|
const auto iter = mIndex.find(old.mRef);
|
||||||
if(iter != mActors.end())
|
if (iter != mIndex.end())
|
||||||
{
|
iter->second->updatePtr(ptr);
|
||||||
Actor *actor = iter->second;
|
|
||||||
mActors.erase(iter);
|
|
||||||
|
|
||||||
actor->updatePtr(ptr);
|
|
||||||
mActors.insert(std::make_pair(ptr, actor));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::dropActors (const MWWorld::CellStore *cellStore, const MWWorld::Ptr& ignore)
|
void Actors::dropActors (const MWWorld::CellStore *cellStore, const MWWorld::Ptr& ignore)
|
||||||
{
|
{
|
||||||
PtrActorMap::iterator iter = mActors.begin();
|
for (auto iter = mActors.begin(); iter != mActors.end();)
|
||||||
while(iter != mActors.end())
|
|
||||||
{
|
{
|
||||||
if((iter->first.isInCell() && iter->first.getCell()==cellStore) && iter->first != ignore)
|
if ((iter->getPtr().isInCell() && iter->getPtr().getCell() == cellStore) && iter->getPtr() != ignore)
|
||||||
{
|
{
|
||||||
removeTemporaryEffects(iter->first);
|
removeTemporaryEffects(iter->getPtr());
|
||||||
delete iter->second;
|
mIndex.erase(iter->getPtr().mRef);
|
||||||
mActors.erase(iter++);
|
iter = mActors.erase(iter);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
++iter;
|
++iter;
|
||||||
|
@ -1189,14 +1178,14 @@ namespace MWMechanics
|
||||||
|
|
||||||
if (aiActive)
|
if (aiActive)
|
||||||
{
|
{
|
||||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
for (const Actor& actor : mActors)
|
||||||
{
|
{
|
||||||
if (iter->first == player) continue;
|
if (actor.getPtr() == player) continue;
|
||||||
|
|
||||||
bool inProcessingRange = (playerPos - iter->first.getRefData().getPosition().asVec3()).length2() <= mActorsProcessingRange*mActorsProcessingRange;
|
bool inProcessingRange = (playerPos - actor.getPtr().getRefData().getPosition().asVec3()).length2() <= mActorsProcessingRange*mActorsProcessingRange;
|
||||||
if (inProcessingRange)
|
if (inProcessingRange)
|
||||||
{
|
{
|
||||||
MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
|
MWMechanics::CreatureStats& stats = actor.getPtr().getClass().getCreatureStats(actor.getPtr());
|
||||||
if (!stats.isDead() && stats.getAiSequence().isInCombat())
|
if (!stats.isDead() && stats.getAiSequence().isInCombat())
|
||||||
{
|
{
|
||||||
hasHostiles = true;
|
hasHostiles = true;
|
||||||
|
@ -1235,9 +1224,9 @@ namespace MWMechanics
|
||||||
|
|
||||||
const MWWorld::Ptr player = getPlayer();
|
const MWWorld::Ptr player = getPlayer();
|
||||||
const MWBase::World* world = MWBase::Environment::get().getWorld();
|
const MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
for (const Actor& actor : mActors)
|
||||||
{
|
{
|
||||||
const MWWorld::Ptr& ptr = iter->first;
|
const MWWorld::Ptr& ptr = actor.getPtr();
|
||||||
if (ptr == player)
|
if (ptr == player)
|
||||||
continue; // Don't interfere with player controls.
|
continue; // Don't interfere with player controls.
|
||||||
|
|
||||||
|
@ -1297,9 +1286,9 @@ namespace MWMechanics
|
||||||
float angleToApproachingActor = 0;
|
float angleToApproachingActor = 0;
|
||||||
|
|
||||||
// Iterate through all other actors and predict collisions.
|
// Iterate through all other actors and predict collisions.
|
||||||
for(PtrActorMap::iterator otherIter(mActors.begin()); otherIter != mActors.end(); ++otherIter)
|
for (const Actor& otherActor : mActors)
|
||||||
{
|
{
|
||||||
const MWWorld::Ptr& otherPtr = otherIter->first;
|
const MWWorld::Ptr& otherPtr = otherActor.getPtr();
|
||||||
if (otherPtr == ptr || otherPtr == currentTarget)
|
if (otherPtr == ptr || otherPtr == currentTarget)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1410,42 +1399,42 @@ namespace MWMechanics
|
||||||
bool godmode = MWBase::Environment::get().getWorld()->getGodModeState();
|
bool godmode = MWBase::Environment::get().getWorld()->getGodModeState();
|
||||||
|
|
||||||
// AI and magic effects update
|
// AI and magic effects update
|
||||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
for (Actor& actor : mActors)
|
||||||
{
|
{
|
||||||
bool isPlayer = iter->first == player;
|
const bool isPlayer = actor.getPtr() == player;
|
||||||
CharacterController* ctrl = iter->second->getCharacterController();
|
CharacterController* const ctrl = actor.getCharacterController();
|
||||||
MWBase::LuaManager::ActorControls* luaControls =
|
MWBase::LuaManager::ActorControls* luaControls =
|
||||||
MWBase::Environment::get().getLuaManager()->getActorControls(iter->first);
|
MWBase::Environment::get().getLuaManager()->getActorControls(actor.getPtr());
|
||||||
|
|
||||||
float distSqr = (playerPos - iter->first.getRefData().getPosition().asVec3()).length2();
|
const float distSqr = (playerPos - actor.getPtr().getRefData().getPosition().asVec3()).length2();
|
||||||
// AI processing is only done within given distance to the player.
|
// AI processing is only done within given distance to the player.
|
||||||
bool inProcessingRange = distSqr <= mActorsProcessingRange*mActorsProcessingRange;
|
bool inProcessingRange = distSqr <= mActorsProcessingRange*mActorsProcessingRange;
|
||||||
|
|
||||||
// If dead or no longer in combat, no longer store any actors who attempted to hit us. Also remove for the player.
|
// If dead or no longer in combat, no longer store any actors who attempted to hit us. Also remove for the player.
|
||||||
if (iter->first != player && (iter->first.getClass().getCreatureStats(iter->first).isDead()
|
if (actor.getPtr() != player && (actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDead()
|
||||||
|| !iter->first.getClass().getCreatureStats(iter->first).getAiSequence().isInCombat()
|
|| !actor.getPtr().getClass().getCreatureStats(actor.getPtr()).getAiSequence().isInCombat()
|
||||||
|| !inProcessingRange))
|
|| !inProcessingRange))
|
||||||
{
|
{
|
||||||
iter->first.getClass().getCreatureStats(iter->first).setHitAttemptActorId(-1);
|
actor.getPtr().getClass().getCreatureStats(actor.getPtr()).setHitAttemptActorId(-1);
|
||||||
if (player.getClass().getCreatureStats(player).getHitAttemptActorId() == iter->first.getClass().getCreatureStats(iter->first).getActorId())
|
if (player.getClass().getCreatureStats(player).getHitAttemptActorId() == actor.getPtr().getClass().getCreatureStats(actor.getPtr()).getActorId())
|
||||||
player.getClass().getCreatureStats(player).setHitAttemptActorId(-1);
|
player.getClass().getCreatureStats(player).setHitAttemptActorId(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Misc::TimerStatus engageCombatTimerStatus = iter->second->updateEngageCombatTimer(duration);
|
const Misc::TimerStatus engageCombatTimerStatus = actor.updateEngageCombatTimer(duration);
|
||||||
|
|
||||||
// For dead actors we need to update looping spell particles
|
// For dead actors we need to update looping spell particles
|
||||||
if (iter->first.getClass().getCreatureStats(iter->first).isDead())
|
if (actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDead())
|
||||||
{
|
{
|
||||||
// They can be added during the death animation
|
// They can be added during the death animation
|
||||||
if (!iter->first.getClass().getCreatureStats(iter->first).isDeathAnimationFinished())
|
if (!actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDeathAnimationFinished())
|
||||||
adjustMagicEffects(iter->first, duration);
|
adjustMagicEffects(actor.getPtr(), duration);
|
||||||
ctrl->updateContinuousVfx();
|
ctrl->updateContinuousVfx();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool cellChanged = world->hasCellChanged();
|
bool cellChanged = world->hasCellChanged();
|
||||||
MWWorld::Ptr actor = iter->first; // make a copy of the map key to avoid it being invalidated when the player teleports
|
const MWWorld::Ptr actorPtr = actor.getPtr(); // make a copy of the map key to avoid it being invalidated when the player teleports
|
||||||
updateActor(actor, duration);
|
updateActor(actorPtr, duration);
|
||||||
|
|
||||||
// Looping magic VFX update
|
// Looping magic VFX update
|
||||||
// Note: we need to do this before any of the animations are updated.
|
// Note: we need to do this before any of the animations are updated.
|
||||||
|
@ -1464,13 +1453,13 @@ namespace MWMechanics
|
||||||
if (engageCombatTimerStatus == Misc::TimerStatus::Elapsed)
|
if (engageCombatTimerStatus == Misc::TimerStatus::Elapsed)
|
||||||
{
|
{
|
||||||
if (!isPlayer)
|
if (!isPlayer)
|
||||||
adjustCommandedActor(iter->first);
|
adjustCommandedActor(actor.getPtr());
|
||||||
|
|
||||||
for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it)
|
for (const Actor& otherActor : mActors)
|
||||||
{
|
{
|
||||||
if (it->first == iter->first || isPlayer) // player is not AI-controlled
|
if (otherActor.getPtr() == actor.getPtr() || isPlayer) // player is not AI-controlled
|
||||||
continue;
|
continue;
|
||||||
engageCombat(iter->first, it->first, cachedAllies, it->first == player);
|
engageCombat(actor.getPtr(), otherActor.getPtr(), cachedAllies, otherActor.getPtr() == player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mTimerUpdateHeadTrack == 0)
|
if (mTimerUpdateHeadTrack == 0)
|
||||||
|
@ -1478,7 +1467,7 @@ namespace MWMechanics
|
||||||
float sqrHeadTrackDistance = std::numeric_limits<float>::max();
|
float sqrHeadTrackDistance = std::numeric_limits<float>::max();
|
||||||
MWWorld::Ptr headTrackTarget;
|
MWWorld::Ptr headTrackTarget;
|
||||||
|
|
||||||
MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
|
MWMechanics::CreatureStats& stats = actor.getPtr().getClass().getCreatureStats(actor.getPtr());
|
||||||
bool firstPersonPlayer = isPlayer && world->isFirstPerson();
|
bool firstPersonPlayer = isPlayer && world->isFirstPerson();
|
||||||
|
|
||||||
// 1. Unconsious actor can not track target
|
// 1. Unconsious actor can not track target
|
||||||
|
@ -1493,18 +1482,18 @@ namespace MWMechanics
|
||||||
if (!activePackageTarget.isEmpty())
|
if (!activePackageTarget.isEmpty())
|
||||||
{
|
{
|
||||||
// Track the specified target of package.
|
// Track the specified target of package.
|
||||||
updateHeadTracking(iter->first, activePackageTarget, headTrackTarget, sqrHeadTrackDistance, inCombatOrPursue);
|
updateHeadTracking(actor.getPtr(), activePackageTarget, headTrackTarget, sqrHeadTrackDistance, inCombatOrPursue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Find something nearby.
|
// Find something nearby.
|
||||||
for (auto& [ptr, _] : mActors)
|
for (const Actor& otherActor : mActors)
|
||||||
{
|
{
|
||||||
if (ptr == iter->first)
|
if (otherActor.getPtr() == actor.getPtr())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
updateHeadTracking(iter->first, ptr, headTrackTarget, sqrHeadTrackDistance, inCombatOrPursue);
|
updateHeadTracking(actor.getPtr(), otherActor.getPtr(), headTrackTarget, sqrHeadTrackDistance, inCombatOrPursue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1512,39 +1501,39 @@ namespace MWMechanics
|
||||||
ctrl->setHeadTrackTarget(headTrackTarget);
|
ctrl->setHeadTrackTarget(headTrackTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iter->first.getClass().isNpc() && iter->first != player)
|
if (actor.getPtr().getClass().isNpc() && actor.getPtr() != player)
|
||||||
updateCrimePursuit(iter->first, duration);
|
updateCrimePursuit(actor.getPtr(), duration);
|
||||||
|
|
||||||
if (iter->first != player)
|
if (actor.getPtr() != player)
|
||||||
{
|
{
|
||||||
CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first);
|
CreatureStats &stats = actor.getPtr().getClass().getCreatureStats(actor.getPtr());
|
||||||
if (isConscious(iter->first) && !(luaControls && luaControls->mDisableAI))
|
if (isConscious(actor.getPtr()) && !(luaControls && luaControls->mDisableAI))
|
||||||
{
|
{
|
||||||
stats.getAiSequence().execute(iter->first, *ctrl, duration);
|
stats.getAiSequence().execute(actor.getPtr(), *ctrl, duration);
|
||||||
updateGreetingState(iter->first, *iter->second, mTimerUpdateHello > 0);
|
updateGreetingState(actor.getPtr(), actor, mTimerUpdateHello > 0);
|
||||||
playIdleDialogue(iter->first);
|
playIdleDialogue(actor.getPtr());
|
||||||
updateMovementSpeed(iter->first);
|
updateMovementSpeed(actor.getPtr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (aiActive && iter->first != player && isConscious(iter->first) && !(luaControls && luaControls->mDisableAI))
|
else if (aiActive && actor.getPtr() != player && isConscious(actor.getPtr()) && !(luaControls && luaControls->mDisableAI))
|
||||||
{
|
{
|
||||||
CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first);
|
CreatureStats &stats = actor.getPtr().getClass().getCreatureStats(actor.getPtr());
|
||||||
stats.getAiSequence().execute(iter->first, *ctrl, duration, /*outOfRange*/true);
|
stats.getAiSequence().execute(actor.getPtr(), *ctrl, duration, /*outOfRange*/true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(inProcessingRange && iter->first.getClass().isNpc())
|
if (inProcessingRange && actor.getPtr().getClass().isNpc())
|
||||||
{
|
{
|
||||||
// We can not update drowning state for actors outside of AI distance - they can not resurface to breathe
|
// We can not update drowning state for actors outside of AI distance - they can not resurface to breathe
|
||||||
updateDrowning(iter->first, duration, ctrl->isKnockedOut(), isPlayer);
|
updateDrowning(actor.getPtr(), duration, ctrl->isKnockedOut(), isPlayer);
|
||||||
}
|
}
|
||||||
if(mTimerUpdateEquippedLight == 0 && iter->first.getClass().hasInventoryStore(iter->first))
|
if (mTimerUpdateEquippedLight == 0 && actor.getPtr().getClass().hasInventoryStore(actor.getPtr()))
|
||||||
updateEquippedLight(iter->first, updateEquippedLightInterval, showTorches);
|
updateEquippedLight(actor.getPtr(), updateEquippedLightInterval, showTorches);
|
||||||
|
|
||||||
if (luaControls && isConscious(iter->first))
|
if (luaControls && isConscious(actor.getPtr()))
|
||||||
{
|
{
|
||||||
Movement& mov = iter->first.getClass().getMovementSettings(iter->first);
|
Movement& mov = actor.getPtr().getClass().getMovementSettings(actor.getPtr());
|
||||||
CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
|
CreatureStats& stats = actor.getPtr().getClass().getCreatureStats(actor.getPtr());
|
||||||
float speedFactor = isPlayer ? 1.f : mov.mSpeedFactor;
|
float speedFactor = isPlayer ? 1.f : mov.mSpeedFactor;
|
||||||
osg::Vec2f movement = osg::Vec2f(mov.mPosition[0], mov.mPosition[1]) * speedFactor;
|
osg::Vec2f movement = osg::Vec2f(mov.mPosition[0], mov.mPosition[1]) * speedFactor;
|
||||||
float rotationX = mov.mRotation[0];
|
float rotationX = mov.mRotation[0];
|
||||||
|
@ -1587,14 +1576,14 @@ namespace MWMechanics
|
||||||
|
|
||||||
// Animation/movement update
|
// Animation/movement update
|
||||||
CharacterController* playerCharacter = nullptr;
|
CharacterController* playerCharacter = nullptr;
|
||||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
for (Actor& actor : mActors)
|
||||||
{
|
{
|
||||||
const float dist = (playerPos - iter->first.getRefData().getPosition().asVec3()).length();
|
const float dist = (playerPos - actor.getPtr().getRefData().getPosition().asVec3()).length();
|
||||||
bool isPlayer = iter->first == player;
|
const bool isPlayer = actor.getPtr() == player;
|
||||||
CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first);
|
CreatureStats &stats = actor.getPtr().getClass().getCreatureStats(actor.getPtr());
|
||||||
// Actors with active AI should be able to move.
|
// Actors with active AI should be able to move.
|
||||||
bool alwaysActive = false;
|
bool alwaysActive = false;
|
||||||
if (!isPlayer && isConscious(iter->first) && !stats.isParalyzed())
|
if (!isPlayer && isConscious(actor.getPtr()) && !stats.isParalyzed())
|
||||||
{
|
{
|
||||||
MWMechanics::AiSequence& seq = stats.getAiSequence();
|
MWMechanics::AiSequence& seq = stats.getAiSequence();
|
||||||
alwaysActive = !seq.isEmpty() && seq.getActivePackage().alwaysActive();
|
alwaysActive = !seq.isEmpty() && seq.getActivePackage().alwaysActive();
|
||||||
|
@ -1605,41 +1594,41 @@ namespace MWMechanics
|
||||||
activeFlag = 2;
|
activeFlag = 2;
|
||||||
int active = inRange ? activeFlag : 0;
|
int active = inRange ? activeFlag : 0;
|
||||||
|
|
||||||
CharacterController* ctrl = iter->second->getCharacterController();
|
CharacterController* const ctrl = actor.getCharacterController();
|
||||||
ctrl->setActive(active);
|
ctrl->setActive(active);
|
||||||
|
|
||||||
if (!inRange)
|
if (!inRange)
|
||||||
{
|
{
|
||||||
iter->first.getRefData().getBaseNode()->setNodeMask(0);
|
actor.getPtr().getRefData().getBaseNode()->setNodeMask(0);
|
||||||
world->setActorCollisionMode(iter->first, false, false);
|
world->setActorCollisionMode(actor.getPtr(), false, false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (!isPlayer)
|
else if (!isPlayer)
|
||||||
{
|
{
|
||||||
iter->first.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Actor);
|
actor.getPtr().getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Actor);
|
||||||
if (!iter->second->getPositionAdjusted())
|
if (!actor.getPositionAdjusted())
|
||||||
{
|
{
|
||||||
iter->first.getClass().adjustPosition(iter->first, false);
|
actor.getPtr().getClass().adjustPosition(actor.getPtr(), false);
|
||||||
iter->second->setPositionAdjusted(true);
|
actor.setPositionAdjusted(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool isDead = iter->first.getClass().getCreatureStats(iter->first).isDead();
|
const bool isDead = actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDead();
|
||||||
if (!isDead && (!godmode || !isPlayer) && iter->first.getClass().getCreatureStats(iter->first).isParalyzed())
|
if (!isDead && (!godmode || !isPlayer) && actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isParalyzed())
|
||||||
ctrl->skipAnim();
|
ctrl->skipAnim();
|
||||||
|
|
||||||
// Handle player last, in case a cell transition occurs by casting a teleportation spell
|
// Handle player last, in case a cell transition occurs by casting a teleportation spell
|
||||||
// (would invalidate the iterator)
|
// (would invalidate the iterator)
|
||||||
if (iter->first == getPlayer())
|
if (actor.getPtr() == getPlayer())
|
||||||
{
|
{
|
||||||
playerCharacter = ctrl;
|
playerCharacter = ctrl;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
world->setActorCollisionMode(iter->first, true, !iter->first.getClass().getCreatureStats(iter->first).isDeathAnimationFinished());
|
world->setActorCollisionMode(actor.getPtr(), true, !actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDeathAnimationFinished());
|
||||||
ctrl->update(duration);
|
ctrl->update(duration);
|
||||||
|
|
||||||
updateVisibility(iter->first, ctrl);
|
updateVisibility(actor.getPtr(), ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playerCharacter)
|
if (playerCharacter)
|
||||||
|
@ -1649,10 +1638,10 @@ namespace MWMechanics
|
||||||
playerCharacter->setVisibility(1.f);
|
playerCharacter->setVisibility(1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
for (const Actor& actor : mActors)
|
||||||
{
|
{
|
||||||
const MWWorld::Class &cls = iter->first.getClass();
|
const MWWorld::Class &cls = actor.getPtr().getClass();
|
||||||
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
CreatureStats &stats = cls.getCreatureStats(actor.getPtr());
|
||||||
|
|
||||||
//KnockedOutOneFrameLogic
|
//KnockedOutOneFrameLogic
|
||||||
//Used for "OnKnockedOut" command
|
//Used for "OnKnockedOut" command
|
||||||
|
@ -1684,13 +1673,13 @@ namespace MWMechanics
|
||||||
|
|
||||||
void Actors::resurrect(const MWWorld::Ptr &ptr)
|
void Actors::resurrect(const MWWorld::Ptr &ptr)
|
||||||
{
|
{
|
||||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
const auto iter = mIndex.find(ptr.mRef);
|
||||||
if(iter != mActors.end())
|
if (iter != mIndex.end())
|
||||||
{
|
{
|
||||||
if(iter->second->getCharacterController()->isDead())
|
if (iter->second->getCharacterController()->isDead())
|
||||||
{
|
{
|
||||||
// Actor has been resurrected. Notify the CharacterController and re-enable collision.
|
// Actor has been resurrected. Notify the CharacterController and re-enable collision.
|
||||||
MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, true);
|
MWBase::Environment::get().getWorld()->enableActorCollision(iter->second->getPtr(), true);
|
||||||
iter->second->getCharacterController()->resurrect();
|
iter->second->getCharacterController()->resurrect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1698,39 +1687,39 @@ namespace MWMechanics
|
||||||
|
|
||||||
void Actors::killDeadActors()
|
void Actors::killDeadActors()
|
||||||
{
|
{
|
||||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
for (Actor& actor : mActors)
|
||||||
{
|
{
|
||||||
const MWWorld::Class &cls = iter->first.getClass();
|
const MWWorld::Class &cls = actor.getPtr().getClass();
|
||||||
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
CreatureStats &stats = cls.getCreatureStats(actor.getPtr());
|
||||||
|
|
||||||
if(!stats.isDead())
|
if(!stats.isDead())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->removeActorPath(iter->first);
|
MWBase::Environment::get().getWorld()->removeActorPath(actor.getPtr());
|
||||||
CharacterController::KillResult killResult = iter->second->getCharacterController()->kill();
|
CharacterController::KillResult killResult = actor.getCharacterController()->kill();
|
||||||
if (killResult == CharacterController::Result_DeathAnimStarted)
|
if (killResult == CharacterController::Result_DeathAnimStarted)
|
||||||
{
|
{
|
||||||
// Play dying words
|
// Play dying words
|
||||||
// Note: It's not known whether the soundgen tags scream, roar, and moan are reliable
|
// Note: It's not known whether the soundgen tags scream, roar, and moan are reliable
|
||||||
// for NPCs since some of the npc death animation files are missing them.
|
// for NPCs since some of the npc death animation files are missing them.
|
||||||
MWBase::Environment::get().getDialogueManager()->say(iter->first, "hit");
|
MWBase::Environment::get().getDialogueManager()->say(actor.getPtr(), "hit");
|
||||||
|
|
||||||
// Apply soultrap
|
// Apply soultrap
|
||||||
if (iter->first.getType() == ESM::Creature::sRecordId)
|
if (actor.getPtr().getType() == ESM::Creature::sRecordId)
|
||||||
soulTrap(iter->first);
|
soulTrap(actor.getPtr());
|
||||||
|
|
||||||
if (cls.isEssential(iter->first))
|
if (cls.isEssential(actor.getPtr()))
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}");
|
||||||
}
|
}
|
||||||
else if (killResult == CharacterController::Result_DeathAnimJustFinished)
|
else if (killResult == CharacterController::Result_DeathAnimJustFinished)
|
||||||
{
|
{
|
||||||
bool isPlayer = iter->first == getPlayer();
|
const bool isPlayer = actor.getPtr() == getPlayer();
|
||||||
notifyDied(iter->first);
|
notifyDied(actor.getPtr());
|
||||||
|
|
||||||
// Reset magic effects and recalculate derived effects
|
// Reset magic effects and recalculate derived effects
|
||||||
// One case where we need this is to make sure bound items are removed upon death
|
// One case where we need this is to make sure bound items are removed upon death
|
||||||
float vampirism = stats.getMagicEffects().get(ESM::MagicEffect::Vampirism).getMagnitude();
|
float vampirism = stats.getMagicEffects().get(ESM::MagicEffect::Vampirism).getMagnitude();
|
||||||
stats.getActiveSpells().clear(iter->first);
|
stats.getActiveSpells().clear(actor.getPtr());
|
||||||
// Make sure spell effects are removed
|
// Make sure spell effects are removed
|
||||||
purgeSpellEffects(stats.getActorId());
|
purgeSpellEffects(stats.getActorId());
|
||||||
|
|
||||||
|
@ -1746,7 +1735,7 @@ namespace MWMechanics
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// NPC death animation is over, disable actor collision
|
// NPC death animation is over, disable actor collision
|
||||||
MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, false);
|
MWBase::Environment::get().getWorld()->enableActorCollision(actor.getPtr(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1785,10 +1774,10 @@ namespace MWMechanics
|
||||||
|
|
||||||
void Actors::purgeSpellEffects(int casterActorId)
|
void Actors::purgeSpellEffects(int casterActorId)
|
||||||
{
|
{
|
||||||
for (PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
for (const Actor& actor : mActors)
|
||||||
{
|
{
|
||||||
MWMechanics::ActiveSpells& spells = iter->first.getClass().getCreatureStats(iter->first).getActiveSpells();
|
MWMechanics::ActiveSpells& spells = actor.getPtr().getClass().getCreatureStats(actor.getPtr()).getActiveSpells();
|
||||||
spells.purge(iter->first, casterActorId);
|
spells.purge(actor.getPtr(), casterActorId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1802,28 +1791,28 @@ namespace MWMechanics
|
||||||
const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
const osg::Vec3f playerPos = player.getRefData().getPosition().asVec3();
|
const osg::Vec3f playerPos = player.getRefData().getPosition().asVec3();
|
||||||
|
|
||||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
for (const Actor& actor : mActors)
|
||||||
{
|
{
|
||||||
if (iter->first.getClass().getCreatureStats(iter->first).isDead())
|
if (actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDead())
|
||||||
{
|
{
|
||||||
adjustMagicEffects (iter->first, duration);
|
adjustMagicEffects(actor.getPtr(), duration);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sleep || iter->first == player)
|
if (!sleep || actor.getPtr() == player)
|
||||||
restoreDynamicStats(iter->first, hours, sleep);
|
restoreDynamicStats(actor.getPtr(), hours, sleep);
|
||||||
|
|
||||||
if ((!iter->first.getRefData().getBaseNode()) ||
|
if ((!actor.getPtr().getRefData().getBaseNode()) ||
|
||||||
(playerPos - iter->first.getRefData().getPosition().asVec3()).length2() > mActorsProcessingRange*mActorsProcessingRange)
|
(playerPos - actor.getPtr().getRefData().getPosition().asVec3()).length2() > mActorsProcessingRange*mActorsProcessingRange)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
adjustMagicEffects (iter->first, duration);
|
adjustMagicEffects (actor.getPtr(), duration);
|
||||||
|
|
||||||
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(iter->first);
|
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(actor.getPtr());
|
||||||
if (animation)
|
if (animation)
|
||||||
{
|
{
|
||||||
animation->removeEffects();
|
animation->removeEffects();
|
||||||
MWBase::Environment::get().getWorld()->applyLoopingParticles(iter->first);
|
MWBase::Environment::get().getWorld()->applyLoopingParticles(actor.getPtr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1935,15 +1924,15 @@ namespace MWMechanics
|
||||||
|
|
||||||
void Actors::forceStateUpdate(const MWWorld::Ptr & ptr)
|
void Actors::forceStateUpdate(const MWWorld::Ptr & ptr)
|
||||||
{
|
{
|
||||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
const auto iter = mIndex.find(ptr.mRef);
|
||||||
if(iter != mActors.end())
|
if (iter != mIndex.end())
|
||||||
iter->second->getCharacterController()->forceStateUpdate();
|
iter->second->getCharacterController()->forceStateUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist)
|
bool Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist)
|
||||||
{
|
{
|
||||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
const auto iter = mIndex.find(ptr.mRef);
|
||||||
if(iter != mActors.end())
|
if(iter != mIndex.end())
|
||||||
{
|
{
|
||||||
return iter->second->getCharacterController()->playGroup(groupName, mode, number, persist);
|
return iter->second->getCharacterController()->playGroup(groupName, mode, number, persist);
|
||||||
}
|
}
|
||||||
|
@ -1955,55 +1944,55 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
void Actors::skipAnimation(const MWWorld::Ptr& ptr)
|
void Actors::skipAnimation(const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
const auto iter = mIndex.find(ptr.mRef);
|
||||||
if(iter != mActors.end())
|
if (iter != mIndex.end())
|
||||||
iter->second->getCharacterController()->skipAnim();
|
iter->second->getCharacterController()->skipAnim();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Actors::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName)
|
bool Actors::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName)
|
||||||
{
|
{
|
||||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
const auto iter = mIndex.find(ptr.mRef);
|
||||||
if(iter != mActors.end())
|
if(iter != mIndex.end())
|
||||||
return iter->second->getCharacterController()->isAnimPlaying(groupName);
|
return iter->second->getCharacterController()->isAnimPlaying(groupName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::persistAnimationStates()
|
void Actors::persistAnimationStates()
|
||||||
{
|
{
|
||||||
for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
|
for (Actor& actor : mActors)
|
||||||
iter->second->getCharacterController()->persistAnimationState();
|
actor.getCharacterController()->persistAnimationState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::getObjectsInRange(const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& out)
|
void Actors::getObjectsInRange(const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& out)
|
||||||
{
|
{
|
||||||
for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
|
for (const Actor& actor : mActors)
|
||||||
{
|
{
|
||||||
if ((iter->first.getRefData().getPosition().asVec3() - position).length2() <= radius*radius)
|
if ((actor.getPtr().getRefData().getPosition().asVec3() - position).length2() <= radius*radius)
|
||||||
out.push_back(iter->first);
|
out.push_back(actor.getPtr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Actors::isAnyObjectInRange(const osg::Vec3f& position, float radius)
|
bool Actors::isAnyObjectInRange(const osg::Vec3f& position, float radius)
|
||||||
{
|
{
|
||||||
for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
|
for (const Actor& actor : mActors)
|
||||||
{
|
{
|
||||||
if ((iter->first.getRefData().getPosition().asVec3() - position).length2() <= radius*radius)
|
if ((actor.getPtr().getRefData().getPosition().asVec3() - position).length2() <= radius*radius)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<MWWorld::Ptr> Actors::getActorsSidingWith(const MWWorld::Ptr& actor)
|
std::vector<MWWorld::Ptr> Actors::getActorsSidingWith(const MWWorld::Ptr& actorPtr)
|
||||||
{
|
{
|
||||||
std::vector<MWWorld::Ptr> list;
|
std::vector<MWWorld::Ptr> list;
|
||||||
for(PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
|
for (const Actor& actor : mActors)
|
||||||
{
|
{
|
||||||
const MWWorld::Ptr &iteratedActor = iter->first;
|
const MWWorld::Ptr& iteratedActor = actor.getPtr();
|
||||||
if (iteratedActor == getPlayer())
|
if (iteratedActor == getPlayer())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const bool sameActor = (iteratedActor == actor);
|
const bool sameActor = (iteratedActor == actorPtr);
|
||||||
|
|
||||||
const CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor);
|
const CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor);
|
||||||
if (stats.isDead())
|
if (stats.isDead())
|
||||||
|
@ -2019,7 +2008,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
list.push_back(package->getTarget());
|
list.push_back(package->getTarget());
|
||||||
}
|
}
|
||||||
else if (package->getTarget() == actor)
|
else if (package->getTarget() == actorPtr)
|
||||||
{
|
{
|
||||||
list.push_back(iteratedActor);
|
list.push_back(iteratedActor);
|
||||||
}
|
}
|
||||||
|
@ -2032,13 +2021,13 @@ namespace MWMechanics
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<MWWorld::Ptr> Actors::getActorsFollowing(const MWWorld::Ptr& actor)
|
std::vector<MWWorld::Ptr> Actors::getActorsFollowing(const MWWorld::Ptr& actorPtr)
|
||||||
{
|
{
|
||||||
std::vector<MWWorld::Ptr> list;
|
std::vector<MWWorld::Ptr> list;
|
||||||
forEachFollowingPackage(mActors, actor, getPlayer(), [&] (auto& iter, const std::shared_ptr<AiPackage>& package)
|
forEachFollowingPackage(mActors, actorPtr, getPlayer(), [&] (const Actor& actor, const std::shared_ptr<AiPackage>& package)
|
||||||
{
|
{
|
||||||
if (package->followTargetThroughDoors() && package->getTarget() == actor)
|
if (package->followTargetThroughDoors() && package->getTarget() == actorPtr)
|
||||||
list.push_back(iter.first);
|
list.push_back(actor.getPtr());
|
||||||
else if (package->getTypeId() != AiPackageTypeId::Combat && package->getTypeId() != AiPackageTypeId::Wander)
|
else if (package->getTypeId() != AiPackageTypeId::Combat && package->getTypeId() != AiPackageTypeId::Wander)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
@ -2086,7 +2075,7 @@ namespace MWMechanics
|
||||||
std::vector<int> Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor)
|
std::vector<int> Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor)
|
||||||
{
|
{
|
||||||
std::vector<int> list;
|
std::vector<int> list;
|
||||||
forEachFollowingPackage(mActors, actor, getPlayer(), [&] (auto& iter, const std::shared_ptr<AiPackage>& package)
|
forEachFollowingPackage(mActors, actor, getPlayer(), [&] (const Actor&, const std::shared_ptr<AiPackage>& package)
|
||||||
{
|
{
|
||||||
if (package->followTargetThroughDoors() && package->getTarget() == actor)
|
if (package->followTargetThroughDoors() && package->getTarget() == actor)
|
||||||
{
|
{
|
||||||
|
@ -2103,12 +2092,12 @@ namespace MWMechanics
|
||||||
std::map<int, MWWorld::Ptr> Actors::getActorsFollowingByIndex(const MWWorld::Ptr &actor)
|
std::map<int, MWWorld::Ptr> Actors::getActorsFollowingByIndex(const MWWorld::Ptr &actor)
|
||||||
{
|
{
|
||||||
std::map<int, MWWorld::Ptr> map;
|
std::map<int, MWWorld::Ptr> map;
|
||||||
forEachFollowingPackage(mActors, actor, getPlayer(), [&] (auto& iter, const std::shared_ptr<AiPackage>& package)
|
forEachFollowingPackage(mActors, actor, getPlayer(), [&] (const Actor& otherActor, const std::shared_ptr<AiPackage>& package)
|
||||||
{
|
{
|
||||||
if (package->followTargetThroughDoors() && package->getTarget() == actor)
|
if (package->followTargetThroughDoors() && package->getTarget() == actor)
|
||||||
{
|
{
|
||||||
int index = static_cast<const AiFollow*>(package.get())->getFollowIndex();
|
int index = static_cast<const AiFollow*>(package.get())->getFollowIndex();
|
||||||
map[index] = iter.first;
|
map[index] = otherActor.getPtr();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (package->getTypeId() != AiPackageTypeId::Combat && package->getTypeId() != AiPackageTypeId::Wander)
|
else if (package->getTypeId() != AiPackageTypeId::Combat && package->getTypeId() != AiPackageTypeId::Wander)
|
||||||
|
@ -2190,12 +2179,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
void Actors::clear()
|
void Actors::clear()
|
||||||
{
|
{
|
||||||
PtrActorMap::iterator it(mActors.begin());
|
mIndex.clear();
|
||||||
for (; it != mActors.end(); ++it)
|
|
||||||
{
|
|
||||||
delete it->second;
|
|
||||||
it->second = nullptr;
|
|
||||||
}
|
|
||||||
mActors.clear();
|
mActors.clear();
|
||||||
mDeathCount.clear();
|
mDeathCount.clear();
|
||||||
}
|
}
|
||||||
|
@ -2207,8 +2191,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool Actors::isReadyToBlock(const MWWorld::Ptr &ptr) const
|
bool Actors::isReadyToBlock(const MWWorld::Ptr &ptr) const
|
||||||
{
|
{
|
||||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
const auto it = mIndex.find(ptr.mRef);
|
||||||
if (it == mActors.end())
|
if (it == mIndex.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return it->second->getCharacterController()->isReadyToBlock();
|
return it->second->getCharacterController()->isReadyToBlock();
|
||||||
|
@ -2216,8 +2200,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool Actors::isCastingSpell(const MWWorld::Ptr &ptr) const
|
bool Actors::isCastingSpell(const MWWorld::Ptr &ptr) const
|
||||||
{
|
{
|
||||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
const auto it = mIndex.find(ptr.mRef);
|
||||||
if (it == mActors.end())
|
if (it == mIndex.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return it->second->getCharacterController()->isCastingSpell();
|
return it->second->getCharacterController()->isCastingSpell();
|
||||||
|
@ -2225,8 +2209,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool Actors::isAttackingOrSpell(const MWWorld::Ptr& ptr) const
|
bool Actors::isAttackingOrSpell(const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
const auto it = mIndex.find(ptr.mRef);
|
||||||
if (it == mActors.end())
|
if (it == mIndex.end())
|
||||||
return false;
|
return false;
|
||||||
CharacterController* ctrl = it->second->getCharacterController();
|
CharacterController* ctrl = it->second->getCharacterController();
|
||||||
|
|
||||||
|
@ -2235,8 +2219,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
int Actors::getGreetingTimer(const MWWorld::Ptr& ptr) const
|
int Actors::getGreetingTimer(const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
const auto it = mIndex.find(ptr.mRef);
|
||||||
if (it == mActors.end())
|
if (it == mIndex.end())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return it->second->getGreetingTimer();
|
return it->second->getGreetingTimer();
|
||||||
|
@ -2244,8 +2228,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
float Actors::getAngleToPlayer(const MWWorld::Ptr& ptr) const
|
float Actors::getAngleToPlayer(const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
const auto it = mIndex.find(ptr.mRef);
|
||||||
if (it == mActors.end())
|
if (it == mIndex.end())
|
||||||
return 0.f;
|
return 0.f;
|
||||||
|
|
||||||
return it->second->getAngleToPlayer();
|
return it->second->getAngleToPlayer();
|
||||||
|
@ -2253,8 +2237,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
GreetingState Actors::getGreetingState(const MWWorld::Ptr& ptr) const
|
GreetingState Actors::getGreetingState(const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
const auto it = mIndex.find(ptr.mRef);
|
||||||
if (it == mActors.end())
|
if (it == mIndex.end())
|
||||||
return Greet_None;
|
return Greet_None;
|
||||||
|
|
||||||
return it->second->getGreetingState();
|
return it->second->getGreetingState();
|
||||||
|
@ -2262,8 +2246,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool Actors::isTurningToPlayer(const MWWorld::Ptr& ptr) const
|
bool Actors::isTurningToPlayer(const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
const auto it = mIndex.find(ptr.mRef);
|
||||||
if (it == mActors.end())
|
if (it == mIndex.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return it->second->isTurningToPlayer();
|
return it->second->isTurningToPlayer();
|
||||||
|
@ -2274,11 +2258,9 @@ namespace MWMechanics
|
||||||
if (!MWBase::Environment::get().getMechanicsManager()->isAIActive())
|
if (!MWBase::Environment::get().getMechanicsManager()->isAIActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// making a copy since fast-forward could move actor to a different cell and invalidate the mActors iterator
|
for (const Actor& actor : mActors)
|
||||||
PtrActorMap map = mActors;
|
|
||||||
for (PtrActorMap::iterator it = map.begin(); it != map.end(); ++it)
|
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = it->first;
|
const MWWorld::Ptr ptr = actor.getPtr();
|
||||||
if (ptr == getPlayer()
|
if (ptr == getPlayer()
|
||||||
|| !isConscious(ptr)
|
|| !isConscious(ptr)
|
||||||
|| ptr.getClass().getCreatureStats(ptr).isParalyzed())
|
|| ptr.getClass().getCreatureStats(ptr).isParalyzed())
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "../mwmechanics/actorutil.hpp"
|
#include "actorutil.hpp"
|
||||||
|
#include "actor.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
|
@ -42,12 +43,9 @@ namespace MWMechanics
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Actors();
|
Actors();
|
||||||
~Actors();
|
|
||||||
|
|
||||||
typedef std::map<MWWorld::Ptr,Actor*> PtrActorMap;
|
std::list<Actor>::const_iterator begin() const { return mActors.begin(); }
|
||||||
|
std::list<Actor>::const_iterator end() const { return mActors.end(); }
|
||||||
PtrActorMap::const_iterator begin() { return mActors.begin(); }
|
|
||||||
PtrActorMap::const_iterator end() { return mActors.end(); }
|
|
||||||
std::size_t size() const { return mActors.size(); }
|
std::size_t size() const { return mActors.size(); }
|
||||||
|
|
||||||
void notifyDied(const MWWorld::Ptr &actor);
|
void notifyDied(const MWWorld::Ptr &actor);
|
||||||
|
@ -190,7 +188,8 @@ namespace MWMechanics
|
||||||
};
|
};
|
||||||
|
|
||||||
std::map<std::string, int> mDeathCount;
|
std::map<std::string, int> mDeathCount;
|
||||||
PtrActorMap mActors;
|
std::list<Actor> mActors;
|
||||||
|
std::map<const MWWorld::LiveCellRefBase*, std::list<Actor>::iterator> mIndex;
|
||||||
float mTimerDisposeSummonsCorpses;
|
float mTimerDisposeSummonsCorpses;
|
||||||
float mTimerUpdateHeadTrack = 0;
|
float mTimerUpdateHeadTrack = 0;
|
||||||
float mTimerUpdateEquippedLight = 0;
|
float mTimerUpdateEquippedLight = 0;
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "npcstats.hpp"
|
#include "npcstats.hpp"
|
||||||
#include "actorutil.hpp"
|
#include "actorutil.hpp"
|
||||||
#include "combat.hpp"
|
#include "combat.hpp"
|
||||||
|
#include "actor.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -1599,16 +1600,16 @@ namespace MWMechanics
|
||||||
if (ptr.getClass().isClass(ptr, "Guard"))
|
if (ptr.getClass().isClass(ptr, "Guard"))
|
||||||
{
|
{
|
||||||
stats.setHitAttemptActorId(target.getClass().getCreatureStats(target).getActorId()); // Stops guard from ending combat if player is unreachable
|
stats.setHitAttemptActorId(target.getClass().getCreatureStats(target).getActorId()); // Stops guard from ending combat if player is unreachable
|
||||||
for (Actors::PtrActorMap::const_iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
|
for (const Actor& actor : mActors)
|
||||||
{
|
{
|
||||||
if (iter->first.getClass().isClass(iter->first, "Guard"))
|
if (actor.getPtr().getClass().isClass(actor.getPtr(), "Guard"))
|
||||||
{
|
{
|
||||||
MWMechanics::AiSequence& aiSeq = iter->first.getClass().getCreatureStats(iter->first).getAiSequence();
|
MWMechanics::AiSequence& aiSeq = actor.getPtr().getClass().getCreatureStats(actor.getPtr()).getAiSequence();
|
||||||
if (aiSeq.getTypeId() == MWMechanics::AiPackageTypeId::Pursue)
|
if (aiSeq.getTypeId() == MWMechanics::AiPackageTypeId::Pursue)
|
||||||
{
|
{
|
||||||
aiSeq.stopPursuit();
|
aiSeq.stopPursuit();
|
||||||
aiSeq.stack(MWMechanics::AiCombat(target), ptr);
|
aiSeq.stack(MWMechanics::AiCombat(target), ptr);
|
||||||
iter->first.getClass().getCreatureStats(iter->first).setHitAttemptActorId(target.getClass().getCreatureStats(target).getActorId()); // Stops guard from ending combat if player is unreachable
|
actor.getPtr().getClass().getCreatureStats(actor.getPtr()).setHitAttemptActorId(target.getClass().getCreatureStats(target).getActorId()); // Stops guard from ending combat if player is unreachable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue