mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-14 01:19:59 +00:00
Merge branch 'mechanics_actors_list' into 'master'
Use std::list to store mechanics actors See merge request OpenMW/openmw!1893
This commit is contained in:
commit
d2a9334f39
@ -95,7 +95,7 @@ add_openmw_dir (mwmechanics
|
||||
mechanicsmanagerimp stat creaturestats magiceffects movement actorutil spelllist
|
||||
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aibreathe
|
||||
aicast aiescort aiface aiactivate aicombat recharge repair enchanting pathfinding pathgrid security spellcasting spellresistance
|
||||
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
|
||||
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction summoning
|
||||
character actors objects aistate trading weaponpriority spellpriority weapontype spellutil
|
||||
spelleffects
|
||||
)
|
||||
|
@ -1,77 +0,0 @@
|
||||
#include "actor.hpp"
|
||||
|
||||
#include "character.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
Actor::Actor(const MWWorld::Ptr &ptr, MWRender::Animation *animation)
|
||||
: mPositionAdjusted(false)
|
||||
{
|
||||
mCharacterController.reset(new CharacterController(ptr, animation));
|
||||
}
|
||||
|
||||
void Actor::updatePtr(const MWWorld::Ptr &newPtr)
|
||||
{
|
||||
mCharacterController->updatePtr(newPtr);
|
||||
}
|
||||
|
||||
CharacterController* Actor::getCharacterController()
|
||||
{
|
||||
return mCharacterController.get();
|
||||
}
|
||||
|
||||
int Actor::getGreetingTimer() const
|
||||
{
|
||||
return mGreetingTimer;
|
||||
}
|
||||
|
||||
void Actor::setGreetingTimer(int timer)
|
||||
{
|
||||
mGreetingTimer = timer;
|
||||
}
|
||||
|
||||
float Actor::getAngleToPlayer() const
|
||||
{
|
||||
return mTargetAngleRadians;
|
||||
}
|
||||
|
||||
void Actor::setAngleToPlayer(float angle)
|
||||
{
|
||||
mTargetAngleRadians = angle;
|
||||
}
|
||||
|
||||
GreetingState Actor::getGreetingState() const
|
||||
{
|
||||
return mGreetingState;
|
||||
}
|
||||
|
||||
void Actor::setGreetingState(GreetingState state)
|
||||
{
|
||||
mGreetingState = state;
|
||||
}
|
||||
|
||||
bool Actor::isTurningToPlayer() const
|
||||
{
|
||||
return mIsTurningToPlayer;
|
||||
}
|
||||
|
||||
void Actor::setTurningToPlayer(bool turning)
|
||||
{
|
||||
mIsTurningToPlayer = turning;
|
||||
}
|
||||
|
||||
Misc::TimerStatus Actor::updateEngageCombatTimer(float duration)
|
||||
{
|
||||
return mEngageCombat.update(duration, MWBase::Environment::get().getWorld()->getPrng());
|
||||
}
|
||||
|
||||
void Actor::setPositionAdjusted(bool adjusted)
|
||||
{
|
||||
mPositionAdjusted = adjusted;
|
||||
}
|
||||
|
||||
bool Actor::getPositionAdjusted() const
|
||||
{
|
||||
return mPositionAdjusted;
|
||||
}
|
||||
}
|
@ -3,7 +3,8 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
#include "actorutil.hpp"
|
||||
#include "character.hpp"
|
||||
|
||||
#include <components/misc/timer.hpp>
|
||||
|
||||
@ -18,38 +19,44 @@ namespace MWWorld
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
class CharacterController;
|
||||
|
||||
/// @brief Holds temporary state for an actor that will be discarded when the actor leaves the scene.
|
||||
class Actor
|
||||
{
|
||||
public:
|
||||
Actor(const MWWorld::Ptr& ptr, MWRender::Animation* animation);
|
||||
Actor(const MWWorld::Ptr& ptr, MWRender::Animation* animation)
|
||||
: mCharacterController(ptr, animation)
|
||||
, mPositionAdjusted(false)
|
||||
{}
|
||||
|
||||
const MWWorld::Ptr& getPtr() const { return mCharacterController.getPtr(); }
|
||||
|
||||
/// 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) { mCharacterController.updatePtr(newPtr); }
|
||||
|
||||
CharacterController* getCharacterController();
|
||||
CharacterController& getCharacterController() { return mCharacterController; }
|
||||
|
||||
int getGreetingTimer() const;
|
||||
void setGreetingTimer(int timer);
|
||||
int getGreetingTimer() const { return mGreetingTimer; }
|
||||
void setGreetingTimer(int timer) { mGreetingTimer = timer; }
|
||||
|
||||
float getAngleToPlayer() const;
|
||||
void setAngleToPlayer(float angle);
|
||||
float getAngleToPlayer() const { return mTargetAngleRadians; }
|
||||
void setAngleToPlayer(float angle) { mTargetAngleRadians = angle; }
|
||||
|
||||
GreetingState getGreetingState() const;
|
||||
void setGreetingState(GreetingState state);
|
||||
GreetingState getGreetingState() const { return mGreetingState; }
|
||||
void setGreetingState(GreetingState state) { mGreetingState = state; }
|
||||
|
||||
bool isTurningToPlayer() const;
|
||||
void setTurningToPlayer(bool turning);
|
||||
bool isTurningToPlayer() const { return mIsTurningToPlayer; }
|
||||
void setTurningToPlayer(bool turning) { mIsTurningToPlayer = turning; }
|
||||
|
||||
Misc::TimerStatus updateEngageCombatTimer(float duration);
|
||||
Misc::TimerStatus updateEngageCombatTimer(float duration)
|
||||
{
|
||||
return mEngageCombat.update(duration, MWBase::Environment::get().getWorld()->getPrng());
|
||||
}
|
||||
|
||||
void setPositionAdjusted(bool adjusted);
|
||||
bool getPositionAdjusted() const;
|
||||
void setPositionAdjusted(bool adjusted) { mPositionAdjusted = adjusted; }
|
||||
bool getPositionAdjusted() const { return mPositionAdjusted; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<CharacterController> mCharacterController;
|
||||
CharacterController mCharacterController;
|
||||
int mGreetingTimer{0};
|
||||
float mTargetAngleRadians{0.f};
|
||||
GreetingState mGreetingState{Greet_None};
|
||||
|
@ -105,12 +105,12 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float
|
||||
}
|
||||
|
||||
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;
|
||||
if (iteratedActor == player || iteratedActor == actor)
|
||||
const MWWorld::Ptr &iteratedActor = actor.getPtr();
|
||||
if (iteratedActor == player || iteratedActor == actorPtr)
|
||||
continue;
|
||||
|
||||
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
|
||||
for (const auto& package : stats.getAiSequence())
|
||||
{
|
||||
if(!func(iter, package))
|
||||
if (!func(actor, package))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -771,32 +771,26 @@ namespace MWMechanics
|
||||
|
||||
bool Actors::isAttackPreparing(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
PtrActorMap::iterator it = mActors.find(ptr);
|
||||
if (it == mActors.end())
|
||||
const auto it = mIndex.find(ptr.mRef);
|
||||
if (it == mIndex.end())
|
||||
return false;
|
||||
CharacterController* ctrl = it->second->getCharacterController();
|
||||
|
||||
return ctrl->isAttackPreparing();
|
||||
return it->second->getCharacterController().isAttackPreparing();
|
||||
}
|
||||
|
||||
bool Actors::isRunning(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
PtrActorMap::iterator it = mActors.find(ptr);
|
||||
if (it == mActors.end())
|
||||
const auto it = mIndex.find(ptr.mRef);
|
||||
if (it == mIndex.end())
|
||||
return false;
|
||||
CharacterController* ctrl = it->second->getCharacterController();
|
||||
|
||||
return ctrl->isRunning();
|
||||
return it->second->getCharacterController().isRunning();
|
||||
}
|
||||
|
||||
bool Actors::isSneaking(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
PtrActorMap::iterator it = mActors.find(ptr);
|
||||
if (it == mActors.end())
|
||||
const auto it = mIndex.find(ptr.mRef);
|
||||
if (it == mIndex.end())
|
||||
return false;
|
||||
CharacterController* ctrl = it->second->getCharacterController();
|
||||
|
||||
return ctrl->isSneaking();
|
||||
return it->second->getCharacterController().isSneaking();
|
||||
}
|
||||
|
||||
void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration, bool isKnockedOut, bool isPlayer)
|
||||
@ -1031,11 +1025,6 @@ namespace MWMechanics
|
||||
updateProcessingRange();
|
||||
}
|
||||
|
||||
Actors::~Actors()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
float Actors::getProcessingRange() const
|
||||
{
|
||||
return mActorsProcessingRange;
|
||||
@ -1057,11 +1046,11 @@ namespace MWMechanics
|
||||
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
|
||||
if (!anim)
|
||||
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();
|
||||
if (updateImmediately)
|
||||
ctrl->update(0);
|
||||
it->getCharacterController().update(0);
|
||||
|
||||
// We should initially hide actors outside of processing range.
|
||||
// Note: since we update player after other actors, distance will be incorrect during teleportation.
|
||||
@ -1069,10 +1058,10 @@ namespace MWMechanics
|
||||
if (MWBase::Environment::get().getWorld()->getPlayer().wasTeleported())
|
||||
return;
|
||||
|
||||
updateVisibility(ptr, ctrl);
|
||||
updateVisibility(ptr, it->getCharacterController());
|
||||
}
|
||||
|
||||
void Actors::updateVisibility (const MWWorld::Ptr& ptr, CharacterController* ctrl)
|
||||
void Actors::updateVisibility (const MWWorld::Ptr& ptr, CharacterController& ctrl)
|
||||
{
|
||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||
if (ptr == player)
|
||||
@ -1097,26 +1086,26 @@ namespace MWMechanics
|
||||
|
||||
visibilityRatio = std::min(1.f, visibilityRatio);
|
||||
|
||||
ctrl->setVisibility(visibilityRatio);
|
||||
ctrl.setVisibility(visibilityRatio);
|
||||
}
|
||||
|
||||
void Actors::removeActor (const MWWorld::Ptr& ptr, bool keepActive)
|
||||
{
|
||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
||||
if(iter != mActors.end())
|
||||
const auto iter = mIndex.find(ptr.mRef);
|
||||
if (iter != mIndex.end())
|
||||
{
|
||||
if(!keepActive)
|
||||
removeTemporaryEffects(iter->first);
|
||||
delete iter->second;
|
||||
mActors.erase(iter);
|
||||
removeTemporaryEffects(iter->second->getPtr());
|
||||
mActors.erase(iter->second);
|
||||
mIndex.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void Actors::castSpell(const MWWorld::Ptr& ptr, const std::string& spellId, bool manualSpell)
|
||||
{
|
||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
||||
if(iter != mActors.end())
|
||||
iter->second->getCharacterController()->castSpell(spellId, manualSpell);
|
||||
const auto iter = mIndex.find(ptr.mRef);
|
||||
if (iter != mIndex.end())
|
||||
iter->second->getCharacterController().castSpell(spellId, manualSpell);
|
||||
}
|
||||
|
||||
bool Actors::isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer)
|
||||
@ -1153,27 +1142,20 @@ namespace MWMechanics
|
||||
|
||||
void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
|
||||
{
|
||||
PtrActorMap::iterator iter = mActors.find(old);
|
||||
if(iter != mActors.end())
|
||||
{
|
||||
Actor *actor = iter->second;
|
||||
mActors.erase(iter);
|
||||
|
||||
actor->updatePtr(ptr);
|
||||
mActors.insert(std::make_pair(ptr, actor));
|
||||
}
|
||||
const auto iter = mIndex.find(old.mRef);
|
||||
if (iter != mIndex.end())
|
||||
iter->second->updatePtr(ptr);
|
||||
}
|
||||
|
||||
void Actors::dropActors (const MWWorld::CellStore *cellStore, const MWWorld::Ptr& ignore)
|
||||
{
|
||||
PtrActorMap::iterator iter = mActors.begin();
|
||||
while(iter != mActors.end())
|
||||
for (auto iter = mActors.begin(); 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);
|
||||
delete iter->second;
|
||||
mActors.erase(iter++);
|
||||
removeTemporaryEffects(iter->getPtr());
|
||||
mIndex.erase(iter->getPtr().mRef);
|
||||
iter = mActors.erase(iter);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
@ -1189,14 +1171,14 @@ namespace MWMechanics
|
||||
|
||||
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)
|
||||
{
|
||||
MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
|
||||
MWMechanics::CreatureStats& stats = actor.getPtr().getClass().getCreatureStats(actor.getPtr());
|
||||
if (!stats.isDead() && stats.getAiSequence().isInCombat())
|
||||
{
|
||||
hasHostiles = true;
|
||||
@ -1235,9 +1217,9 @@ namespace MWMechanics
|
||||
|
||||
const MWWorld::Ptr player = getPlayer();
|
||||
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)
|
||||
continue; // Don't interfere with player controls.
|
||||
|
||||
@ -1297,9 +1279,9 @@ namespace MWMechanics
|
||||
float angleToApproachingActor = 0;
|
||||
|
||||
// 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)
|
||||
continue;
|
||||
|
||||
@ -1410,49 +1392,49 @@ namespace MWMechanics
|
||||
bool godmode = MWBase::Environment::get().getWorld()->getGodModeState();
|
||||
|
||||
// AI and magic effects update
|
||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
for (Actor& actor : mActors)
|
||||
{
|
||||
bool isPlayer = iter->first == player;
|
||||
CharacterController* ctrl = iter->second->getCharacterController();
|
||||
const bool isPlayer = actor.getPtr() == player;
|
||||
CharacterController& ctrl = actor.getCharacterController();
|
||||
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.
|
||||
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 (iter->first != player && (iter->first.getClass().getCreatureStats(iter->first).isDead()
|
||||
|| !iter->first.getClass().getCreatureStats(iter->first).getAiSequence().isInCombat()
|
||||
if (actor.getPtr() != player && (actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDead()
|
||||
|| !actor.getPtr().getClass().getCreatureStats(actor.getPtr()).getAiSequence().isInCombat()
|
||||
|| !inProcessingRange))
|
||||
{
|
||||
iter->first.getClass().getCreatureStats(iter->first).setHitAttemptActorId(-1);
|
||||
if (player.getClass().getCreatureStats(player).getHitAttemptActorId() == iter->first.getClass().getCreatureStats(iter->first).getActorId())
|
||||
actor.getPtr().getClass().getCreatureStats(actor.getPtr()).setHitAttemptActorId(-1);
|
||||
if (player.getClass().getCreatureStats(player).getHitAttemptActorId() == actor.getPtr().getClass().getCreatureStats(actor.getPtr()).getActorId())
|
||||
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
|
||||
if (iter->first.getClass().getCreatureStats(iter->first).isDead())
|
||||
if (actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDead())
|
||||
{
|
||||
// They can be added during the death animation
|
||||
if (!iter->first.getClass().getCreatureStats(iter->first).isDeathAnimationFinished())
|
||||
adjustMagicEffects(iter->first, duration);
|
||||
ctrl->updateContinuousVfx();
|
||||
if (!actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDeathAnimationFinished())
|
||||
adjustMagicEffects(actor.getPtr(), duration);
|
||||
ctrl.updateContinuousVfx();
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
updateActor(actor, duration);
|
||||
const MWWorld::Ptr actorPtr = actor.getPtr(); // make a copy of the map key to avoid it being invalidated when the player teleports
|
||||
updateActor(actorPtr, duration);
|
||||
|
||||
// Looping magic VFX update
|
||||
// Note: we need to do this before any of the animations are updated.
|
||||
// Reaching the text keys may trigger Hit / Spellcast (and as such, particles),
|
||||
// so updating VFX immediately after that would just remove the particle effects instantly.
|
||||
// There needs to be a magic effect update in between.
|
||||
ctrl->updateContinuousVfx();
|
||||
ctrl.updateContinuousVfx();
|
||||
|
||||
if (!cellChanged && world->hasCellChanged())
|
||||
{
|
||||
@ -1464,13 +1446,13 @@ namespace MWMechanics
|
||||
if (engageCombatTimerStatus == Misc::TimerStatus::Elapsed)
|
||||
{
|
||||
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;
|
||||
engageCombat(iter->first, it->first, cachedAllies, it->first == player);
|
||||
engageCombat(actor.getPtr(), otherActor.getPtr(), cachedAllies, otherActor.getPtr() == player);
|
||||
}
|
||||
}
|
||||
if (mTimerUpdateHeadTrack == 0)
|
||||
@ -1478,7 +1460,7 @@ namespace MWMechanics
|
||||
float sqrHeadTrackDistance = std::numeric_limits<float>::max();
|
||||
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();
|
||||
|
||||
// 1. Unconsious actor can not track target
|
||||
@ -1493,58 +1475,58 @@ namespace MWMechanics
|
||||
if (!activePackageTarget.isEmpty())
|
||||
{
|
||||
// Track the specified target of package.
|
||||
updateHeadTracking(iter->first, activePackageTarget, headTrackTarget, sqrHeadTrackDistance, inCombatOrPursue);
|
||||
updateHeadTracking(actor.getPtr(), activePackageTarget, headTrackTarget, sqrHeadTrackDistance, inCombatOrPursue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find something nearby.
|
||||
for (auto& [ptr, _] : mActors)
|
||||
for (const Actor& otherActor : mActors)
|
||||
{
|
||||
if (ptr == iter->first)
|
||||
if (otherActor.getPtr() == actor.getPtr())
|
||||
continue;
|
||||
|
||||
updateHeadTracking(iter->first, ptr, headTrackTarget, sqrHeadTrackDistance, inCombatOrPursue);
|
||||
updateHeadTracking(actor.getPtr(), otherActor.getPtr(), headTrackTarget, sqrHeadTrackDistance, inCombatOrPursue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctrl->setHeadTrackTarget(headTrackTarget);
|
||||
ctrl.setHeadTrackTarget(headTrackTarget);
|
||||
}
|
||||
|
||||
if (iter->first.getClass().isNpc() && iter->first != player)
|
||||
updateCrimePursuit(iter->first, duration);
|
||||
if (actor.getPtr().getClass().isNpc() && actor.getPtr() != player)
|
||||
updateCrimePursuit(actor.getPtr(), duration);
|
||||
|
||||
if (iter->first != player)
|
||||
if (actor.getPtr() != player)
|
||||
{
|
||||
CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first);
|
||||
if (isConscious(iter->first) && !(luaControls && luaControls->mDisableAI))
|
||||
CreatureStats &stats = actor.getPtr().getClass().getCreatureStats(actor.getPtr());
|
||||
if (isConscious(actor.getPtr()) && !(luaControls && luaControls->mDisableAI))
|
||||
{
|
||||
stats.getAiSequence().execute(iter->first, *ctrl, duration);
|
||||
updateGreetingState(iter->first, *iter->second, mTimerUpdateHello > 0);
|
||||
playIdleDialogue(iter->first);
|
||||
updateMovementSpeed(iter->first);
|
||||
stats.getAiSequence().execute(actor.getPtr(), ctrl, duration);
|
||||
updateGreetingState(actor.getPtr(), actor, mTimerUpdateHello > 0);
|
||||
playIdleDialogue(actor.getPtr());
|
||||
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);
|
||||
stats.getAiSequence().execute(iter->first, *ctrl, duration, /*outOfRange*/true);
|
||||
CreatureStats &stats = actor.getPtr().getClass().getCreatureStats(actor.getPtr());
|
||||
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
|
||||
updateDrowning(iter->first, duration, ctrl->isKnockedOut(), isPlayer);
|
||||
updateDrowning(actor.getPtr(), duration, ctrl.isKnockedOut(), isPlayer);
|
||||
}
|
||||
if(mTimerUpdateEquippedLight == 0 && iter->first.getClass().hasInventoryStore(iter->first))
|
||||
updateEquippedLight(iter->first, updateEquippedLightInterval, showTorches);
|
||||
if (mTimerUpdateEquippedLight == 0 && actor.getPtr().getClass().hasInventoryStore(actor.getPtr()))
|
||||
updateEquippedLight(actor.getPtr(), updateEquippedLightInterval, showTorches);
|
||||
|
||||
if (luaControls && isConscious(iter->first))
|
||||
if (luaControls && isConscious(actor.getPtr()))
|
||||
{
|
||||
Movement& mov = iter->first.getClass().getMovementSettings(iter->first);
|
||||
CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
|
||||
Movement& mov = actor.getPtr().getClass().getMovementSettings(actor.getPtr());
|
||||
CreatureStats& stats = actor.getPtr().getClass().getCreatureStats(actor.getPtr());
|
||||
float speedFactor = isPlayer ? 1.f : mov.mSpeedFactor;
|
||||
osg::Vec2f movement = osg::Vec2f(mov.mPosition[0], mov.mPosition[1]) * speedFactor;
|
||||
float rotationX = mov.mRotation[0];
|
||||
@ -1587,14 +1569,14 @@ namespace MWMechanics
|
||||
|
||||
// Animation/movement update
|
||||
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();
|
||||
bool isPlayer = iter->first == player;
|
||||
CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first);
|
||||
const float dist = (playerPos - actor.getPtr().getRefData().getPosition().asVec3()).length();
|
||||
const bool isPlayer = actor.getPtr() == player;
|
||||
CreatureStats &stats = actor.getPtr().getClass().getCreatureStats(actor.getPtr());
|
||||
// Actors with active AI should be able to move.
|
||||
bool alwaysActive = false;
|
||||
if (!isPlayer && isConscious(iter->first) && !stats.isParalyzed())
|
||||
if (!isPlayer && isConscious(actor.getPtr()) && !stats.isParalyzed())
|
||||
{
|
||||
MWMechanics::AiSequence& seq = stats.getAiSequence();
|
||||
alwaysActive = !seq.isEmpty() && seq.getActivePackage().alwaysActive();
|
||||
@ -1605,41 +1587,41 @@ namespace MWMechanics
|
||||
activeFlag = 2;
|
||||
int active = inRange ? activeFlag : 0;
|
||||
|
||||
CharacterController* ctrl = iter->second->getCharacterController();
|
||||
ctrl->setActive(active);
|
||||
CharacterController& ctrl = actor.getCharacterController();
|
||||
ctrl.setActive(active);
|
||||
|
||||
if (!inRange)
|
||||
{
|
||||
iter->first.getRefData().getBaseNode()->setNodeMask(0);
|
||||
world->setActorCollisionMode(iter->first, false, false);
|
||||
actor.getPtr().getRefData().getBaseNode()->setNodeMask(0);
|
||||
world->setActorCollisionMode(actor.getPtr(), false, false);
|
||||
continue;
|
||||
}
|
||||
else if (!isPlayer)
|
||||
{
|
||||
iter->first.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Actor);
|
||||
if (!iter->second->getPositionAdjusted())
|
||||
actor.getPtr().getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Actor);
|
||||
if (!actor.getPositionAdjusted())
|
||||
{
|
||||
iter->first.getClass().adjustPosition(iter->first, false);
|
||||
iter->second->setPositionAdjusted(true);
|
||||
actor.getPtr().getClass().adjustPosition(actor.getPtr(), false);
|
||||
actor.setPositionAdjusted(true);
|
||||
}
|
||||
}
|
||||
|
||||
const bool isDead = iter->first.getClass().getCreatureStats(iter->first).isDead();
|
||||
if (!isDead && (!godmode || !isPlayer) && iter->first.getClass().getCreatureStats(iter->first).isParalyzed())
|
||||
ctrl->skipAnim();
|
||||
const bool isDead = actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDead();
|
||||
if (!isDead && (!godmode || !isPlayer) && actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isParalyzed())
|
||||
ctrl.skipAnim();
|
||||
|
||||
// Handle player last, in case a cell transition occurs by casting a teleportation spell
|
||||
// (would invalidate the iterator)
|
||||
if (iter->first == getPlayer())
|
||||
if (actor.getPtr() == getPlayer())
|
||||
{
|
||||
playerCharacter = ctrl;
|
||||
playerCharacter = &ctrl;
|
||||
continue;
|
||||
}
|
||||
|
||||
world->setActorCollisionMode(iter->first, true, !iter->first.getClass().getCreatureStats(iter->first).isDeathAnimationFinished());
|
||||
ctrl->update(duration);
|
||||
world->setActorCollisionMode(actor.getPtr(), true, !actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDeathAnimationFinished());
|
||||
ctrl.update(duration);
|
||||
|
||||
updateVisibility(iter->first, ctrl);
|
||||
updateVisibility(actor.getPtr(), ctrl);
|
||||
}
|
||||
|
||||
if (playerCharacter)
|
||||
@ -1649,10 +1631,10 @@ namespace MWMechanics
|
||||
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();
|
||||
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
||||
const MWWorld::Class &cls = actor.getPtr().getClass();
|
||||
CreatureStats &stats = cls.getCreatureStats(actor.getPtr());
|
||||
|
||||
//KnockedOutOneFrameLogic
|
||||
//Used for "OnKnockedOut" command
|
||||
@ -1684,53 +1666,53 @@ namespace MWMechanics
|
||||
|
||||
void Actors::resurrect(const MWWorld::Ptr &ptr)
|
||||
{
|
||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
||||
if(iter != mActors.end())
|
||||
const auto iter = mIndex.find(ptr.mRef);
|
||||
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.
|
||||
MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, true);
|
||||
iter->second->getCharacterController()->resurrect();
|
||||
MWBase::Environment::get().getWorld()->enableActorCollision(iter->second->getPtr(), true);
|
||||
iter->second->getCharacterController().resurrect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Actors::killDeadActors()
|
||||
{
|
||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
for (Actor& actor : mActors)
|
||||
{
|
||||
const MWWorld::Class &cls = iter->first.getClass();
|
||||
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
||||
const MWWorld::Class &cls = actor.getPtr().getClass();
|
||||
CreatureStats &stats = cls.getCreatureStats(actor.getPtr());
|
||||
|
||||
if(!stats.isDead())
|
||||
continue;
|
||||
|
||||
MWBase::Environment::get().getWorld()->removeActorPath(iter->first);
|
||||
CharacterController::KillResult killResult = iter->second->getCharacterController()->kill();
|
||||
MWBase::Environment::get().getWorld()->removeActorPath(actor.getPtr());
|
||||
CharacterController::KillResult killResult = actor.getCharacterController().kill();
|
||||
if (killResult == CharacterController::Result_DeathAnimStarted)
|
||||
{
|
||||
// Play dying words
|
||||
// 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.
|
||||
MWBase::Environment::get().getDialogueManager()->say(iter->first, "hit");
|
||||
MWBase::Environment::get().getDialogueManager()->say(actor.getPtr(), "hit");
|
||||
|
||||
// Apply soultrap
|
||||
if (iter->first.getType() == ESM::Creature::sRecordId)
|
||||
soulTrap(iter->first);
|
||||
if (actor.getPtr().getType() == ESM::Creature::sRecordId)
|
||||
soulTrap(actor.getPtr());
|
||||
|
||||
if (cls.isEssential(iter->first))
|
||||
if (cls.isEssential(actor.getPtr()))
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}");
|
||||
}
|
||||
else if (killResult == CharacterController::Result_DeathAnimJustFinished)
|
||||
{
|
||||
bool isPlayer = iter->first == getPlayer();
|
||||
notifyDied(iter->first);
|
||||
const bool isPlayer = actor.getPtr() == getPlayer();
|
||||
notifyDied(actor.getPtr());
|
||||
|
||||
// Reset magic effects and recalculate derived effects
|
||||
// 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();
|
||||
stats.getActiveSpells().clear(iter->first);
|
||||
stats.getActiveSpells().clear(actor.getPtr());
|
||||
// Make sure spell effects are removed
|
||||
purgeSpellEffects(stats.getActorId());
|
||||
|
||||
@ -1746,7 +1728,7 @@ namespace MWMechanics
|
||||
else
|
||||
{
|
||||
// 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 +1767,10 @@ namespace MWMechanics
|
||||
|
||||
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();
|
||||
spells.purge(iter->first, casterActorId);
|
||||
MWMechanics::ActiveSpells& spells = actor.getPtr().getClass().getCreatureStats(actor.getPtr()).getActiveSpells();
|
||||
spells.purge(actor.getPtr(), casterActorId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1802,28 +1784,28 @@ namespace MWMechanics
|
||||
const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
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;
|
||||
}
|
||||
|
||||
if (!sleep || iter->first == player)
|
||||
restoreDynamicStats(iter->first, hours, sleep);
|
||||
if (!sleep || actor.getPtr() == player)
|
||||
restoreDynamicStats(actor.getPtr(), hours, sleep);
|
||||
|
||||
if ((!iter->first.getRefData().getBaseNode()) ||
|
||||
(playerPos - iter->first.getRefData().getPosition().asVec3()).length2() > mActorsProcessingRange*mActorsProcessingRange)
|
||||
if ((!actor.getPtr().getRefData().getBaseNode()) ||
|
||||
(playerPos - actor.getPtr().getRefData().getPosition().asVec3()).length2() > mActorsProcessingRange*mActorsProcessingRange)
|
||||
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)
|
||||
{
|
||||
animation->removeEffects();
|
||||
MWBase::Environment::get().getWorld()->applyLoopingParticles(iter->first);
|
||||
MWBase::Environment::get().getWorld()->applyLoopingParticles(actor.getPtr());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1935,17 +1917,17 @@ namespace MWMechanics
|
||||
|
||||
void Actors::forceStateUpdate(const MWWorld::Ptr & ptr)
|
||||
{
|
||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
||||
if(iter != mActors.end())
|
||||
iter->second->getCharacterController()->forceStateUpdate();
|
||||
const auto iter = mIndex.find(ptr.mRef);
|
||||
if (iter != mIndex.end())
|
||||
iter->second->getCharacterController().forceStateUpdate();
|
||||
}
|
||||
|
||||
bool Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist)
|
||||
{
|
||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
||||
if(iter != mActors.end())
|
||||
const auto iter = mIndex.find(ptr.mRef);
|
||||
if(iter != mIndex.end())
|
||||
{
|
||||
return iter->second->getCharacterController()->playGroup(groupName, mode, number, persist);
|
||||
return iter->second->getCharacterController().playGroup(groupName, mode, number, persist);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1955,55 +1937,55 @@ namespace MWMechanics
|
||||
}
|
||||
void Actors::skipAnimation(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
||||
if(iter != mActors.end())
|
||||
iter->second->getCharacterController()->skipAnim();
|
||||
const auto iter = mIndex.find(ptr.mRef);
|
||||
if (iter != mIndex.end())
|
||||
iter->second->getCharacterController().skipAnim();
|
||||
}
|
||||
|
||||
bool Actors::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName)
|
||||
{
|
||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
||||
if(iter != mActors.end())
|
||||
return iter->second->getCharacterController()->isAnimPlaying(groupName);
|
||||
const auto iter = mIndex.find(ptr.mRef);
|
||||
if(iter != mIndex.end())
|
||||
return iter->second->getCharacterController().isAnimPlaying(groupName);
|
||||
return false;
|
||||
}
|
||||
|
||||
void Actors::persistAnimationStates()
|
||||
{
|
||||
for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
|
||||
iter->second->getCharacterController()->persistAnimationState();
|
||||
for (Actor& actor : mActors)
|
||||
actor.getCharacterController().persistAnimationState();
|
||||
}
|
||||
|
||||
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)
|
||||
out.push_back(iter->first);
|
||||
if ((actor.getPtr().getRefData().getPosition().asVec3() - position).length2() <= radius*radius)
|
||||
out.push_back(actor.getPtr());
|
||||
}
|
||||
}
|
||||
|
||||
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 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;
|
||||
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())
|
||||
continue;
|
||||
|
||||
const bool sameActor = (iteratedActor == actor);
|
||||
const bool sameActor = (iteratedActor == actorPtr);
|
||||
|
||||
const CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor);
|
||||
if (stats.isDead())
|
||||
@ -2019,7 +2001,7 @@ namespace MWMechanics
|
||||
{
|
||||
list.push_back(package->getTarget());
|
||||
}
|
||||
else if (package->getTarget() == actor)
|
||||
else if (package->getTarget() == actorPtr)
|
||||
{
|
||||
list.push_back(iteratedActor);
|
||||
}
|
||||
@ -2032,13 +2014,13 @@ namespace MWMechanics
|
||||
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;
|
||||
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)
|
||||
list.push_back(iter.first);
|
||||
if (package->followTargetThroughDoors() && package->getTarget() == actorPtr)
|
||||
list.push_back(actor.getPtr());
|
||||
else if (package->getTypeId() != AiPackageTypeId::Combat && package->getTypeId() != AiPackageTypeId::Wander)
|
||||
return false;
|
||||
return true;
|
||||
@ -2086,7 +2068,7 @@ namespace MWMechanics
|
||||
std::vector<int> Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -2103,12 +2085,12 @@ namespace MWMechanics
|
||||
std::map<int, MWWorld::Ptr> Actors::getActorsFollowingByIndex(const MWWorld::Ptr &actor)
|
||||
{
|
||||
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)
|
||||
{
|
||||
int index = static_cast<const AiFollow*>(package.get())->getFollowIndex();
|
||||
map[index] = iter.first;
|
||||
map[index] = otherActor.getPtr();
|
||||
return false;
|
||||
}
|
||||
else if (package->getTypeId() != AiPackageTypeId::Combat && package->getTypeId() != AiPackageTypeId::Wander)
|
||||
@ -2190,12 +2172,7 @@ namespace MWMechanics
|
||||
|
||||
void Actors::clear()
|
||||
{
|
||||
PtrActorMap::iterator it(mActors.begin());
|
||||
for (; it != mActors.end(); ++it)
|
||||
{
|
||||
delete it->second;
|
||||
it->second = nullptr;
|
||||
}
|
||||
mIndex.clear();
|
||||
mActors.clear();
|
||||
mDeathCount.clear();
|
||||
}
|
||||
@ -2207,36 +2184,35 @@ namespace MWMechanics
|
||||
|
||||
bool Actors::isReadyToBlock(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
||||
if (it == mActors.end())
|
||||
const auto it = mIndex.find(ptr.mRef);
|
||||
if (it == mIndex.end())
|
||||
return false;
|
||||
|
||||
return it->second->getCharacterController()->isReadyToBlock();
|
||||
return it->second->getCharacterController().isReadyToBlock();
|
||||
}
|
||||
|
||||
bool Actors::isCastingSpell(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
||||
if (it == mActors.end())
|
||||
const auto it = mIndex.find(ptr.mRef);
|
||||
if (it == mIndex.end())
|
||||
return false;
|
||||
|
||||
return it->second->getCharacterController()->isCastingSpell();
|
||||
return it->second->getCharacterController().isCastingSpell();
|
||||
}
|
||||
|
||||
bool Actors::isAttackingOrSpell(const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
||||
if (it == mActors.end())
|
||||
const auto it = mIndex.find(ptr.mRef);
|
||||
if (it == mIndex.end())
|
||||
return false;
|
||||
CharacterController* ctrl = it->second->getCharacterController();
|
||||
|
||||
return ctrl->isAttackingOrSpell();
|
||||
return it->second->getCharacterController().isAttackingOrSpell();
|
||||
}
|
||||
|
||||
int Actors::getGreetingTimer(const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
||||
if (it == mActors.end())
|
||||
const auto it = mIndex.find(ptr.mRef);
|
||||
if (it == mIndex.end())
|
||||
return 0;
|
||||
|
||||
return it->second->getGreetingTimer();
|
||||
@ -2244,8 +2220,8 @@ namespace MWMechanics
|
||||
|
||||
float Actors::getAngleToPlayer(const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
||||
if (it == mActors.end())
|
||||
const auto it = mIndex.find(ptr.mRef);
|
||||
if (it == mIndex.end())
|
||||
return 0.f;
|
||||
|
||||
return it->second->getAngleToPlayer();
|
||||
@ -2253,8 +2229,8 @@ namespace MWMechanics
|
||||
|
||||
GreetingState Actors::getGreetingState(const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
||||
if (it == mActors.end())
|
||||
const auto it = mIndex.find(ptr.mRef);
|
||||
if (it == mIndex.end())
|
||||
return Greet_None;
|
||||
|
||||
return it->second->getGreetingState();
|
||||
@ -2262,8 +2238,8 @@ namespace MWMechanics
|
||||
|
||||
bool Actors::isTurningToPlayer(const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
||||
if (it == mActors.end())
|
||||
const auto it = mIndex.find(ptr.mRef);
|
||||
if (it == mIndex.end())
|
||||
return false;
|
||||
|
||||
return it->second->isTurningToPlayer();
|
||||
@ -2274,11 +2250,9 @@ namespace MWMechanics
|
||||
if (!MWBase::Environment::get().getMechanicsManager()->isAIActive())
|
||||
return;
|
||||
|
||||
// making a copy since fast-forward could move actor to a different cell and invalidate the mActors iterator
|
||||
PtrActorMap map = mActors;
|
||||
for (PtrActorMap::iterator it = map.begin(); it != map.end(); ++it)
|
||||
for (const Actor& actor : mActors)
|
||||
{
|
||||
MWWorld::Ptr ptr = it->first;
|
||||
const MWWorld::Ptr ptr = actor.getPtr();
|
||||
if (ptr == getPlayer()
|
||||
|| !isConscious(ptr)
|
||||
|| ptr.getClass().getCreatureStats(ptr).isParalyzed())
|
||||
|
@ -7,7 +7,8 @@
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
#include "actorutil.hpp"
|
||||
#include "actor.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
@ -42,12 +43,9 @@ namespace MWMechanics
|
||||
public:
|
||||
|
||||
Actors();
|
||||
~Actors();
|
||||
|
||||
typedef std::map<MWWorld::Ptr,Actor*> PtrActorMap;
|
||||
|
||||
PtrActorMap::const_iterator begin() { return mActors.begin(); }
|
||||
PtrActorMap::const_iterator end() { return mActors.end(); }
|
||||
std::list<Actor>::const_iterator begin() const { return mActors.begin(); }
|
||||
std::list<Actor>::const_iterator end() const { return mActors.end(); }
|
||||
std::size_t size() const { return mActors.size(); }
|
||||
|
||||
void notifyDied(const MWWorld::Ptr &actor);
|
||||
@ -190,7 +188,8 @@ namespace MWMechanics
|
||||
};
|
||||
|
||||
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 mTimerUpdateHeadTrack = 0;
|
||||
float mTimerUpdateEquippedLight = 0;
|
||||
@ -201,7 +200,7 @@ namespace MWMechanics
|
||||
bool mSmoothMovement;
|
||||
MusicType mCurrentMusic = MusicType::Explore;
|
||||
|
||||
void updateVisibility (const MWWorld::Ptr& ptr, CharacterController* ctrl);
|
||||
void updateVisibility (const MWWorld::Ptr& ptr, CharacterController& ctrl);
|
||||
|
||||
void adjustMagicEffects (const MWWorld::Ptr& creature, float duration);
|
||||
|
||||
|
@ -241,7 +241,10 @@ public:
|
||||
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
|
||||
virtual ~CharacterController();
|
||||
|
||||
const MWWorld::Ptr& getPtr() const { return mPtr; };
|
||||
CharacterController(const CharacterController&) = delete;
|
||||
CharacterController(CharacterController&&) = delete;
|
||||
|
||||
const MWWorld::Ptr& getPtr() const { return mPtr; }
|
||||
|
||||
void handleTextKey(const std::string &groupname, SceneUtil::TextKeyMap::ConstIterator key, const SceneUtil::TextKeyMap& map) override;
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "npcstats.hpp"
|
||||
#include "actorutil.hpp"
|
||||
#include "combat.hpp"
|
||||
#include "actor.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -1599,16 +1600,16 @@ namespace MWMechanics
|
||||
if (ptr.getClass().isClass(ptr, "Guard"))
|
||||
{
|
||||
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)
|
||||
{
|
||||
aiSeq.stopPursuit();
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,12 +22,12 @@ void Objects::addObject(const MWWorld::Ptr& ptr)
|
||||
return;
|
||||
|
||||
const auto it = mObjects.emplace(mObjects.end(), ptr, anim);
|
||||
mIndex.emplace(ptr.getBase(), it);
|
||||
mIndex.emplace(ptr.mRef, it);
|
||||
}
|
||||
|
||||
void Objects::removeObject(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
const auto iter = mIndex.find(ptr.getBase());
|
||||
const auto iter = mIndex.find(ptr.mRef);
|
||||
if (iter != mIndex.end())
|
||||
{
|
||||
mObjects.erase(iter->second);
|
||||
@ -37,7 +37,7 @@ void Objects::removeObject(const MWWorld::Ptr& ptr)
|
||||
|
||||
void Objects::updateObject(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
|
||||
{
|
||||
const auto iter = mIndex.find(old.getBase());
|
||||
const auto iter = mIndex.find(old.mRef);
|
||||
if (iter != mIndex.end())
|
||||
iter->second->updatePtr(ptr);
|
||||
}
|
||||
@ -48,7 +48,7 @@ void Objects::dropObjects (const MWWorld::CellStore *cellStore)
|
||||
{
|
||||
if (iter->getPtr().getCell() == cellStore)
|
||||
{
|
||||
mIndex.erase(iter->getPtr().getBase());
|
||||
mIndex.erase(iter->getPtr().mRef);
|
||||
iter = mObjects.erase(iter);
|
||||
}
|
||||
else
|
||||
@ -86,7 +86,7 @@ void Objects::update(float duration, bool paused)
|
||||
|
||||
bool Objects::onOpen(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
const auto iter = mIndex.find(ptr.getBase());
|
||||
const auto iter = mIndex.find(ptr.mRef);
|
||||
if (iter != mIndex.end())
|
||||
return iter->second->onOpen();
|
||||
return true;
|
||||
@ -94,14 +94,14 @@ bool Objects::onOpen(const MWWorld::Ptr& ptr)
|
||||
|
||||
void Objects::onClose(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
const auto iter = mIndex.find(ptr.getBase());
|
||||
const auto iter = mIndex.find(ptr.mRef);
|
||||
if (iter != mIndex.end())
|
||||
iter->second->onClose();
|
||||
}
|
||||
|
||||
bool Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist)
|
||||
{
|
||||
const auto iter = mIndex.find(ptr.getBase());
|
||||
const auto iter = mIndex.find(ptr.mRef);
|
||||
if (iter != mIndex.end())
|
||||
{
|
||||
return iter->second->playGroup(groupName, mode, number, persist);
|
||||
@ -114,7 +114,7 @@ bool Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& gro
|
||||
}
|
||||
void Objects::skipAnimation(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
const auto iter = mIndex.find(ptr.getBase());
|
||||
const auto iter = mIndex.find(ptr.mRef);
|
||||
if (iter != mIndex.end())
|
||||
iter->second->skipAnim();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user