mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-30 12:45:33 +00:00
Add MWMechanics::Actor class for temporary actor state, move AiState there
This commit is contained in:
parent
42d63a4eb2
commit
edc128572d
7 changed files with 124 additions and 55 deletions
|
@ -76,7 +76,7 @@ add_openmw_dir (mwmechanics
|
|||
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
||||
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor
|
||||
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
|
||||
|
|
28
apps/openmw/mwmechanics/actor.cpp
Normal file
28
apps/openmw/mwmechanics/actor.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
42
apps/openmw/mwmechanics/actor.hpp
Normal file
42
apps/openmw/mwmechanics/actor.hpp
Normal 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
|
|
@ -35,6 +35,8 @@
|
|||
#include "aifollow.hpp"
|
||||
#include "aipursue.hpp"
|
||||
|
||||
#include "actor.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
|
@ -920,10 +922,10 @@ namespace MWMechanics
|
|||
|
||||
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())
|
||||
return;
|
||||
CharacterController* ctrl = it->second;
|
||||
CharacterController* ctrl = it->second->getCharacterController();
|
||||
|
||||
NpcStats &stats = ptr.getClass().getNpcStats(ptr);
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
|
@ -1128,14 +1130,14 @@ namespace MWMechanics
|
|||
removeActor(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)
|
||||
mActors[ptr]->update(0);
|
||||
mActors[ptr]->getCharacterController()->update(0);
|
||||
}
|
||||
|
||||
void Actors::removeActor (const MWWorld::Ptr& ptr)
|
||||
{
|
||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
||||
if(iter != mActors.end())
|
||||
{
|
||||
delete iter->second;
|
||||
|
@ -1145,20 +1147,20 @@ namespace MWMechanics
|
|||
|
||||
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())
|
||||
{
|
||||
CharacterController *ctrl = iter->second;
|
||||
Actor *actor = iter->second;
|
||||
mActors.erase(iter);
|
||||
|
||||
ctrl->updatePtr(ptr);
|
||||
mActors.insert(std::make_pair(ptr, ctrl));
|
||||
actor->updatePtr(ptr);
|
||||
mActors.insert(std::make_pair(ptr, actor));
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
{
|
||||
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)
|
||||
const float sqrProcessingDistance = 7168*7168;
|
||||
|
||||
/// \todo move update logic to Actor class where appropriate
|
||||
|
||||
// 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())
|
||||
{
|
||||
|
@ -1207,7 +1211,7 @@ namespace MWMechanics
|
|||
if (iter->first != player)
|
||||
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
|
||||
continue;
|
||||
|
@ -1219,13 +1223,13 @@ namespace MWMechanics
|
|||
float sqrHeadTrackDistance = std::numeric_limits<float>::max();
|
||||
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)
|
||||
continue;
|
||||
updateHeadTracking(iter->first, it->first, headTrackTarget, sqrHeadTrackDistance);
|
||||
}
|
||||
iter->second->setHeadTrackTarget(headTrackTarget);
|
||||
iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget);
|
||||
}
|
||||
|
||||
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),
|
||||
// so updating VFX immediately after that would just remove the particle effects instantly.
|
||||
// There needs to be a magic effect update in between.
|
||||
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
iter->second->updateContinuousVfx();
|
||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
iter->second->getCharacterController()->updateContinuousVfx();
|
||||
|
||||
// Animation/movement update
|
||||
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 &&
|
||||
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(
|
||||
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
|
||||
// (would invalidate the iterator)
|
||||
if (iter->first.getCellRef().getRefId() == "player")
|
||||
{
|
||||
playerCharacter = iter->second;
|
||||
playerCharacter = iter->second->getCharacterController();
|
||||
continue;
|
||||
}
|
||||
iter->second->update(duration);
|
||||
iter->second->getCharacterController()->update(duration);
|
||||
}
|
||||
|
||||
if (playerCharacter)
|
||||
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();
|
||||
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
||||
|
@ -1341,7 +1345,7 @@ namespace MWMechanics
|
|||
|
||||
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
|
||||
continue;
|
||||
|
@ -1384,32 +1388,32 @@ namespace MWMechanics
|
|||
|
||||
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();
|
||||
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
||||
|
||||
if(!stats.isDead())
|
||||
{
|
||||
if(iter->second->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->resurrect();
|
||||
iter->second->getCharacterController()->resurrect();
|
||||
}
|
||||
|
||||
if(!stats.isDead())
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iter->second->kill())
|
||||
if (iter->second->getCharacterController()->kill())
|
||||
{
|
||||
iter->first.getClass().getCreatureStats(iter->first).notifyDied();
|
||||
|
||||
++mDeathCount[Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId())];
|
||||
|
||||
// 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();
|
||||
spells.purge(stats.getActorId());
|
||||
|
@ -1438,7 +1442,7 @@ namespace MWMechanics
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1470,35 +1474,35 @@ namespace MWMechanics
|
|||
|
||||
void Actors::forceStateUpdate(const MWWorld::Ptr & ptr)
|
||||
{
|
||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
||||
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)
|
||||
{
|
||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
||||
if(iter != mActors.end())
|
||||
iter->second->playGroup(groupName, mode, number);
|
||||
iter->second->getCharacterController()->playGroup(groupName, mode, number);
|
||||
}
|
||||
void Actors::skipAnimation(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
||||
if(iter != mActors.end())
|
||||
iter->second->skipAnim();
|
||||
iter->second->getCharacterController()->skipAnim();
|
||||
}
|
||||
|
||||
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())
|
||||
return iter->second->isAnimPlaying(groupName);
|
||||
return iter->second->getCharacterController()->isAnimPlaying(groupName);
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
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> 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();
|
||||
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
||||
|
@ -1538,7 +1542,7 @@ namespace MWMechanics
|
|||
std::list<int> Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor)
|
||||
{
|
||||
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();
|
||||
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
||||
|
@ -1611,7 +1615,7 @@ namespace MWMechanics
|
|||
|
||||
void Actors::clear()
|
||||
{
|
||||
PtrControllerMap::iterator it(mActors.begin());
|
||||
PtrActorMap::iterator it(mActors.begin());
|
||||
for (; it != mActors.end(); ++it)
|
||||
{
|
||||
delete it->second;
|
||||
|
@ -1631,10 +1635,10 @@ namespace MWMechanics
|
|||
|
||||
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())
|
||||
return false;
|
||||
|
||||
return it->second->isReadyToBlock();
|
||||
return it->second->getCharacterController()->isReadyToBlock();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "character.hpp"
|
||||
#include "movement.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
|
@ -23,6 +22,8 @@ namespace MWWorld
|
|||
|
||||
namespace MWMechanics
|
||||
{
|
||||
class Actor;
|
||||
|
||||
class Actors
|
||||
{
|
||||
std::map<std::string, int> mDeathCount;
|
||||
|
@ -51,10 +52,10 @@ namespace MWMechanics
|
|||
Actors();
|
||||
~Actors();
|
||||
|
||||
typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap;
|
||||
typedef std::map<MWWorld::Ptr,Actor*> PtrActorMap;
|
||||
|
||||
PtrControllerMap::const_iterator begin() { return mActors.begin(); }
|
||||
PtrControllerMap::const_iterator end() { return mActors.end(); }
|
||||
PtrActorMap::const_iterator begin() { return mActors.begin(); }
|
||||
PtrActorMap::const_iterator end() { return mActors.end(); }
|
||||
|
||||
/// 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)
|
||||
|
@ -131,7 +132,7 @@ namespace MWMechanics
|
|||
bool isReadyToBlock(const MWWorld::Ptr& ptr) const;
|
||||
|
||||
private:
|
||||
PtrControllerMap mActors;
|
||||
PtrActorMap mActors;
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include <components/esm/loadmgef.hpp>
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "aistate.hpp"
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
|
@ -140,9 +139,6 @@ class CharacterController
|
|||
MWWorld::Ptr mPtr;
|
||||
MWRender::Animation *mAnimation;
|
||||
|
||||
//
|
||||
AiState mAiState;
|
||||
|
||||
typedef std::deque<std::pair<std::string,size_t> > AnimationQueue;
|
||||
AnimationQueue mAnimQueue;
|
||||
|
||||
|
@ -229,8 +225,6 @@ public:
|
|||
|
||||
void forceStateUpdate();
|
||||
|
||||
AiState& getAiState() { return mAiState; }
|
||||
|
||||
bool isReadyToBlock() const;
|
||||
bool isKnockedOut() const;
|
||||
|
||||
|
|
|
@ -1289,7 +1289,7 @@ namespace MWMechanics
|
|||
// if guard starts combat with player, guards pursuing player should do the same
|
||||
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"))
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue