1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-23 22:09:45 +00:00

Add MWMechanics::Actor class for temporary actor state, move AiState there

This commit is contained in:
scrawl 2014-12-21 16:45:30 +01:00
parent 42d63a4eb2
commit edc128572d
7 changed files with 124 additions and 55 deletions

View file

@ -76,7 +76,7 @@ add_openmw_dir (mwmechanics
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor
aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor
) )
add_openmw_dir (mwstate add_openmw_dir (mwstate

View file

@ -0,0 +1,28 @@
#include "actor.hpp"
#include "character.hpp"
namespace MWMechanics
{
Actor::Actor(const MWWorld::Ptr &ptr, MWRender::Animation *animation)
{
mCharacterController.reset(new CharacterController(ptr, animation));
}
void Actor::updatePtr(const MWWorld::Ptr &newPtr)
{
mCharacterController->updatePtr(newPtr);
}
CharacterController* Actor::getCharacterController()
{
return mCharacterController.get();
}
AiState& Actor::getAiState()
{
return mAiState;
}
}

View file

@ -0,0 +1,42 @@
#ifndef OPENMW_MECHANICS_ACTOR_H
#define OPENMW_MECHANICS_ACTOR_H
#include <memory>
#include "aistate.hpp"
namespace MWRender
{
class Animation;
}
namespace MWWorld
{
class Ptr;
}
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);
/// Notify this actor of its new base object Ptr, use when the object changed cells
void updatePtr(const MWWorld::Ptr& newPtr);
CharacterController* getCharacterController();
AiState& getAiState();
private:
std::auto_ptr<CharacterController> mCharacterController;
AiState mAiState;
};
}
#endif

View file

@ -35,6 +35,8 @@
#include "aifollow.hpp" #include "aifollow.hpp"
#include "aipursue.hpp" #include "aipursue.hpp"
#include "actor.hpp"
namespace namespace
{ {
@ -920,10 +922,10 @@ namespace MWMechanics
void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration) void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration)
{ {
PtrControllerMap::iterator it = mActors.find(ptr); PtrActorMap::iterator it = mActors.find(ptr);
if (it == mActors.end()) if (it == mActors.end())
return; return;
CharacterController* ctrl = it->second; CharacterController* ctrl = it->second->getCharacterController();
NpcStats &stats = ptr.getClass().getNpcStats(ptr); NpcStats &stats = ptr.getClass().getNpcStats(ptr);
MWBase::World *world = MWBase::Environment::get().getWorld(); MWBase::World *world = MWBase::Environment::get().getWorld();
@ -1128,14 +1130,14 @@ namespace MWMechanics
removeActor(ptr); removeActor(ptr);
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
mActors.insert(std::make_pair(ptr, new CharacterController(ptr, anim))); mActors.insert(std::make_pair(ptr, new Actor(ptr, anim)));
if (updateImmediately) if (updateImmediately)
mActors[ptr]->update(0); mActors[ptr]->getCharacterController()->update(0);
} }
void Actors::removeActor (const MWWorld::Ptr& ptr) void Actors::removeActor (const MWWorld::Ptr& ptr)
{ {
PtrControllerMap::iterator iter = mActors.find(ptr); PtrActorMap::iterator iter = mActors.find(ptr);
if(iter != mActors.end()) if(iter != mActors.end())
{ {
delete iter->second; delete iter->second;
@ -1145,20 +1147,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)
{ {
PtrControllerMap::iterator iter = mActors.find(old); PtrActorMap::iterator iter = mActors.find(old);
if(iter != mActors.end()) if(iter != mActors.end())
{ {
CharacterController *ctrl = iter->second; Actor *actor = iter->second;
mActors.erase(iter); mActors.erase(iter);
ctrl->updatePtr(ptr); actor->updatePtr(ptr);
mActors.insert(std::make_pair(ptr, ctrl)); 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)
{ {
PtrControllerMap::iterator iter = mActors.begin(); PtrActorMap::iterator iter = mActors.begin();
while(iter != mActors.end()) while(iter != mActors.end())
{ {
if(iter->first.getCell()==cellStore && iter->first != ignore) if(iter->first.getCell()==cellStore && iter->first != ignore)
@ -1192,8 +1194,10 @@ namespace MWMechanics
// using higher values will make a quest in Bloodmoon harder or impossible to complete (bug #1876) // using higher values will make a quest in Bloodmoon harder or impossible to complete (bug #1876)
const float sqrProcessingDistance = 7168*7168; const float sqrProcessingDistance = 7168*7168;
/// \todo move update logic to Actor class where appropriate
// AI and magic effects update // AI and magic effects update
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{ {
if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) if (!iter->first.getClass().getCreatureStats(iter->first).isDead())
{ {
@ -1207,7 +1211,7 @@ namespace MWMechanics
if (iter->first != player) if (iter->first != player)
adjustCommandedActor(iter->first); adjustCommandedActor(iter->first);
for(PtrControllerMap::iterator it(mActors.begin()); it != mActors.end(); ++it) for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it)
{ {
if (it->first == iter->first || iter->first == player) // player is not AI-controlled if (it->first == iter->first || iter->first == player) // player is not AI-controlled
continue; continue;
@ -1219,13 +1223,13 @@ namespace MWMechanics
float sqrHeadTrackDistance = std::numeric_limits<float>::max(); float sqrHeadTrackDistance = std::numeric_limits<float>::max();
MWWorld::Ptr headTrackTarget; MWWorld::Ptr headTrackTarget;
for(PtrControllerMap::iterator it(mActors.begin()); it != mActors.end(); ++it) for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it)
{ {
if (it->first == iter->first) if (it->first == iter->first)
continue; continue;
updateHeadTracking(iter->first, it->first, headTrackTarget, sqrHeadTrackDistance); updateHeadTracking(iter->first, it->first, headTrackTarget, sqrHeadTrackDistance);
} }
iter->second->setHeadTrackTarget(headTrackTarget); iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget);
} }
if (iter->first.getClass().isNpc() && iter->first != player) if (iter->first.getClass().isNpc() && iter->first != player)
@ -1254,12 +1258,12 @@ namespace MWMechanics
// Reaching the text keys may trigger Hit / Spellcast (and as such, particles), // 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. // so updating VFX immediately after that would just remove the particle effects instantly.
// There needs to be a magic effect update in between. // There needs to be a magic effect update in between.
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
iter->second->updateContinuousVfx(); iter->second->getCharacterController()->updateContinuousVfx();
// Animation/movement update // Animation/movement update
CharacterController* playerCharacter = NULL; CharacterController* playerCharacter = NULL;
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{ {
if (iter->first != player && if (iter->first != player &&
Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(iter->first.getRefData().getPosition().pos)) Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(iter->first.getRefData().getPosition().pos))
@ -1268,22 +1272,22 @@ namespace MWMechanics
if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get( if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get(
ESM::MagicEffect::Paralyze).getMagnitude() > 0) ESM::MagicEffect::Paralyze).getMagnitude() > 0)
iter->second->skipAnim(); iter->second->getCharacterController()->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.getCellRef().getRefId() == "player") if (iter->first.getCellRef().getRefId() == "player")
{ {
playerCharacter = iter->second; playerCharacter = iter->second->getCharacterController();
continue; continue;
} }
iter->second->update(duration); iter->second->getCharacterController()->update(duration);
} }
if (playerCharacter) if (playerCharacter)
playerCharacter->update(duration); playerCharacter->update(duration);
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{ {
const MWWorld::Class &cls = iter->first.getClass(); const MWWorld::Class &cls = iter->first.getClass();
CreatureStats &stats = cls.getCreatureStats(iter->first); CreatureStats &stats = cls.getCreatureStats(iter->first);
@ -1341,7 +1345,7 @@ namespace MWMechanics
bool detected = false; bool detected = false;
for (PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) for (PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{ {
if (iter->first == player) // not the player if (iter->first == player) // not the player
continue; continue;
@ -1384,32 +1388,32 @@ namespace MWMechanics
void Actors::killDeadActors() void Actors::killDeadActors()
{ {
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{ {
const MWWorld::Class &cls = iter->first.getClass(); const MWWorld::Class &cls = iter->first.getClass();
CreatureStats &stats = cls.getCreatureStats(iter->first); CreatureStats &stats = cls.getCreatureStats(iter->first);
if(!stats.isDead()) if(!stats.isDead())
{ {
if(iter->second->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->first, true);
iter->second->resurrect(); iter->second->getCharacterController()->resurrect();
} }
if(!stats.isDead()) if(!stats.isDead())
continue; continue;
} }
if (iter->second->kill()) if (iter->second->getCharacterController()->kill())
{ {
iter->first.getClass().getCreatureStats(iter->first).notifyDied(); iter->first.getClass().getCreatureStats(iter->first).notifyDied();
++mDeathCount[Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId())]; ++mDeathCount[Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId())];
// Make sure spell effects with CasterLinked flag are removed // Make sure spell effects with CasterLinked flag are removed
for (PtrControllerMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2) for (PtrActorMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2)
{ {
MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells(); MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells();
spells.purge(stats.getActorId()); spells.purge(stats.getActorId());
@ -1438,7 +1442,7 @@ namespace MWMechanics
void Actors::restoreDynamicStats(bool sleep) void Actors::restoreDynamicStats(bool sleep)
{ {
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
restoreDynamicStats(iter->first, sleep); restoreDynamicStats(iter->first, sleep);
} }
@ -1470,35 +1474,35 @@ namespace MWMechanics
void Actors::forceStateUpdate(const MWWorld::Ptr & ptr) void Actors::forceStateUpdate(const MWWorld::Ptr & ptr)
{ {
PtrControllerMap::iterator iter = mActors.find(ptr); PtrActorMap::iterator iter = mActors.find(ptr);
if(iter != mActors.end()) if(iter != mActors.end())
iter->second->forceStateUpdate(); iter->second->getCharacterController()->forceStateUpdate();
} }
void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number)
{ {
PtrControllerMap::iterator iter = mActors.find(ptr); PtrActorMap::iterator iter = mActors.find(ptr);
if(iter != mActors.end()) if(iter != mActors.end())
iter->second->playGroup(groupName, mode, number); iter->second->getCharacterController()->playGroup(groupName, mode, number);
} }
void Actors::skipAnimation(const MWWorld::Ptr& ptr) void Actors::skipAnimation(const MWWorld::Ptr& ptr)
{ {
PtrControllerMap::iterator iter = mActors.find(ptr); PtrActorMap::iterator iter = mActors.find(ptr);
if(iter != mActors.end()) if(iter != mActors.end())
iter->second->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)
{ {
PtrControllerMap::iterator iter = mActors.find(ptr); PtrActorMap::iterator iter = mActors.find(ptr);
if(iter != mActors.end()) if(iter != mActors.end())
return iter->second->isAnimPlaying(groupName); return iter->second->getCharacterController()->isAnimPlaying(groupName);
return false; return false;
} }
void Actors::getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& out) void Actors::getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& out)
{ {
for (PtrControllerMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter) for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
{ {
if (Ogre::Vector3(iter->first.getRefData().getPosition().pos).squaredDistance(position) <= radius*radius) if (Ogre::Vector3(iter->first.getRefData().getPosition().pos).squaredDistance(position) <= radius*radius)
out.push_back(iter->first); out.push_back(iter->first);
@ -1508,7 +1512,7 @@ namespace MWMechanics
std::list<MWWorld::Ptr> Actors::getActorsFollowing(const MWWorld::Ptr& actor) std::list<MWWorld::Ptr> Actors::getActorsFollowing(const MWWorld::Ptr& actor)
{ {
std::list<MWWorld::Ptr> list; std::list<MWWorld::Ptr> list;
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
{ {
const MWWorld::Class &cls = iter->first.getClass(); const MWWorld::Class &cls = iter->first.getClass();
CreatureStats &stats = cls.getCreatureStats(iter->first); CreatureStats &stats = cls.getCreatureStats(iter->first);
@ -1538,7 +1542,7 @@ namespace MWMechanics
std::list<int> Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor) std::list<int> Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor)
{ {
std::list<int> list; std::list<int> list;
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
{ {
const MWWorld::Class &cls = iter->first.getClass(); const MWWorld::Class &cls = iter->first.getClass();
CreatureStats &stats = cls.getCreatureStats(iter->first); CreatureStats &stats = cls.getCreatureStats(iter->first);
@ -1611,7 +1615,7 @@ namespace MWMechanics
void Actors::clear() void Actors::clear()
{ {
PtrControllerMap::iterator it(mActors.begin()); PtrActorMap::iterator it(mActors.begin());
for (; it != mActors.end(); ++it) for (; it != mActors.end(); ++it)
{ {
delete it->second; delete it->second;
@ -1631,10 +1635,10 @@ namespace MWMechanics
bool Actors::isReadyToBlock(const MWWorld::Ptr &ptr) const bool Actors::isReadyToBlock(const MWWorld::Ptr &ptr) const
{ {
PtrControllerMap::const_iterator it = mActors.find(ptr); PtrActorMap::const_iterator it = mActors.find(ptr);
if (it == mActors.end()) if (it == mActors.end())
return false; return false;
return it->second->isReadyToBlock(); return it->second->getCharacterController()->isReadyToBlock();
} }
} }

View file

@ -6,7 +6,6 @@
#include <string> #include <string>
#include <map> #include <map>
#include "character.hpp"
#include "movement.hpp" #include "movement.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
@ -23,6 +22,8 @@ namespace MWWorld
namespace MWMechanics namespace MWMechanics
{ {
class Actor;
class Actors class Actors
{ {
std::map<std::string, int> mDeathCount; std::map<std::string, int> mDeathCount;
@ -51,10 +52,10 @@ namespace MWMechanics
Actors(); Actors();
~Actors(); ~Actors();
typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap; typedef std::map<MWWorld::Ptr,Actor*> PtrActorMap;
PtrControllerMap::const_iterator begin() { return mActors.begin(); } PtrActorMap::const_iterator begin() { return mActors.begin(); }
PtrControllerMap::const_iterator end() { return mActors.end(); } PtrActorMap::const_iterator end() { return mActors.end(); }
/// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently
/// paused we may want to do it manually (after equipping permanent enchantment) /// paused we may want to do it manually (after equipping permanent enchantment)
@ -131,7 +132,7 @@ namespace MWMechanics
bool isReadyToBlock(const MWWorld::Ptr& ptr) const; bool isReadyToBlock(const MWWorld::Ptr& ptr) const;
private: private:
PtrControllerMap mActors; PtrActorMap mActors;
}; };
} }

View file

@ -6,7 +6,6 @@
#include <components/esm/loadmgef.hpp> #include <components/esm/loadmgef.hpp>
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "aistate.hpp"
namespace MWWorld namespace MWWorld
{ {
@ -140,9 +139,6 @@ class CharacterController
MWWorld::Ptr mPtr; MWWorld::Ptr mPtr;
MWRender::Animation *mAnimation; MWRender::Animation *mAnimation;
//
AiState mAiState;
typedef std::deque<std::pair<std::string,size_t> > AnimationQueue; typedef std::deque<std::pair<std::string,size_t> > AnimationQueue;
AnimationQueue mAnimQueue; AnimationQueue mAnimQueue;
@ -229,8 +225,6 @@ public:
void forceStateUpdate(); void forceStateUpdate();
AiState& getAiState() { return mAiState; }
bool isReadyToBlock() const; bool isReadyToBlock() const;
bool isKnockedOut() const; bool isKnockedOut() const;

View file

@ -1289,7 +1289,7 @@ namespace MWMechanics
// if guard starts combat with player, guards pursuing player should do the same // if guard starts combat with player, guards pursuing player should do the same
if (ptr.getClass().isClass(ptr, "Guard")) if (ptr.getClass().isClass(ptr, "Guard"))
{ {
for (Actors::PtrControllerMap::const_iterator iter = mActors.begin(); iter != mActors.end(); ++iter) for (Actors::PtrActorMap::const_iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
{ {
if (iter->first.getClass().isClass(iter->first, "Guard")) if (iter->first.getClass().isClass(iter->first, "Guard"))
{ {