mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-05 03:45:35 +00:00
Merge branch 'master' of https://github.com/OpenMW/openmw
This commit is contained in:
commit
9b67fcc4d7
46 changed files with 635 additions and 505 deletions
|
@ -20,7 +20,7 @@
|
||||||
#include "model/world/data.hpp"
|
#include "model/world/data.hpp"
|
||||||
|
|
||||||
CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
|
CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
|
||||||
: mDocumentManager (mCfgMgr), mViewManager (mDocumentManager),
|
: mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), mViewManager (mDocumentManager),
|
||||||
mIpcServerName ("org.openmw.OpenCS")
|
mIpcServerName ("org.openmw.OpenCS")
|
||||||
{
|
{
|
||||||
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
|
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
|
||||||
|
@ -90,6 +90,9 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
|
||||||
|
|
||||||
mCfgMgr.readConfiguration(variables, desc);
|
mCfgMgr.readConfiguration(variables, desc);
|
||||||
|
|
||||||
|
mDocumentManager.setEncoding (
|
||||||
|
ToUTF8::calculateEncoding (variables["encoding"].as<std::string>()));
|
||||||
|
|
||||||
mDocumentManager.setResourceDir (mResources = variables["resources"].as<std::string>());
|
mDocumentManager.setResourceDir (mResources = variables["resources"].as<std::string>());
|
||||||
|
|
||||||
mFsStrict = variables["fs-strict"].as<bool>();
|
mFsStrict = variables["fs-strict"].as<bool>();
|
||||||
|
|
|
@ -2204,11 +2204,13 @@ void CSMDoc::Document::createBase()
|
||||||
|
|
||||||
CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
|
CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
|
||||||
const std::vector< boost::filesystem::path >& files, bool new_,
|
const std::vector< boost::filesystem::path >& files, bool new_,
|
||||||
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir)
|
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
|
||||||
: mSavePath (savePath), mContentFiles (files), mNew (new_), mTools (mData), mResDir(resDir),
|
ToUTF8::FromType encoding)
|
||||||
|
: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding), mTools (mData),
|
||||||
|
mResDir(resDir),
|
||||||
mProjectPath ((configuration.getUserDataPath() / "projects") /
|
mProjectPath ((configuration.getUserDataPath() / "projects") /
|
||||||
(savePath.filename().string() + ".project")),
|
(savePath.filename().string() + ".project")),
|
||||||
mSaving (*this, mProjectPath)
|
mSaving (*this, mProjectPath, encoding)
|
||||||
{
|
{
|
||||||
if (mContentFiles.empty())
|
if (mContentFiles.empty())
|
||||||
throw std::runtime_error ("Empty content file sequence");
|
throw std::runtime_error ("Empty content file sequence");
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
|
||||||
#include "../world/data.hpp"
|
#include "../world/data.hpp"
|
||||||
|
|
||||||
#include "../tools/tools.hpp"
|
#include "../tools/tools.hpp"
|
||||||
|
@ -70,7 +72,8 @@ namespace CSMDoc
|
||||||
|
|
||||||
Document (const Files::ConfigurationManager& configuration,
|
Document (const Files::ConfigurationManager& configuration,
|
||||||
const std::vector< boost::filesystem::path >& files, bool new_,
|
const std::vector< boost::filesystem::path >& files, bool new_,
|
||||||
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir);
|
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
|
||||||
|
ToUTF8::FromType encoding);
|
||||||
|
|
||||||
~Document();
|
~Document();
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include "document.hpp"
|
#include "document.hpp"
|
||||||
|
|
||||||
CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration)
|
CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration)
|
||||||
: mConfiguration (configuration)
|
: mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252)
|
||||||
{
|
{
|
||||||
boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects";
|
boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects";
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ CSMDoc::DocumentManager::~DocumentManager()
|
||||||
void CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files, const boost::filesystem::path& savePath,
|
void CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files, const boost::filesystem::path& savePath,
|
||||||
bool new_)
|
bool new_)
|
||||||
{
|
{
|
||||||
Document *document = new Document (mConfiguration, files, new_, savePath, mResDir);
|
Document *document = new Document (mConfiguration, files, new_, savePath, mResDir, mEncoding);
|
||||||
|
|
||||||
mDocuments.push_back (document);
|
mDocuments.push_back (document);
|
||||||
|
|
||||||
|
@ -80,6 +80,11 @@ void CSMDoc::DocumentManager::setResourceDir (const boost::filesystem::path& par
|
||||||
mResDir = boost::filesystem::system_complete(parResDir);
|
mResDir = boost::filesystem::system_complete(parResDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMDoc::DocumentManager::setEncoding (ToUTF8::FromType encoding)
|
||||||
|
{
|
||||||
|
mEncoding = encoding;
|
||||||
|
}
|
||||||
|
|
||||||
void CSMDoc::DocumentManager::documentLoaded (Document *document)
|
void CSMDoc::DocumentManager::documentLoaded (Document *document)
|
||||||
{
|
{
|
||||||
emit documentAdded (document);
|
emit documentAdded (document);
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
|
||||||
#include "loader.hpp"
|
#include "loader.hpp"
|
||||||
|
|
||||||
namespace Files
|
namespace Files
|
||||||
|
@ -28,6 +30,7 @@ namespace CSMDoc
|
||||||
const Files::ConfigurationManager& mConfiguration;
|
const Files::ConfigurationManager& mConfiguration;
|
||||||
QThread mLoaderThread;
|
QThread mLoaderThread;
|
||||||
Loader mLoader;
|
Loader mLoader;
|
||||||
|
ToUTF8::FromType mEncoding;
|
||||||
|
|
||||||
DocumentManager (const DocumentManager&);
|
DocumentManager (const DocumentManager&);
|
||||||
DocumentManager& operator= (const DocumentManager&);
|
DocumentManager& operator= (const DocumentManager&);
|
||||||
|
@ -45,6 +48,8 @@ namespace CSMDoc
|
||||||
|
|
||||||
void setResourceDir (const boost::filesystem::path& parResDir);
|
void setResourceDir (const boost::filesystem::path& parResDir);
|
||||||
|
|
||||||
|
void setEncoding (ToUTF8::FromType encoding);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
boost::filesystem::path mResDir;
|
boost::filesystem::path mResDir;
|
||||||
|
|
|
@ -8,8 +8,9 @@
|
||||||
#include "savingstages.hpp"
|
#include "savingstages.hpp"
|
||||||
#include "document.hpp"
|
#include "document.hpp"
|
||||||
|
|
||||||
CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& projectPath)
|
CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& projectPath,
|
||||||
: Operation (State_Saving, true, true), mDocument (document), mState (*this, projectPath)
|
ToUTF8::FromType encoding)
|
||||||
|
: Operation (State_Saving, true, true), mDocument (document), mState (*this, projectPath, encoding)
|
||||||
{
|
{
|
||||||
// save project file
|
// save project file
|
||||||
appendStage (new OpenSaveStage (mDocument, mState, true));
|
appendStage (new OpenSaveStage (mDocument, mState, true));
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
|
|
||||||
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
|
||||||
#include "operation.hpp"
|
#include "operation.hpp"
|
||||||
#include "savingstate.hpp"
|
#include "savingstate.hpp"
|
||||||
|
|
||||||
|
@ -19,7 +21,8 @@ namespace CSMDoc
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Saving (Document& document, const boost::filesystem::path& projectPath);
|
Saving (Document& document, const boost::filesystem::path& projectPath,
|
||||||
|
ToUTF8::FromType encoding);
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,9 @@
|
||||||
#include "operation.hpp"
|
#include "operation.hpp"
|
||||||
#include "document.hpp"
|
#include "document.hpp"
|
||||||
|
|
||||||
CSMDoc::SavingState::SavingState (Operation& operation, const boost::filesystem::path& projectPath)
|
CSMDoc::SavingState::SavingState (Operation& operation, const boost::filesystem::path& projectPath,
|
||||||
: mOperation (operation),
|
ToUTF8::FromType encoding)
|
||||||
/// \todo set encoding properly, once config implementation has been fixed.
|
: mOperation (operation), mEncoder (encoding), mProjectPath (projectPath), mProjectFile (false)
|
||||||
mEncoder (ToUTF8::calculateEncoding ("win1252")),
|
|
||||||
mProjectPath (projectPath), mProjectFile (false)
|
|
||||||
{
|
{
|
||||||
mWriter.setEncoder (&mEncoder);
|
mWriter.setEncoder (&mEncoder);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
#include <components/esm/esmwriter.hpp>
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
|
||||||
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
|
||||||
namespace CSMDoc
|
namespace CSMDoc
|
||||||
{
|
{
|
||||||
class Operation;
|
class Operation;
|
||||||
|
@ -25,7 +27,8 @@ namespace CSMDoc
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SavingState (Operation& operation, const boost::filesystem::path& projectPath);
|
SavingState (Operation& operation, const boost::filesystem::path& projectPath,
|
||||||
|
ToUTF8::FromType encoding);
|
||||||
|
|
||||||
bool hasError() const;
|
bool hasError() const;
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,8 @@ namespace boost
|
||||||
|
|
||||||
CSMSettings::UserSettings *CSMSettings::UserSettings::mUserSettingsInstance = 0;
|
CSMSettings::UserSettings *CSMSettings::UserSettings::mUserSettingsInstance = 0;
|
||||||
|
|
||||||
CSMSettings::UserSettings::UserSettings()
|
CSMSettings::UserSettings::UserSettings (const Files::ConfigurationManager& configurationManager)
|
||||||
|
: mCfgMgr (configurationManager)
|
||||||
{
|
{
|
||||||
assert(!mUserSettingsInstance);
|
assert(!mUserSettingsInstance);
|
||||||
mUserSettingsInstance = this;
|
mUserSettingsInstance = this;
|
||||||
|
|
|
@ -30,7 +30,7 @@ namespace CSMSettings {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
static UserSettings *mUserSettingsInstance;
|
static UserSettings *mUserSettingsInstance;
|
||||||
Files::ConfigurationManager mCfgMgr;
|
const Files::ConfigurationManager& mCfgMgr;
|
||||||
|
|
||||||
QSettings *mSettingDefinitions;
|
QSettings *mSettingDefinitions;
|
||||||
QList <Setting *> mSettings;
|
QList <Setting *> mSettings;
|
||||||
|
@ -40,11 +40,11 @@ namespace CSMSettings {
|
||||||
/// Singleton implementation
|
/// Singleton implementation
|
||||||
static UserSettings& instance();
|
static UserSettings& instance();
|
||||||
|
|
||||||
UserSettings();
|
UserSettings (const Files::ConfigurationManager& configurationManager);
|
||||||
~UserSettings();
|
~UserSettings();
|
||||||
|
|
||||||
UserSettings (UserSettings const &); //not implemented
|
UserSettings (UserSettings const &); //not implemented
|
||||||
void operator= (UserSettings const &); //not implemented
|
UserSettings& operator= (UserSettings const &); //not implemented
|
||||||
|
|
||||||
/// Retrieves the settings file at all three levels (global, local and user).
|
/// Retrieves the settings file at all three levels (global, local and user).
|
||||||
void loadSettings (const QString &fileName);
|
void loadSettings (const QString &fileName);
|
||||||
|
|
|
@ -55,10 +55,8 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec
|
||||||
return number;
|
return number;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::Data::Data()
|
CSMWorld::Data::Data (ToUTF8::FromType encoding)
|
||||||
/// \todo set encoding properly, once config implementation has been fixed.
|
: mEncoder (encoding), mRefs (mCells), mReader (0), mDialogue (0)
|
||||||
: mEncoder (ToUTF8::calculateEncoding ("win1252")),
|
|
||||||
mRefs (mCells), mReader (0), mDialogue (0)
|
|
||||||
{
|
{
|
||||||
mGlobals.addColumn (new StringIdColumn<ESM::Global>);
|
mGlobals.addColumn (new StringIdColumn<ESM::Global>);
|
||||||
mGlobals.addColumn (new RecordStateColumn<ESM::Global>);
|
mGlobals.addColumn (new RecordStateColumn<ESM::Global>);
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#include <components/esm/loadspel.hpp>
|
#include <components/esm/loadspel.hpp>
|
||||||
#include <components/esm/loaddial.hpp>
|
#include <components/esm/loaddial.hpp>
|
||||||
|
|
||||||
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
|
||||||
#include "../filter/filter.hpp"
|
#include "../filter/filter.hpp"
|
||||||
|
|
||||||
#include "../doc/stage.hpp"
|
#include "../doc/stage.hpp"
|
||||||
|
@ -91,7 +93,7 @@ namespace CSMWorld
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Data();
|
Data (ToUTF8::FromType encoding);
|
||||||
|
|
||||||
virtual ~Data();
|
virtual ~Data();
|
||||||
|
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
#include <QVBoxLayout>
|
|
||||||
#include <QDialogButtonBox>
|
|
||||||
|
|
||||||
#include <components/fileorderlist/datafileslist.hpp>
|
|
||||||
|
|
||||||
#include "opendialog.hpp"
|
|
||||||
|
|
||||||
OpenDialog::OpenDialog(QWidget * parent) : QDialog(parent)
|
|
||||||
{
|
|
||||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
|
||||||
mFileSelector = new DataFilesList(mCfgMgr, this);
|
|
||||||
layout->addWidget(mFileSelector);
|
|
||||||
|
|
||||||
/// \todo move config to Editor class and add command line options.
|
|
||||||
// We use the Configuration Manager to retrieve the configuration values
|
|
||||||
boost::program_options::variables_map variables;
|
|
||||||
boost::program_options::options_description desc;
|
|
||||||
|
|
||||||
desc.add_options()
|
|
||||||
("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken())
|
|
||||||
("data-local", boost::program_options::value<std::string>()->default_value(""))
|
|
||||||
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
|
|
||||||
("encoding", boost::program_options::value<std::string>()->default_value("win1252"));
|
|
||||||
|
|
||||||
boost::program_options::notify(variables);
|
|
||||||
|
|
||||||
mCfgMgr.readConfiguration(variables, desc);
|
|
||||||
|
|
||||||
Files::PathContainer mDataDirs, mDataLocal;
|
|
||||||
if (!variables["data"].empty()) {
|
|
||||||
mDataDirs = Files::PathContainer(variables["data"].as<Files::PathContainer>());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string local = variables["data-local"].as<std::string>();
|
|
||||||
if (!local.empty()) {
|
|
||||||
mDataLocal.push_back(Files::PathContainer::value_type(local));
|
|
||||||
}
|
|
||||||
|
|
||||||
mCfgMgr.processPaths(mDataDirs);
|
|
||||||
mCfgMgr.processPaths(mDataLocal);
|
|
||||||
|
|
||||||
// Set the charset for reading the esm/esp files
|
|
||||||
QString encoding = QString::fromUtf8 (variables["encoding"].as<std::string>().c_str());
|
|
||||||
|
|
||||||
Files::PathContainer dataDirs;
|
|
||||||
dataDirs.insert(dataDirs.end(), mDataDirs.begin(), mDataDirs.end());
|
|
||||||
dataDirs.insert(dataDirs.end(), mDataLocal.begin(), mDataLocal.end());
|
|
||||||
mFileSelector->setupDataFiles(dataDirs, encoding);
|
|
||||||
|
|
||||||
buttonBox = new QDialogButtonBox(QDialogButtonBox::Open | QDialogButtonBox::Cancel, Qt::Horizontal, this);
|
|
||||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
|
||||||
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
|
||||||
layout->addWidget(buttonBox);
|
|
||||||
|
|
||||||
setLayout(layout);
|
|
||||||
setWindowTitle(tr("Open"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenDialog::getFileList(std::vector<boost::filesystem::path>& paths)
|
|
||||||
{
|
|
||||||
mFileSelector->selectedFiles(paths);
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
#include <qdialog.h>
|
|
||||||
#include <components/files/configurationmanager.hpp>
|
|
||||||
|
|
||||||
class DataFilesList;
|
|
||||||
class QDialogButtonBox;
|
|
||||||
|
|
||||||
class OpenDialog : public QDialog {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
OpenDialog(QWidget * parent = 0);
|
|
||||||
|
|
||||||
void getFileList(std::vector<boost::filesystem::path>& paths);
|
|
||||||
private:
|
|
||||||
DataFilesList * mFileSelector;
|
|
||||||
QDialogButtonBox * buttonBox;
|
|
||||||
Files::ConfigurationManager mCfgMgr;
|
|
||||||
};
|
|
|
@ -111,13 +111,17 @@ void CSVWorld::TableSubView::createFilterRequest (std::vector< CSMWorld::Univers
|
||||||
{
|
{
|
||||||
std::vector<std::pair<std::string, std::vector<std::string> > > filterSource;
|
std::vector<std::pair<std::string, std::vector<std::string> > > filterSource;
|
||||||
|
|
||||||
for (std::vector<CSMWorld::UniversalId>::iterator it = types.begin(); it != types.end(); ++it)
|
for (std::vector<CSMWorld::UniversalId>::iterator it(types.begin()); it != types.end(); ++it)
|
||||||
{
|
{
|
||||||
std::pair<std::string, std::vector<std::string> > pair( //splited long line
|
std::pair<std::string, std::vector<std::string> > pair( //splited long line
|
||||||
std::make_pair(it->getId(), mTable->getColumnsWithDisplay(CSMWorld::TableMimeData::convertEnums(it->getType()))));
|
std::make_pair(it->getId(), mTable->getColumnsWithDisplay(CSMWorld::TableMimeData::convertEnums(it->getType()))));
|
||||||
|
|
||||||
filterSource.push_back(pair);
|
if(!pair.second.empty())
|
||||||
|
{
|
||||||
|
filterSource.push_back(pair);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mFilterBox->createFilterRequest(filterSource, action);
|
mFilterBox->createFilterRequest(filterSource, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ add_openmw_dir (mwclass
|
||||||
|
|
||||||
add_openmw_dir (mwmechanics
|
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
|
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
|
disease pickpocket levelledlist combat steering obstacle
|
||||||
)
|
)
|
||||||
|
|
|
@ -393,10 +393,14 @@ namespace MWBase
|
||||||
virtual void setupPlayer() = 0;
|
virtual void setupPlayer() = 0;
|
||||||
virtual void renderPlayer() = 0;
|
virtual void renderPlayer() = 0;
|
||||||
|
|
||||||
|
/// if activated, should this door be opened or closed?
|
||||||
virtual bool getOpenOrCloseDoor(const MWWorld::Ptr& door) = 0;
|
virtual bool getOpenOrCloseDoor(const MWWorld::Ptr& door) = 0;
|
||||||
///< if activated, should this door be opened or closed?
|
|
||||||
|
/// activate (open or close) an non-teleport door
|
||||||
virtual void activateDoor(const MWWorld::Ptr& door) = 0;
|
virtual void activateDoor(const MWWorld::Ptr& door) = 0;
|
||||||
///< activate (open or close) an non-teleport door
|
|
||||||
|
/// Is door currently opening/closing?
|
||||||
|
virtual bool getIsMovingDoor(const MWWorld::Ptr& door) = 0;
|
||||||
|
|
||||||
virtual bool getPlayerStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if the player is standing on \a object
|
virtual bool getPlayerStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if the player is standing on \a object
|
||||||
virtual bool getActorStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if any actor is standing on \a object
|
virtual bool getActorStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if any actor is standing on \a object
|
||||||
|
|
|
@ -19,83 +19,26 @@ MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const
|
||||||
return new AiActivate(*this);
|
return new AiActivate(*this);
|
||||||
}
|
}
|
||||||
bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration)
|
bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration)
|
||||||
{
|
{
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
||||||
ESM::Position pos = actor.getRefData().getPosition();
|
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mObjectId, false); //The target to follow
|
||||||
Movement &movement = actor.getClass().getMovementSettings(actor);
|
|
||||||
const ESM::Cell *cell = actor.getCell()->getCell();
|
if(target == MWWorld::Ptr())
|
||||||
|
return true; //Target doesn't exist
|
||||||
MWWorld::Ptr player = world->getPlayerPtr();
|
|
||||||
if(cell->mData.mX != player.getCell()->getCell()->mData.mX)
|
//Set the target desition from the actor
|
||||||
{
|
ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos;
|
||||||
int sideX = PathFinder::sgn(cell->mData.mX - player.getCell()->getCell()->mData.mX);
|
|
||||||
//check if actor is near the border of an inactive cell. If so, stop walking.
|
if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 200) { //Stop when you get close
|
||||||
if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) >
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||||
sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false);
|
||||||
{
|
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor); //Arrest player
|
||||||
movement.mPosition[1] = 0;
|
return true;
|
||||||
return false;
|
}
|
||||||
}
|
else {
|
||||||
}
|
pathTo(actor, dest, duration); //Go to the destination
|
||||||
if(cell->mData.mY != player.getCell()->getCell()->mData.mY)
|
}
|
||||||
{
|
|
||||||
int sideY = PathFinder::sgn(cell->mData.mY - player.getCell()->getCell()->mData.mY);
|
|
||||||
//check if actor is near the border of an inactive cell. If so, stop walking.
|
|
||||||
if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) >
|
|
||||||
sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
|
||||||
{
|
|
||||||
movement.mPosition[1] = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MWWorld::Ptr target = world->searchPtr(mObjectId,false);
|
|
||||||
if(target == MWWorld::Ptr()) return true;
|
|
||||||
|
|
||||||
ESM::Position targetPos = target.getRefData().getPosition();
|
|
||||||
|
|
||||||
bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY;
|
|
||||||
if(!mPathFinder.isPathConstructed() || cellChange)
|
|
||||||
{
|
|
||||||
mCellX = cell->mData.mX;
|
|
||||||
mCellY = cell->mData.mY;
|
|
||||||
|
|
||||||
ESM::Pathgrid::Point dest;
|
|
||||||
dest.mX = targetPos.pos[0];
|
|
||||||
dest.mY = targetPos.pos[1];
|
|
||||||
dest.mZ = targetPos.pos[2];
|
|
||||||
|
|
||||||
ESM::Pathgrid::Point start;
|
|
||||||
start.mX = pos.pos[0];
|
|
||||||
start.mY = pos.pos[1];
|
|
||||||
start.mZ = pos.pos[2];
|
|
||||||
|
|
||||||
mPathFinder.buildPath(start, dest, actor.getCell(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if((pos.pos[0]-targetPos.pos[0])*(pos.pos[0]-targetPos.pos[0])+
|
|
||||||
(pos.pos[1]-targetPos.pos[1])*(pos.pos[1]-targetPos.pos[1])+
|
|
||||||
(pos.pos[2]-targetPos.pos[2])*(pos.pos[2]-targetPos.pos[2]) < 200*200)
|
|
||||||
{
|
|
||||||
movement.mPosition[1] = 0;
|
|
||||||
MWWorld::Ptr target = world->getPtr(mObjectId,false);
|
|
||||||
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
|
||||||
{
|
|
||||||
movement.mPosition[1] = 0;
|
|
||||||
MWWorld::Ptr target = world->getPtr(mObjectId,false);
|
|
||||||
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
|
||||||
zTurn(actor, Ogre::Degree(zAngle));
|
|
||||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
|
||||||
movement.mPosition[1] = 1;
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,21 +7,21 @@
|
||||||
#include "pathfinding.hpp"
|
#include "pathfinding.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
/// \brief Causes actor to walk to activatable object and activate it
|
||||||
|
/** Will activate when close to object **/
|
||||||
class AiActivate : public AiPackage
|
class AiActivate : public AiPackage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// Constructor
|
||||||
|
/** \param objectId Reference to object to activate **/
|
||||||
AiActivate(const std::string &objectId);
|
AiActivate(const std::string &objectId);
|
||||||
virtual AiActivate *clone() const;
|
virtual AiActivate *clone() const;
|
||||||
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
///< \return Package completed?
|
|
||||||
virtual int getTypeId() const;
|
virtual int getTypeId() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string mObjectId;
|
std::string mObjectId;
|
||||||
|
|
||||||
PathFinder mPathFinder;
|
|
||||||
int mCellX;
|
int mCellX;
|
||||||
int mCellY;
|
int mCellY;
|
||||||
};
|
};
|
||||||
|
|
90
apps/openmw/mwmechanics/aiavoiddoor.cpp
Normal file
90
apps/openmw/mwmechanics/aiavoiddoor.cpp
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
#include "aiavoiddoor.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
#include "creaturestats.hpp"
|
||||||
|
#include "movement.hpp"
|
||||||
|
#include "mechanicsmanagerimp.hpp"
|
||||||
|
|
||||||
|
#include <OgreMath.h>
|
||||||
|
|
||||||
|
#include "steering.hpp"
|
||||||
|
|
||||||
|
MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::Ptr& doorPtr)
|
||||||
|
: AiPackage(), mDoorPtr(doorPtr), mDuration(1), mAdjAngle(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor,float duration)
|
||||||
|
{
|
||||||
|
|
||||||
|
ESM::Position pos = actor.getRefData().getPosition();
|
||||||
|
if(mDuration == 1) //If it just started, get the actor position as the stuck detection thing
|
||||||
|
mLastPos = pos;
|
||||||
|
|
||||||
|
mDuration -= duration; //Update timer
|
||||||
|
|
||||||
|
if(mDuration < 0) {
|
||||||
|
float x = pos.pos[0] - mLastPos.pos[0];
|
||||||
|
float y = pos.pos[1] - mLastPos.pos[1];
|
||||||
|
float z = pos.pos[2] - mLastPos.pos[2];
|
||||||
|
int distance = x * x + y * y + z * z;
|
||||||
|
if(distance < 10 * 10) { //Got stuck, didn't move
|
||||||
|
if(mAdjAngle == 0) //Try going in various directions
|
||||||
|
mAdjAngle = 1.57079632679f; //pi/2
|
||||||
|
else if (mAdjAngle == 1.57079632679f)
|
||||||
|
mAdjAngle = -1.57079632679;
|
||||||
|
else
|
||||||
|
mAdjAngle = 0;
|
||||||
|
mDuration = 1; //reset timer
|
||||||
|
}
|
||||||
|
else //Not stuck
|
||||||
|
return true; // We have tried backing up for more than one second, we've probably cleared it
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!MWBase::Environment::get().getWorld()->getIsMovingDoor(mDoorPtr))
|
||||||
|
return true; //Door is no longer opening
|
||||||
|
|
||||||
|
ESM::Position tPos = mDoorPtr.getRefData().getPosition(); //Position of the door
|
||||||
|
float x = pos.pos[0] - tPos.pos[0];
|
||||||
|
float y = pos.pos[1] - tPos.pos[1];
|
||||||
|
float dirToDoor = std::atan2(x,y) + pos.rot[2] + mAdjAngle; //Calculates the direction to the door, relative to the direction of the NPC
|
||||||
|
// For example, if the NPC is directly facing the door this will be pi/2
|
||||||
|
|
||||||
|
// Make actor move away from the door
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[1] = -1 * std::sin(dirToDoor); //I knew I'd use trig someday
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[0] = -1 * std::cos(dirToDoor);
|
||||||
|
|
||||||
|
//Make all nearby actors also avoid the door
|
||||||
|
std::vector<MWWorld::Ptr> actors;
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->getActorsInRange(Ogre::Vector3(pos.pos[0],pos.pos[1],pos.pos[2]),100,actors);
|
||||||
|
for(std::vector<MWWorld::Ptr>::iterator it = actors.begin(); it != actors.end(); it++) {
|
||||||
|
if(*it != MWBase::Environment::get().getWorld()->getPlayerPtr()) { //Not the player
|
||||||
|
MWMechanics::AiSequence& seq = MWWorld::Class::get(*it).getCreatureStats(*it).getAiSequence();
|
||||||
|
if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) { //Only add it once
|
||||||
|
seq.stack(MWMechanics::AiAvoidDoor(mDoorPtr),*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MWMechanics::AiAvoidDoor::getAvoidedDoor()
|
||||||
|
{
|
||||||
|
return mDoorPtr.getCellRef().mRefID;
|
||||||
|
}
|
||||||
|
|
||||||
|
MWMechanics::AiAvoidDoor *MWMechanics::AiAvoidDoor::clone() const
|
||||||
|
{
|
||||||
|
return new AiAvoidDoor(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
int MWMechanics::AiAvoidDoor::getTypeId() const
|
||||||
|
{
|
||||||
|
return TypeIdAvoidDoor;
|
||||||
|
}
|
||||||
|
|
38
apps/openmw/mwmechanics/aiavoiddoor.hpp
Normal file
38
apps/openmw/mwmechanics/aiavoiddoor.hpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef GAME_MWMECHANICS_AIAVOIDDOOR_H
|
||||||
|
#define GAME_MWMECHANICS_AIAVOIDDOOR_H
|
||||||
|
|
||||||
|
#include "aipackage.hpp"
|
||||||
|
#include <string>
|
||||||
|
#include "pathfinding.hpp"
|
||||||
|
#include <components/esm/defs.hpp>
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
|
namespace MWMechanics
|
||||||
|
{
|
||||||
|
/// \brief AiPackage to have an actor avoid an opening door
|
||||||
|
/** The AI will retreat from the door until it has finished opening, walked far away from it, or one second has passed, in an attempt to avoid it
|
||||||
|
**/
|
||||||
|
class AiAvoidDoor : public AiPackage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Avoid door until the door is fully open
|
||||||
|
AiAvoidDoor(const MWWorld::Ptr& doorPtr);
|
||||||
|
|
||||||
|
virtual AiAvoidDoor *clone() const;
|
||||||
|
|
||||||
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
|
|
||||||
|
virtual int getTypeId() const;
|
||||||
|
|
||||||
|
/// Returns the door being avoided
|
||||||
|
std::string getAvoidedDoor();
|
||||||
|
|
||||||
|
private:
|
||||||
|
float mDuration;
|
||||||
|
const MWWorld::Ptr& mDoorPtr;
|
||||||
|
ESM::Position mLastPos;
|
||||||
|
float mAdjAngle;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -14,20 +14,23 @@
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
/// \brief Causes the actor to fight another actor
|
||||||
class AiCombat : public AiPackage
|
class AiCombat : public AiPackage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
///Constructor
|
||||||
|
/** \param actor Actor to fight **/
|
||||||
AiCombat(const MWWorld::Ptr& actor);
|
AiCombat(const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
virtual AiCombat *clone() const;
|
virtual AiCombat *clone() const;
|
||||||
|
|
||||||
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
///< \return Package completed?
|
|
||||||
|
|
||||||
virtual int getTypeId() const;
|
virtual int getTypeId() const;
|
||||||
|
|
||||||
virtual unsigned int getPriority() const;
|
virtual unsigned int getPriority() const;
|
||||||
|
|
||||||
|
///Returns target ID
|
||||||
const std::string &getTargetId() const;
|
const std::string &getTargetId() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -75,58 +75,6 @@ namespace MWMechanics
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
|
||||||
ESM::Position pos = actor.getRefData().getPosition();
|
|
||||||
bool cellChange = actor.getCell()->getCell()->mData.mX != mCellX || actor.getCell()->getCell()->mData.mY != mCellY;
|
|
||||||
|
|
||||||
if(actor.getCell()->getCell()->mData.mX != player.getCell()->getCell()->mData.mX)
|
|
||||||
{
|
|
||||||
int sideX = PathFinder::sgn(actor.getCell()->getCell()->mData.mX - player.getCell()->getCell()->mData.mX);
|
|
||||||
// Check if actor is near the border of an inactive cell. If so, pause walking.
|
|
||||||
if(sideX * (pos.pos[0] - actor.getCell()->getCell()->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE /
|
|
||||||
2.0 - 200))
|
|
||||||
{
|
|
||||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(actor.getCell()->getCell()->mData.mY != player.getCell()->getCell()->mData.mY)
|
|
||||||
{
|
|
||||||
int sideY = PathFinder::sgn(actor.getCell()->getCell()->mData.mY - player.getCell()->getCell()->mData.mY);
|
|
||||||
// Check if actor is near the border of an inactive cell. If so, pause walking.
|
|
||||||
if(sideY*(pos.pos[1] - actor.getCell()->getCell()->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE /
|
|
||||||
2.0 - 200))
|
|
||||||
{
|
|
||||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(!mPathFinder.isPathConstructed() || cellChange)
|
|
||||||
{
|
|
||||||
mCellX = actor.getCell()->getCell()->mData.mX;
|
|
||||||
mCellY = actor.getCell()->getCell()->mData.mY;
|
|
||||||
|
|
||||||
ESM::Pathgrid::Point dest;
|
|
||||||
dest.mX = mX;
|
|
||||||
dest.mY = mY;
|
|
||||||
dest.mZ = mZ;
|
|
||||||
|
|
||||||
ESM::Pathgrid::Point start;
|
|
||||||
start.mX = pos.pos[0];
|
|
||||||
start.mY = pos.pos[1];
|
|
||||||
start.mZ = pos.pos[2];
|
|
||||||
|
|
||||||
mPathFinder.buildPath(start, dest, actor.getCell(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]))
|
|
||||||
{
|
|
||||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mActorId, false);
|
const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mActorId, false);
|
||||||
const float* const leaderPos = actor.getRefData().getPosition().pos;
|
const float* const leaderPos = actor.getRefData().getPosition().pos;
|
||||||
const float* const followerPos = follower.getRefData().getPosition().pos;
|
const float* const followerPos = follower.getRefData().getPosition().pos;
|
||||||
|
@ -141,9 +89,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
if(distanceBetweenResult <= mMaxDist * mMaxDist)
|
if(distanceBetweenResult <= mMaxDist * mMaxDist)
|
||||||
{
|
{
|
||||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
if(pathTo(actor,ESM::Pathgrid::Point(mX,mY,mZ),duration)) //Returns true on path complete
|
||||||
zTurn(actor, Ogre::Degree(zAngle));
|
return true;
|
||||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
|
||||||
mMaxDist = 470;
|
mMaxDist = 470;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -8,18 +8,22 @@
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
/// \brief AI Package to have an NPC lead the player to a specific point
|
||||||
class AiEscort : public AiPackage
|
class AiEscort : public AiPackage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// Implementation of AiEscort
|
||||||
|
/** The Actor will escort the specified actor to the world position x, y, z until they reach their position, or they run out of time
|
||||||
|
\implement AiEscort **/
|
||||||
AiEscort(const std::string &actorId,int duration, float x, float y, float z);
|
AiEscort(const std::string &actorId,int duration, float x, float y, float z);
|
||||||
///< \implement AiEscort
|
/// Implementation of AiEscortCell
|
||||||
|
/** The Actor will escort the specified actor to the cell position x, y, z until they reach their position, or they run out of time
|
||||||
|
\implement AiEscortCell **/
|
||||||
AiEscort(const std::string &actorId,const std::string &cellId,int duration, float x, float y, float z);
|
AiEscort(const std::string &actorId,const std::string &cellId,int duration, float x, float y, float z);
|
||||||
///< \implement AiEscortCell
|
|
||||||
|
|
||||||
virtual AiEscort *clone() const;
|
virtual AiEscort *clone() const;
|
||||||
|
|
||||||
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
///< \return Package completed?
|
|
||||||
|
|
||||||
virtual int getTypeId() const;
|
virtual int getTypeId() const;
|
||||||
|
|
||||||
|
|
|
@ -12,16 +12,16 @@
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
|
|
||||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z)
|
MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z)
|
||||||
: mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(""), mTimer(0), mStuckTimer(0)
|
: mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(""), AiPackage()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z)
|
MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z)
|
||||||
: mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(cellId), mTimer(0), mStuckTimer(0)
|
: mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(cellId), AiPackage()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId)
|
MWMechanics::AiFollow::AiFollow(const std::string &actorId)
|
||||||
: mAlwaysFollow(true), mDuration(0), mX(0), mY(0), mZ(0), mActorId(actorId), mCellId(""), mTimer(0), mStuckTimer(0)
|
: mAlwaysFollow(true), mDuration(0), mX(0), mY(0), mZ(0), mActorId(actorId), mCellId(""), AiPackage()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,10 +31,6 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
||||||
|
|
||||||
if(target == MWWorld::Ptr()) return true; //Target doesn't exist
|
if(target == MWWorld::Ptr()) return true; //Target doesn't exist
|
||||||
|
|
||||||
mTimer = mTimer + duration; //Update timer
|
|
||||||
mStuckTimer = mStuckTimer + duration; //Update stuck timer
|
|
||||||
mTotalTime = mTotalTime + duration; //Update total time following
|
|
||||||
|
|
||||||
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
||||||
|
|
||||||
if(!mAlwaysFollow) //Update if you only follow for a bit
|
if(!mAlwaysFollow) //Update if you only follow for a bit
|
||||||
|
@ -60,74 +56,18 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set the target desition from the actor
|
//Set the target desition from the actor
|
||||||
ESM::Pathgrid::Point dest;
|
ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos;
|
||||||
dest.mX = target.getRefData().getPosition().pos[0];
|
|
||||||
dest.mY = target.getRefData().getPosition().pos[1];
|
|
||||||
dest.mZ = target.getRefData().getPosition().pos[2];
|
|
||||||
|
|
||||||
//Current position, for pathfilding stuff
|
if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 100) //Stop when you get close
|
||||||
ESM::Pathgrid::Point start;
|
|
||||||
start.mX = pos.pos[0];
|
|
||||||
start.mY = pos.pos[1];
|
|
||||||
start.mZ = pos.pos[2];
|
|
||||||
|
|
||||||
//Build the path to get to the destination
|
|
||||||
if(mPathFinder.getPath().empty())
|
|
||||||
mPathFinder.buildPath(start, dest, actor.getCell(), true);
|
|
||||||
|
|
||||||
//***********************
|
|
||||||
// Checks if you can't get to the end position at all
|
|
||||||
//***********************
|
|
||||||
if(mTimer > 0.25)
|
|
||||||
{
|
|
||||||
if(!mPathFinder.getPath().empty()) //Path has points in it
|
|
||||||
{
|
|
||||||
ESM::Pathgrid::Point lastPos = mPathFinder.getPath().back(); //Get the end of the proposed path
|
|
||||||
|
|
||||||
if((dest.mX - lastPos.mX)*(dest.mX - lastPos.mX)
|
|
||||||
+(dest.mY - lastPos.mY)*(dest.mY - lastPos.mY)
|
|
||||||
+(dest.mZ - lastPos.mZ)*(dest.mZ - lastPos.mZ)
|
|
||||||
> 100*100) //End of the path is far from the destination
|
|
||||||
mPathFinder.addPointToPath(dest); //Adds the final destination to the path, to try to get to where you want to go
|
|
||||||
}
|
|
||||||
|
|
||||||
mTimer = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//************************
|
|
||||||
// Checks if you aren't moving; you're stuck
|
|
||||||
//************************
|
|
||||||
if(mStuckTimer>0.5) //Checks every half of a second
|
|
||||||
{
|
|
||||||
if((mStuckPos.pos[0] - pos.pos[0])*(mStuckPos.pos[0] - pos.pos[0])
|
|
||||||
+(mStuckPos.pos[1] - pos.pos[1])*(mStuckPos.pos[1] - pos.pos[1])
|
|
||||||
+(mStuckPos.pos[2] - pos.pos[2])*(mStuckPos.pos[2] - pos.pos[2]) < 100) //NPC is stuck
|
|
||||||
mPathFinder.buildPath(start, dest, actor.getCell(), true);
|
|
||||||
|
|
||||||
mStuckTimer = 0;
|
|
||||||
mStuckPos = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Checks if the path isn't over, turn tomards the direction that you're going
|
|
||||||
if(!mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]))
|
|
||||||
{
|
|
||||||
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
|
||||||
}
|
|
||||||
|
|
||||||
if((dest.mX - pos.pos[0])*(dest.mX - pos.pos[0])+(dest.mY - pos.pos[1])*(dest.mY - pos.pos[1])+(dest.mZ - pos.pos[2])*(dest.mZ - pos.pos[2])
|
|
||||||
< 100*100)
|
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||||
else
|
else {
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
pathTo(actor, dest, duration); //Go to the destination
|
||||||
|
}
|
||||||
|
|
||||||
//Check if you're far away
|
//Check if you're far away
|
||||||
if((dest.mX - start.mX)*(dest.mX - start.mX)
|
if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) > 1000)
|
||||||
+(dest.mY - start.mY)*(dest.mY - start.mY)
|
|
||||||
+(dest.mZ - start.mZ)*(dest.mZ - start.mZ) > 1000*1000)
|
|
||||||
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
|
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
|
||||||
else if((dest.mX - start.mX)*(dest.mX - start.mX) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold
|
else if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 800) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold
|
||||||
+(dest.mY - start.mY)*(dest.mY - start.mY)
|
|
||||||
+(dest.mZ - start.mZ)*(dest.mZ - start.mZ) < 800*800)
|
|
||||||
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk
|
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,43 +1,45 @@
|
||||||
#ifndef GAME_MWMECHANICS_AIFALLOW_H
|
#ifndef GAME_MWMECHANICS_AIFOLLOW_H
|
||||||
#define GAME_MWMECHANICS_AIFALLOW_H
|
#define GAME_MWMECHANICS_AIFOLLOW_H
|
||||||
|
|
||||||
#include "aipackage.hpp"
|
#include "aipackage.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "pathfinding.hpp"
|
#include "pathfinding.hpp"
|
||||||
#include "../../../components/esm/defs.hpp"
|
#include <components/esm/defs.hpp>
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
/// \brief AiPackage for an actor to follow another actor/the PC
|
||||||
|
/** The AI will follow the target until a condition (time, or position) are set. Both can be disabled to cause the actor to follow the other indefinitely
|
||||||
|
**/
|
||||||
class AiFollow : public AiPackage
|
class AiFollow : public AiPackage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// Follow Actor for duration or until you arrive at a world position
|
||||||
AiFollow(const std::string &ActorId,float duration, float X, float Y, float Z);
|
AiFollow(const std::string &ActorId,float duration, float X, float Y, float Z);
|
||||||
|
/// Follow Actor for duration or until you arrive at a position in a cell
|
||||||
AiFollow(const std::string &ActorId,const std::string &CellId,float duration, float X, float Y, float Z);
|
AiFollow(const std::string &ActorId,const std::string &CellId,float duration, float X, float Y, float Z);
|
||||||
|
/// Follow Actor indefinitively
|
||||||
AiFollow(const std::string &ActorId);
|
AiFollow(const std::string &ActorId);
|
||||||
|
|
||||||
virtual AiFollow *clone() const;
|
virtual AiFollow *clone() const;
|
||||||
|
|
||||||
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
///< \return Package completed?
|
|
||||||
virtual int getTypeId() const;
|
virtual int getTypeId() const;
|
||||||
|
|
||||||
|
/// Returns the actor being followed
|
||||||
std::string getFollowedActor();
|
std::string getFollowedActor();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool mAlwaysFollow; //this will make the actor always follow, thus ignoring mDuration and mX,mY,mZ (used for summoned creatures).
|
/// This will make the actor always follow.
|
||||||
|
/** Thus ignoring mDuration and mX,mY,mZ (used for summoned creatures). **/
|
||||||
|
bool mAlwaysFollow;
|
||||||
float mDuration;
|
float mDuration;
|
||||||
float mX;
|
float mX;
|
||||||
float mY;
|
float mY;
|
||||||
float mZ;
|
float mZ;
|
||||||
std::string mActorId;
|
std::string mActorId;
|
||||||
std::string mCellId;
|
std::string mCellId;
|
||||||
|
|
||||||
float mTimer;
|
|
||||||
float mStuckTimer;
|
|
||||||
float mTotalTime;
|
|
||||||
|
|
||||||
ESM::Position mStuckPos;
|
|
||||||
|
|
||||||
PathFinder mPathFinder;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,4 +1,131 @@
|
||||||
|
|
||||||
#include "aipackage.hpp"
|
#include "aipackage.hpp"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
#include "creaturestats.hpp"
|
||||||
|
#include "movement.hpp"
|
||||||
|
#include "../mwworld/action.hpp"
|
||||||
|
|
||||||
|
#include <OgreMath.h>
|
||||||
|
|
||||||
|
#include "steering.hpp"
|
||||||
|
|
||||||
MWMechanics::AiPackage::~AiPackage() {}
|
MWMechanics::AiPackage::~AiPackage() {}
|
||||||
|
|
||||||
|
MWMechanics::AiPackage::AiPackage() : mLastDoorChecked(MWWorld::Ptr()), mTimer(.26), mStuckTimer(0) { //mTimer starts at .26 to force initial pathbuild
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Point dest, float duration)
|
||||||
|
{
|
||||||
|
//Update various Timers
|
||||||
|
mTimer += duration; //Update timer
|
||||||
|
mStuckTimer += duration; //Update stuck timer
|
||||||
|
mTotalTime += duration; //Update total time following
|
||||||
|
|
||||||
|
|
||||||
|
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
||||||
|
|
||||||
|
/// Stops the actor when it gets too close to a unloaded cell
|
||||||
|
{
|
||||||
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
const ESM::Cell *cell = actor.getCell()->getCell();
|
||||||
|
Movement &movement = actor.getClass().getMovementSettings(actor);
|
||||||
|
|
||||||
|
//Ensure pursuer doesn't leave loaded cells
|
||||||
|
if(cell->mData.mX != player.getCell()->getCell()->mData.mX)
|
||||||
|
{
|
||||||
|
int sideX = PathFinder::sgn(cell->mData.mX - player.getCell()->getCell()->mData.mX);
|
||||||
|
//check if actor is near the border of an inactive cell. If so, stop walking.
|
||||||
|
if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
||||||
|
{
|
||||||
|
movement.mPosition[1] = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(cell->mData.mY != player.getCell()->getCell()->mData.mY)
|
||||||
|
{
|
||||||
|
int sideY = PathFinder::sgn(cell->mData.mY - player.getCell()->getCell()->mData.mY);
|
||||||
|
//check if actor is near the border of an inactive cell. If so, stop walking.
|
||||||
|
if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
||||||
|
{
|
||||||
|
movement.mPosition[1] = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Start position
|
||||||
|
ESM::Pathgrid::Point start = pos.pos;
|
||||||
|
|
||||||
|
//***********************
|
||||||
|
/// Checks if you can't get to the end position at all, adds end position to end of path
|
||||||
|
/// Rebuilds path every quarter of a second, in case the target has moved
|
||||||
|
//***********************
|
||||||
|
if(mTimer > 0.25)
|
||||||
|
{
|
||||||
|
if(distance(mPrevDest, dest) > 10) { //Only rebuild path if it's moved
|
||||||
|
mPathFinder.buildPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved
|
||||||
|
mPrevDest = dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!mPathFinder.getPath().empty()) //Path has points in it
|
||||||
|
{
|
||||||
|
ESM::Pathgrid::Point lastPos = mPathFinder.getPath().back(); //Get the end of the proposed path
|
||||||
|
|
||||||
|
if(distance(dest, lastPos) > 100) //End of the path is far from the destination
|
||||||
|
mPathFinder.addPointToPath(dest); //Adds the final destination to the path, to try to get to where you want to go
|
||||||
|
}
|
||||||
|
|
||||||
|
mTimer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//************************
|
||||||
|
/// Checks if you aren't moving; attempts to unstick you
|
||||||
|
//************************
|
||||||
|
if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) //Path finished?
|
||||||
|
return true;
|
||||||
|
else if(mStuckTimer>0.5) //Every half second see if we need to take action to avoid something
|
||||||
|
{
|
||||||
|
/// TODO (tluppi#1#): Use ObstacleCheck here. Not working for some reason
|
||||||
|
//if(mObstacleCheck.check(actor, duration)) {
|
||||||
|
if(distance(start, mStuckPos.pos[0], mStuckPos.pos[1], mStuckPos.pos[2]) < 10 && distance(dest, start) > 20) { //Actually stuck, and far enough away from destination to care
|
||||||
|
// first check if we're walking into a door
|
||||||
|
MWWorld::Ptr door = getNearbyDoor(actor);
|
||||||
|
if(door != MWWorld::Ptr()) // NOTE: checks interior cells only
|
||||||
|
{
|
||||||
|
if(door.getCellRef().mTrap.empty() && mLastDoorChecked != door) { //Open the door if untrapped
|
||||||
|
door.getClass().activate(door, actor).get()->execute(actor);
|
||||||
|
mLastDoorChecked = door;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // probably walking into another NPC
|
||||||
|
{
|
||||||
|
// TODO: diagonal should have same animation as walk forward
|
||||||
|
// but doesn't seem to do that?
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[0] = 1;
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f;
|
||||||
|
// change the angle a bit, too
|
||||||
|
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { //Not stuck, so reset things
|
||||||
|
mStuckTimer = 0;
|
||||||
|
mStuckPos = pos;
|
||||||
|
mLastDoorChecked = MWWorld::Ptr(); //Resets it, in case he gets stuck behind the door again
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward the rest of the time
|
||||||
|
}
|
||||||
|
|
||||||
|
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
#ifndef GAME_MWMECHANICS_AIPACKAGE_H
|
#ifndef GAME_MWMECHANICS_AIPACKAGE_H
|
||||||
#define GAME_MWMECHANICS_AIPACKAGE_H
|
#define GAME_MWMECHANICS_AIPACKAGE_H
|
||||||
|
|
||||||
|
#include "pathfinding.hpp"
|
||||||
|
#include <components/esm/defs.hpp>
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "obstacle.hpp"
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class Ptr;
|
class Ptr;
|
||||||
|
@ -12,6 +18,7 @@ namespace MWMechanics
|
||||||
class AiPackage
|
class AiPackage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
///Enumerates the various AITypes availible.
|
||||||
enum TypeId {
|
enum TypeId {
|
||||||
TypeIdNone = -1,
|
TypeIdNone = -1,
|
||||||
TypeIdWander = 0,
|
TypeIdWander = 0,
|
||||||
|
@ -20,21 +27,47 @@ namespace MWMechanics
|
||||||
TypeIdFollow = 3,
|
TypeIdFollow = 3,
|
||||||
TypeIdActivate = 4,
|
TypeIdActivate = 4,
|
||||||
TypeIdCombat = 5,
|
TypeIdCombat = 5,
|
||||||
TypeIdPursue = 6
|
TypeIdPursue = 6,
|
||||||
|
TypeIdAvoidDoor = 7
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual ~AiPackage();
|
///Default constructor
|
||||||
|
AiPackage();
|
||||||
virtual AiPackage *clone() const = 0;
|
|
||||||
|
|
||||||
virtual bool execute (const MWWorld::Ptr& actor,float duration) = 0;
|
|
||||||
///< \return Package completed?
|
|
||||||
|
|
||||||
virtual int getTypeId() const = 0;
|
|
||||||
///< @see enum TypeId
|
|
||||||
|
|
||||||
|
///Default Deconstructor
|
||||||
|
virtual ~AiPackage();
|
||||||
|
|
||||||
|
///Clones the package
|
||||||
|
virtual AiPackage *clone() const = 0;
|
||||||
|
|
||||||
|
/// Updates and runs the package (Should run every frame)
|
||||||
|
/// \return Package completed?
|
||||||
|
virtual bool execute (const MWWorld::Ptr& actor,float duration) = 0;
|
||||||
|
|
||||||
|
/// Returns the TypeID of the AiPackage
|
||||||
|
/// \see enum TypeId
|
||||||
|
virtual int getTypeId() const = 0;
|
||||||
|
|
||||||
|
/// Higher number is higher priority (0 being the lowest)
|
||||||
virtual unsigned int getPriority() const {return 0;}
|
virtual unsigned int getPriority() const {return 0;}
|
||||||
///< higher number is higher priority (0 beeing the lowest)
|
|
||||||
|
protected:
|
||||||
|
/// Causes the actor to attempt to walk to the specified location
|
||||||
|
/** \return If the actor has arrived at his destination **/
|
||||||
|
bool pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Point dest, float duration);
|
||||||
|
|
||||||
|
PathFinder mPathFinder;
|
||||||
|
ObstacleCheck mObstacleCheck;
|
||||||
|
|
||||||
|
float mDoorCheckDuration;
|
||||||
|
float mTimer;
|
||||||
|
float mStuckTimer;
|
||||||
|
float mTotalTime;
|
||||||
|
|
||||||
|
MWWorld::Ptr mLastDoorChecked; //Used to ensure we don't try to CONSTANTLY open a door
|
||||||
|
|
||||||
|
ESM::Position mStuckPos;
|
||||||
|
ESM::Pathgrid::Point mPrevDest;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,75 +21,27 @@ MWMechanics::AiPursue *MWMechanics::AiPursue::clone() const
|
||||||
}
|
}
|
||||||
bool MWMechanics::AiPursue::execute (const MWWorld::Ptr& actor, float duration)
|
bool MWMechanics::AiPursue::execute (const MWWorld::Ptr& actor, float duration)
|
||||||
{
|
{
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
|
||||||
ESM::Position pos = actor.getRefData().getPosition();
|
|
||||||
Movement &movement = actor.getClass().getMovementSettings(actor);
|
|
||||||
const ESM::Cell *cell = actor.getCell()->getCell();
|
|
||||||
|
|
||||||
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
|
||||||
|
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mObjectId, false); //The target to follow
|
||||||
|
|
||||||
MWWorld::Ptr player = world->getPlayerPtr();
|
if(target == MWWorld::Ptr())
|
||||||
if(cell->mData.mX != player.getCell()->getCell()->mData.mX)
|
return true; //Target doesn't exist
|
||||||
{
|
|
||||||
int sideX = PathFinder::sgn(cell->mData.mX - player.getCell()->getCell()->mData.mX);
|
|
||||||
//check if actor is near the border of an inactive cell. If so, stop walking.
|
|
||||||
if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) >
|
|
||||||
sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
|
||||||
{
|
|
||||||
movement.mPosition[1] = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(cell->mData.mY != player.getCell()->getCell()->mData.mY)
|
|
||||||
{
|
|
||||||
int sideY = PathFinder::sgn(cell->mData.mY - player.getCell()->getCell()->mData.mY);
|
|
||||||
//check if actor is near the border of an inactive cell. If so, stop walking.
|
|
||||||
if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) >
|
|
||||||
sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
|
|
||||||
{
|
|
||||||
movement.mPosition[1] = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Big TODO: Sync this with current AiFollow. Move common code to a shared base class or helpers (applies to all AI packages, way too much duplicated code)
|
//Set the target desition from the actor
|
||||||
|
ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos;
|
||||||
|
|
||||||
MWWorld::Ptr target = world->getPtr(mObjectId,false);
|
if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 100) { //Stop when you get close
|
||||||
ESM::Position targetPos = target.getRefData().getPosition();
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||||
|
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false);
|
||||||
bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY;
|
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor); //Arrest player
|
||||||
if(!mPathFinder.isPathConstructed() || cellChange || mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
|
||||||
{
|
|
||||||
mCellX = cell->mData.mX;
|
|
||||||
mCellY = cell->mData.mY;
|
|
||||||
|
|
||||||
ESM::Pathgrid::Point dest;
|
|
||||||
dest.mX = targetPos.pos[0];
|
|
||||||
dest.mY = targetPos.pos[1];
|
|
||||||
dest.mZ = targetPos.pos[2];
|
|
||||||
|
|
||||||
ESM::Pathgrid::Point start;
|
|
||||||
start.mX = pos.pos[0];
|
|
||||||
start.mY = pos.pos[1];
|
|
||||||
start.mZ = pos.pos[2];
|
|
||||||
|
|
||||||
mPathFinder.buildPath(start, dest, actor.getCell(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if((pos.pos[0]-targetPos.pos[0])*(pos.pos[0]-targetPos.pos[0])+
|
|
||||||
(pos.pos[1]-targetPos.pos[1])*(pos.pos[1]-targetPos.pos[1])+
|
|
||||||
(pos.pos[2]-targetPos.pos[2])*(pos.pos[2]-targetPos.pos[2]) < 100*100)
|
|
||||||
{
|
|
||||||
movement.mPosition[1] = 0;
|
|
||||||
MWWorld::Ptr target = world->getPtr(mObjectId,false);
|
|
||||||
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
pathTo(actor, dest, duration); //Go to the destination
|
||||||
|
}
|
||||||
|
|
||||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
|
||||||
zTurn(actor, Ogre::Degree(zAngle));
|
|
||||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
|
||||||
movement.mPosition[1] = 1;
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,20 +8,22 @@
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
/// \brief Makes the actor very closely follow the actor
|
||||||
|
/** Used for arresting players. Causes the actor to run to the pursued actor and activate them, to arrest them.
|
||||||
|
Note that while very similar to AiActivate, it will ONLY activate when evry close to target (Not also when the
|
||||||
|
path is completed). **/
|
||||||
class AiPursue : public AiPackage
|
class AiPursue : public AiPackage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
///Constructor
|
||||||
|
/** \param objectId Actor to pursue **/
|
||||||
AiPursue(const std::string &objectId);
|
AiPursue(const std::string &objectId);
|
||||||
virtual AiPursue *clone() const;
|
virtual AiPursue *clone() const;
|
||||||
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
///< \return Package completed?
|
|
||||||
virtual int getTypeId() const;
|
virtual int getTypeId() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string mObjectId;
|
std::string mObjectId;
|
||||||
|
|
||||||
PathFinder mPathFinder;
|
|
||||||
int mCellX;
|
int mCellX;
|
||||||
int mCellY;
|
int mCellY;
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,66 +13,79 @@ namespace MWWorld
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
class AiPackage;
|
class AiPackage;
|
||||||
|
|
||||||
/// \brief Sequence of AI-packages for a single actor
|
/// \brief Sequence of AI-packages for a single actor
|
||||||
|
/** The top-most AI package is run each frame. When completed, it is removed from the stack. **/
|
||||||
class AiSequence
|
class AiSequence
|
||||||
{
|
{
|
||||||
|
///AiPackages to run though
|
||||||
std::list<AiPackage *> mPackages;
|
std::list<AiPackage *> mPackages;
|
||||||
|
|
||||||
|
///Finished with top AIPackage, set for one frame
|
||||||
bool mDone;
|
bool mDone;
|
||||||
|
|
||||||
|
///Copy AiSequence
|
||||||
void copy (const AiSequence& sequence);
|
void copy (const AiSequence& sequence);
|
||||||
|
|
||||||
// The type of AI package that ran last
|
/// The type of AI package that ran last
|
||||||
int mLastAiPackage;
|
int mLastAiPackage;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
///Default constructor
|
||||||
AiSequence();
|
AiSequence();
|
||||||
|
|
||||||
|
/// Copy Constructor
|
||||||
AiSequence (const AiSequence& sequence);
|
AiSequence (const AiSequence& sequence);
|
||||||
|
|
||||||
|
/// Assignment operator
|
||||||
AiSequence& operator= (const AiSequence& sequence);
|
AiSequence& operator= (const AiSequence& sequence);
|
||||||
|
|
||||||
virtual ~AiSequence();
|
virtual ~AiSequence();
|
||||||
|
|
||||||
|
/// Returns currently executing AiPackage type
|
||||||
|
/** \see enum AiPackage::TypeId **/
|
||||||
int getTypeId() const;
|
int getTypeId() const;
|
||||||
///< @see enum AiPackage::TypeId
|
|
||||||
|
|
||||||
|
/// Get the typeid of the Ai package that ran last
|
||||||
|
/** NOT the currently "active" Ai package that will be run in the next frame.
|
||||||
|
This difference is important when an Ai package has just finished and been removed.
|
||||||
|
\see enum AiPackage::TypeId **/
|
||||||
int getLastRunTypeId() const { return mLastAiPackage; }
|
int getLastRunTypeId() const { return mLastAiPackage; }
|
||||||
///< Get the typeid of the Ai package that ran last, NOT the currently "active" Ai package that will be run in the next frame.
|
|
||||||
/// This difference is important when an Ai package has just finished and been removed.
|
|
||||||
|
|
||||||
|
/// Return true and assign target if combat package is currently active, return false otherwise
|
||||||
bool getCombatTarget (std::string &targetActorId) const;
|
bool getCombatTarget (std::string &targetActorId) const;
|
||||||
///< Return true and assign target if combat package is currently
|
|
||||||
/// active, return false otherwise
|
|
||||||
|
|
||||||
|
/// Removes all combat packages until first non-combat or stack empty.
|
||||||
void stopCombat();
|
void stopCombat();
|
||||||
///< Removes all combat packages until first non-combat or stack empty.
|
|
||||||
|
|
||||||
void stopPursuit();
|
/// Has a package been completed during the last update?
|
||||||
///< Removes all pursue packages until first non-pursue or stack empty.
|
|
||||||
|
|
||||||
bool isPackageDone() const;
|
bool isPackageDone() const;
|
||||||
///< Has a package been completed during the last update?
|
|
||||||
|
/// Removes all pursue packages until first non-pursue or stack empty.
|
||||||
|
void stopPursuit();
|
||||||
|
|
||||||
|
/// Execute current package, switching if needed.
|
||||||
void execute (const MWWorld::Ptr& actor,float duration);
|
void execute (const MWWorld::Ptr& actor,float duration);
|
||||||
///< Execute package.
|
|
||||||
|
/// Remove all packages.
|
||||||
void clear();
|
void clear();
|
||||||
///< Remove all packages.
|
|
||||||
|
|
||||||
|
///< Add \a package to the front of the sequence
|
||||||
|
/** Suspends current package
|
||||||
|
@param actor The actor that owns this AiSequence **/
|
||||||
void stack (const AiPackage& package, const MWWorld::Ptr& actor);
|
void stack (const AiPackage& package, const MWWorld::Ptr& actor);
|
||||||
///< Add \a package to the front of the sequence (suspends current package)
|
|
||||||
/// @param actor The actor that owns this AiSequence
|
/// Add \a package to the end of the sequence
|
||||||
|
/** Executed after all other packages have been completed **/
|
||||||
void queue (const AiPackage& package);
|
void queue (const AiPackage& package);
|
||||||
///< Add \a package to the end of the sequence (executed after all other packages have been
|
|
||||||
/// completed)
|
|
||||||
|
|
||||||
|
/// Return the current active package.
|
||||||
|
/** If there is no active package, it will throw an exception **/
|
||||||
AiPackage* getActivePackage();
|
AiPackage* getActivePackage();
|
||||||
///< return the current active package. If there is no active package, throw an exeption
|
|
||||||
|
|
||||||
|
/// Fills the AiSequence with packages
|
||||||
|
/** Typically used for loading from the ESM
|
||||||
|
\see ESM::AIPackageList **/
|
||||||
void fill (const ESM::AIPackageList& list);
|
void fill (const ESM::AIPackageList& list);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,15 +6,16 @@
|
||||||
#include "pathfinding.hpp"
|
#include "pathfinding.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
/// \brief Causes the AI to travel to the specified point
|
||||||
class AiTravel : public AiPackage
|
class AiTravel : public AiPackage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// Default constructor
|
||||||
AiTravel(float x, float y, float z);
|
AiTravel(float x, float y, float z);
|
||||||
virtual AiTravel *clone() const;
|
virtual AiTravel *clone() const;
|
||||||
|
|
||||||
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
///< \return Package completed?
|
|
||||||
|
|
||||||
virtual int getTypeId() const;
|
virtual int getTypeId() const;
|
||||||
|
|
||||||
|
|
|
@ -14,20 +14,27 @@
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
/// \brief Causes the Actor to wander within a specified range
|
||||||
class AiWander : public AiPackage
|
class AiWander : public AiPackage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// Constructor
|
||||||
|
/** \param distance Max distance the ACtor will wander
|
||||||
|
\param duration Time, in hours, that this package will be preformed
|
||||||
|
\param timeOfDay Start time of the package, if it has a duration. Currently unimplemented
|
||||||
|
\param idle Chances of each idle to play (9 in total)
|
||||||
|
\param repeat Repeat wander or not **/
|
||||||
AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat);
|
AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat);
|
||||||
virtual AiPackage *clone() const;
|
|
||||||
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
|
||||||
///< \return Package completed?
|
|
||||||
virtual int getTypeId() const;
|
|
||||||
///< 0: Wander
|
|
||||||
|
|
||||||
|
virtual AiPackage *clone() const;
|
||||||
|
|
||||||
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
|
|
||||||
|
virtual int getTypeId() const;
|
||||||
|
|
||||||
|
/// Set the position to return to for a stationary (non-wandering) actor
|
||||||
|
/** In case another AI package moved the actor elsewhere **/
|
||||||
void setReturnPosition (const Ogre::Vector3& position);
|
void setReturnPosition (const Ogre::Vector3& position);
|
||||||
///< Set the position to return to for a stationary (non-wandering) actor, in case
|
|
||||||
/// another AI package moved the actor elsewhere
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void stopWalking(const MWWorld::Ptr& actor);
|
void stopWalking(const MWWorld::Ptr& actor);
|
||||||
|
|
|
@ -19,11 +19,19 @@ namespace MWMechanics
|
||||||
// Limitation: there can be false detections, and does not test whether the
|
// Limitation: there can be false detections, and does not test whether the
|
||||||
// actor is facing the door.
|
// actor is facing the door.
|
||||||
bool proximityToDoor(const MWWorld::Ptr& actor, float minSqr, bool closed)
|
bool proximityToDoor(const MWWorld::Ptr& actor, float minSqr, bool closed)
|
||||||
|
{
|
||||||
|
if(getNearbyDoor(actor, minSqr, closed)!=MWWorld::Ptr())
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minSqr, bool closed)
|
||||||
{
|
{
|
||||||
MWWorld::CellStore *cell = actor.getCell();
|
MWWorld::CellStore *cell = actor.getCell();
|
||||||
|
|
||||||
if(cell->getCell()->isExterior())
|
if(cell->getCell()->isExterior())
|
||||||
return false; // check interior cells only
|
return MWWorld::Ptr(); // check interior cells only
|
||||||
|
|
||||||
// Check all the doors in this cell
|
// Check all the doors in this cell
|
||||||
MWWorld::CellRefList<ESM::Door>& doors = cell->get<ESM::Door>();
|
MWWorld::CellRefList<ESM::Door>& doors = cell->get<ESM::Door>();
|
||||||
|
@ -31,14 +39,14 @@ namespace MWMechanics
|
||||||
MWWorld::CellRefList<ESM::Door>::List::iterator it = refList.begin();
|
MWWorld::CellRefList<ESM::Door>::List::iterator it = refList.begin();
|
||||||
Ogre::Vector3 pos(actor.getRefData().getPosition().pos);
|
Ogre::Vector3 pos(actor.getRefData().getPosition().pos);
|
||||||
|
|
||||||
// TODO: How to check whether the actor is facing a door? Below code is for
|
/// TODO: How to check whether the actor is facing a door? Below code is for
|
||||||
// the player, perhaps it can be adapted.
|
/// the player, perhaps it can be adapted.
|
||||||
//MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject();
|
//MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject();
|
||||||
//if(!ptr.isEmpty())
|
//if(!ptr.isEmpty())
|
||||||
//std::cout << "faced door " << ptr.getClass().getName(ptr) << std::endl;
|
//std::cout << "faced door " << ptr.getClass().getName(ptr) << std::endl;
|
||||||
|
|
||||||
// TODO: The in-game observation of rot[2] value seems to be the
|
/// TODO: The in-game observation of rot[2] value seems to be the
|
||||||
// opposite of the code in World::activateDoor() ::confused::
|
/// opposite of the code in World::activateDoor() ::confused::
|
||||||
for (; it != refList.end(); ++it)
|
for (; it != refList.end(); ++it)
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Door>& ref = *it;
|
MWWorld::LiveCellRef<ESM::Door>& ref = *it;
|
||||||
|
@ -46,10 +54,10 @@ namespace MWMechanics
|
||||||
if((closed && ref.mData.getLocalRotation().rot[2] == 0) ||
|
if((closed && ref.mData.getLocalRotation().rot[2] == 0) ||
|
||||||
(!closed && ref.mData.getLocalRotation().rot[2] >= 1))
|
(!closed && ref.mData.getLocalRotation().rot[2] >= 1))
|
||||||
{
|
{
|
||||||
return true; // found, stop searching
|
return MWWorld::Ptr(&ref, actor.getCell()); // found, stop searching
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false; // none found
|
return MWWorld::Ptr(); // none found
|
||||||
}
|
}
|
||||||
|
|
||||||
ObstacleCheck::ObstacleCheck():
|
ObstacleCheck::ObstacleCheck():
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
#ifndef OPENMW_MECHANICS_OBSTACLE_H
|
#ifndef OPENMW_MECHANICS_OBSTACLE_H
|
||||||
#define OPENMW_MECHANICS_OBSTACLE_H
|
#define OPENMW_MECHANICS_OBSTACLE_H
|
||||||
|
|
||||||
|
//#include "../mwbase/world.hpp"
|
||||||
|
//#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class Ptr;
|
class Ptr;
|
||||||
|
@ -8,14 +12,20 @@ namespace MWWorld
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
// NOTE: determined empirically based on in-game behaviour
|
/// NOTE: determined empirically based on in-game behaviour
|
||||||
static const float MIN_DIST_TO_DOOR_SQUARED = 128*128;
|
static const float MIN_DIST_TO_DOOR_SQUARED = 128*128;
|
||||||
|
|
||||||
// tests actor's proximity to a closed door by default
|
/// tests actor's proximity to a closed door by default
|
||||||
bool proximityToDoor(const MWWorld::Ptr& actor,
|
bool proximityToDoor(const MWWorld::Ptr& actor,
|
||||||
float minSqr = MIN_DIST_TO_DOOR_SQUARED,
|
float minSqr = MIN_DIST_TO_DOOR_SQUARED,
|
||||||
bool closed = true);
|
bool closed = true);
|
||||||
|
|
||||||
|
/// Returns door pointer within range. No guarentee is given as too which one
|
||||||
|
/** \return Pointer to the door, or NULL if none exists **/
|
||||||
|
MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor,
|
||||||
|
float minSqr = MIN_DIST_TO_DOOR_SQUARED,
|
||||||
|
bool closed = true);
|
||||||
|
|
||||||
class ObstacleCheck
|
class ObstacleCheck
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -11,30 +11,6 @@
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
float distanceZCorrected(ESM::Pathgrid::Point point, float x, float y, float z)
|
|
||||||
{
|
|
||||||
x -= point.mX;
|
|
||||||
y -= point.mY;
|
|
||||||
z -= point.mZ;
|
|
||||||
return sqrt(x * x + y * y + 0.1 * z * z);
|
|
||||||
}
|
|
||||||
|
|
||||||
float distance(ESM::Pathgrid::Point point, float x, float y, float z)
|
|
||||||
{
|
|
||||||
x -= point.mX;
|
|
||||||
y -= point.mY;
|
|
||||||
z -= point.mZ;
|
|
||||||
return sqrt(x * x + y * y + z * z);
|
|
||||||
}
|
|
||||||
|
|
||||||
float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b)
|
|
||||||
{
|
|
||||||
float x = a.mX - b.mX;
|
|
||||||
float y = a.mY - b.mY;
|
|
||||||
float z = a.mZ - b.mZ;
|
|
||||||
return sqrt(x * x + y * y + z * z);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slightly cheaper version for comparisons.
|
// Slightly cheaper version for comparisons.
|
||||||
// Caller needs to be careful for very short distances (i.e. less than 1)
|
// Caller needs to be careful for very short distances (i.e. less than 1)
|
||||||
// or when accumuating the results i.e. (a + b)^2 != a^2 + b^2
|
// or when accumuating the results i.e. (a + b)^2 != a^2 + b^2
|
||||||
|
@ -114,6 +90,30 @@ namespace
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
float distanceZCorrected(ESM::Pathgrid::Point point, float x, float y, float z)
|
||||||
|
{
|
||||||
|
x -= point.mX;
|
||||||
|
y -= point.mY;
|
||||||
|
z -= point.mZ;
|
||||||
|
return sqrt(x * x + y * y + 0.1 * z * z);
|
||||||
|
}
|
||||||
|
|
||||||
|
float distance(ESM::Pathgrid::Point point, float x, float y, float z)
|
||||||
|
{
|
||||||
|
x -= point.mX;
|
||||||
|
y -= point.mY;
|
||||||
|
z -= point.mZ;
|
||||||
|
return sqrt(x * x + y * y + z * z);
|
||||||
|
}
|
||||||
|
|
||||||
|
float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b)
|
||||||
|
{
|
||||||
|
float x = a.mX - b.mX;
|
||||||
|
float y = a.mY - b.mY;
|
||||||
|
float z = a.mZ - b.mZ;
|
||||||
|
return sqrt(x * x + y * y + z * z);
|
||||||
|
}
|
||||||
|
|
||||||
PathFinder::PathFinder()
|
PathFinder::PathFinder()
|
||||||
: mIsPathConstructed(false),
|
: mIsPathConstructed(false),
|
||||||
mPathgrid(NULL),
|
mPathgrid(NULL),
|
||||||
|
|
|
@ -13,6 +13,8 @@ namespace MWWorld
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
float distance(ESM::Pathgrid::Point point, float x, float y, float);
|
||||||
|
float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b);
|
||||||
class PathFinder
|
class PathFinder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "../mwmechanics/spellcasting.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
#include "../mwmechanics/levelledlist.hpp"
|
#include "../mwmechanics/levelledlist.hpp"
|
||||||
#include "../mwmechanics/combat.hpp"
|
#include "../mwmechanics/combat.hpp"
|
||||||
|
#include "../mwmechanics/aiavoiddoor.hpp" //Used to tell actors to avoid doors
|
||||||
|
|
||||||
#include "../mwrender/sky.hpp"
|
#include "../mwrender/sky.hpp"
|
||||||
#include "../mwrender/animation.hpp"
|
#include "../mwrender/animation.hpp"
|
||||||
|
@ -1216,9 +1217,16 @@ namespace MWWorld
|
||||||
MWWorld::Ptr ptr = getPtrViaHandle(*cit);
|
MWWorld::Ptr ptr = getPtrViaHandle(*cit);
|
||||||
if (MWWorld::Class::get(ptr).isActor())
|
if (MWWorld::Class::get(ptr).isActor())
|
||||||
{
|
{
|
||||||
// we collided with an actor, we need to undo the rotation
|
// Collided with actor, ask actor to try to avoid door
|
||||||
|
if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr() ) {
|
||||||
|
MWMechanics::AiSequence& seq = MWWorld::Class::get(ptr).getCreatureStats(ptr).getAiSequence();
|
||||||
|
if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) //Only add it once
|
||||||
|
seq.stack(MWMechanics::AiAvoidDoor(it->first),ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to undo the rotation
|
||||||
localRotateObject(it->first, 0, 0, oldRot);
|
localRotateObject(it->first, 0, 0, oldRot);
|
||||||
break;
|
//break; //Removed in case multiple actors are touching
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1862,6 +1870,12 @@ namespace MWWorld
|
||||||
return door.getRefData().getLocalRotation().rot[2] == 0;
|
return door.getRefData().getLocalRotation().rot[2] == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool World::getIsMovingDoor(const Ptr& door)
|
||||||
|
{
|
||||||
|
bool result = mDoorStates.find(door) != mDoorStates.end();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool World::getPlayerStandingOn (const MWWorld::Ptr& object)
|
bool World::getPlayerStandingOn (const MWWorld::Ptr& object)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = mPlayer->getPlayer();
|
MWWorld::Ptr player = mPlayer->getPlayer();
|
||||||
|
|
|
@ -496,10 +496,13 @@ namespace MWWorld
|
||||||
virtual void setupPlayer();
|
virtual void setupPlayer();
|
||||||
virtual void renderPlayer();
|
virtual void renderPlayer();
|
||||||
|
|
||||||
|
/// if activated, should this door be opened or closed?
|
||||||
virtual bool getOpenOrCloseDoor(const MWWorld::Ptr& door);
|
virtual bool getOpenOrCloseDoor(const MWWorld::Ptr& door);
|
||||||
///< if activated, should this door be opened or closed?
|
|
||||||
|
/// activate (open or close) an non-teleport door
|
||||||
virtual void activateDoor(const MWWorld::Ptr& door);
|
virtual void activateDoor(const MWWorld::Ptr& door);
|
||||||
///< activate (open or close) an non-teleport door
|
|
||||||
|
virtual bool getIsMovingDoor(const MWWorld::Ptr& door);
|
||||||
|
|
||||||
virtual bool getPlayerStandingOn (const MWWorld::Ptr& object); ///< @return true if the player is standing on \a object
|
virtual bool getPlayerStandingOn (const MWWorld::Ptr& object); ///< @return true if the player is standing on \a object
|
||||||
virtual bool getActorStandingOn (const MWWorld::Ptr& object); ///< @return true if any actor is standing on \a object
|
virtual bool getActorStandingOn (const MWWorld::Ptr& object); ///< @return true if any actor is standing on \a object
|
||||||
|
|
|
@ -98,10 +98,8 @@ namespace Compiler
|
||||||
int parseArguments (const std::string& arguments, Scanner& scanner,
|
int parseArguments (const std::string& arguments, Scanner& scanner,
|
||||||
std::vector<Interpreter::Type_Code>& code, bool invert = false);
|
std::vector<Interpreter::Type_Code>& code, bool invert = false);
|
||||||
///< Parse sequence of arguments specified by \a arguments.
|
///< Parse sequence of arguments specified by \a arguments.
|
||||||
/// \param arguments Each character represents one arguments ('l': integer,
|
/// \param arguments Uses ScriptArgs typedef
|
||||||
/// 'f': float, 'S': string, 'c': string (case smashed), '/': following arguments are
|
/// \see Compiler::ScriptArgs
|
||||||
/// optional)
|
|
||||||
/// 'x': optional string that will be ignored (die in a fire, MW script compiler!)
|
|
||||||
/// \param invert Store arguments in reverted order.
|
/// \param invert Store arguments in reverted order.
|
||||||
/// \return number of optional arguments
|
/// \return number of optional arguments
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace Compiler
|
||||||
return iter->second;
|
return iter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Extensions::isFunction (int keyword, char& returnType, std::string& argumentType,
|
bool Extensions::isFunction (int keyword, ScriptReturn& returnType, ScriptArgs& argumentType,
|
||||||
bool& explicitReference) const
|
bool& explicitReference) const
|
||||||
{
|
{
|
||||||
std::map<int, Function>::const_iterator iter = mFunctions.find (keyword);
|
std::map<int, Function>::const_iterator iter = mFunctions.find (keyword);
|
||||||
|
@ -37,7 +37,7 @@ namespace Compiler
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Extensions::isInstruction (int keyword, std::string& argumentType,
|
bool Extensions::isInstruction (int keyword, ScriptArgs& argumentType,
|
||||||
bool& explicitReference) const
|
bool& explicitReference) const
|
||||||
{
|
{
|
||||||
std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword);
|
std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword);
|
||||||
|
@ -52,8 +52,8 @@ namespace Compiler
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Extensions::registerFunction (const std::string& keyword, char returnType,
|
void Extensions::registerFunction (const std::string& keyword, ScriptReturn returnType,
|
||||||
const std::string& argumentType, int code, int codeExplicit)
|
const ScriptArgs& argumentType, int code, int codeExplicit)
|
||||||
{
|
{
|
||||||
Function function;
|
Function function;
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ namespace Compiler
|
||||||
}
|
}
|
||||||
|
|
||||||
void Extensions::registerInstruction (const std::string& keyword,
|
void Extensions::registerInstruction (const std::string& keyword,
|
||||||
const std::string& argumentType, int code, int codeExplicit)
|
const ScriptArgs& argumentType, int code, int codeExplicit)
|
||||||
{
|
{
|
||||||
Instruction instruction;
|
Instruction instruction;
|
||||||
|
|
||||||
|
|
|
@ -11,14 +11,35 @@ namespace Compiler
|
||||||
{
|
{
|
||||||
class Literals;
|
class Literals;
|
||||||
|
|
||||||
/// \brief Collection of compiler extensions
|
/// Typedef for script arguments string
|
||||||
|
/** Every character reperesents an argument to the command. All arguments are required until a /, after which
|
||||||
|
every argument is optional. <BR>
|
||||||
|
Eg: fff/f represents 3 required floats followed by one optional float <BR>
|
||||||
|
f - Float <BR>
|
||||||
|
c - String, case smashed <BR>
|
||||||
|
l - Integer <BR>
|
||||||
|
s - Short <BR>
|
||||||
|
S - String, case preserved <BR>
|
||||||
|
x - Optional, ignored argument
|
||||||
|
**/
|
||||||
|
typedef std::string ScriptArgs;
|
||||||
|
|
||||||
|
/// Typedef for script return char
|
||||||
|
/** The character represents the type of data being returned. <BR>
|
||||||
|
f - float <BR>
|
||||||
|
S - String (Cell names) <BR>
|
||||||
|
l - Integer
|
||||||
|
**/
|
||||||
|
typedef char ScriptReturn;
|
||||||
|
|
||||||
|
/// \brief Collection of compiler extensions
|
||||||
class Extensions
|
class Extensions
|
||||||
{
|
{
|
||||||
|
|
||||||
struct Function
|
struct Function
|
||||||
{
|
{
|
||||||
char mReturn;
|
char mReturn;
|
||||||
std::string mArguments;
|
ScriptArgs mArguments;
|
||||||
int mCode;
|
int mCode;
|
||||||
int mCodeExplicit;
|
int mCodeExplicit;
|
||||||
int mSegment;
|
int mSegment;
|
||||||
|
@ -26,7 +47,7 @@ namespace Compiler
|
||||||
|
|
||||||
struct Instruction
|
struct Instruction
|
||||||
{
|
{
|
||||||
std::string mArguments;
|
ScriptArgs mArguments;
|
||||||
int mCode;
|
int mCode;
|
||||||
int mCodeExplicit;
|
int mCodeExplicit;
|
||||||
int mSegment;
|
int mSegment;
|
||||||
|
@ -46,21 +67,21 @@ namespace Compiler
|
||||||
/// - if no match is found 0 is returned.
|
/// - if no match is found 0 is returned.
|
||||||
/// - keyword must be all lower case.
|
/// - keyword must be all lower case.
|
||||||
|
|
||||||
bool isFunction (int keyword, char& returnType, std::string& argumentType,
|
bool isFunction (int keyword, ScriptReturn& returnType, ScriptArgs& argumentType,
|
||||||
bool& explicitReference) const;
|
bool& explicitReference) const;
|
||||||
///< Is this keyword registered with a function? If yes, return return and argument
|
///< Is this keyword registered with a function? If yes, return return and argument
|
||||||
/// types.
|
/// types.
|
||||||
/// \param explicitReference In: has explicit reference; Out: set to false, if
|
/// \param explicitReference In: has explicit reference; Out: set to false, if
|
||||||
/// explicit reference is not available for this instruction.
|
/// explicit reference is not available for this instruction.
|
||||||
|
|
||||||
bool isInstruction (int keyword, std::string& argumentType,
|
bool isInstruction (int keyword, ScriptArgs& argumentType,
|
||||||
bool& explicitReference) const;
|
bool& explicitReference) const;
|
||||||
///< Is this keyword registered with a function? If yes, return argument types.
|
///< Is this keyword registered with a function? If yes, return argument types.
|
||||||
/// \param explicitReference In: has explicit reference; Out: set to false, if
|
/// \param explicitReference In: has explicit reference; Out: set to false, if
|
||||||
/// explicit reference is not available for this instruction.
|
/// explicit reference is not available for this instruction.
|
||||||
|
|
||||||
void registerFunction (const std::string& keyword, char returnType,
|
void registerFunction (const std::string& keyword, ScriptReturn returnType,
|
||||||
const std::string& argumentType, int code, int codeExplicit = -1);
|
const ScriptArgs& argumentType, int code, int codeExplicit = -1);
|
||||||
///< Register a custom function
|
///< Register a custom function
|
||||||
/// - keyword must be all lower case.
|
/// - keyword must be all lower case.
|
||||||
/// - keyword must be unique
|
/// - keyword must be unique
|
||||||
|
@ -68,7 +89,7 @@ namespace Compiler
|
||||||
/// \note Currently only segment 3 and segment 5 opcodes are supported.
|
/// \note Currently only segment 3 and segment 5 opcodes are supported.
|
||||||
|
|
||||||
void registerInstruction (const std::string& keyword,
|
void registerInstruction (const std::string& keyword,
|
||||||
const std::string& argumentType, int code, int codeExplicit = -1);
|
const ScriptArgs& argumentType, int code, int codeExplicit = -1);
|
||||||
///< Register a custom instruction
|
///< Register a custom instruction
|
||||||
/// - keyword must be all lower case.
|
/// - keyword must be all lower case.
|
||||||
/// - keyword must be unique
|
/// - keyword must be unique
|
||||||
|
|
|
@ -8,6 +8,20 @@ namespace ESM
|
||||||
{
|
{
|
||||||
unsigned int Pathgrid::sRecordId = REC_PGRD;
|
unsigned int Pathgrid::sRecordId = REC_PGRD;
|
||||||
|
|
||||||
|
Pathgrid::Point& Pathgrid::Point::operator=(const float rhs[3]) {
|
||||||
|
mX = rhs[0];
|
||||||
|
mY = rhs[1];
|
||||||
|
mZ = rhs[2];
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Pathgrid::Point::Point(const float rhs[3]) {
|
||||||
|
mX = rhs[0];
|
||||||
|
mY = rhs[1];
|
||||||
|
mZ = rhs[2];
|
||||||
|
}
|
||||||
|
Pathgrid::Point::Point():mX(0),mY(0),mZ(0) {
|
||||||
|
}
|
||||||
|
|
||||||
void Pathgrid::load(ESMReader &esm)
|
void Pathgrid::load(ESMReader &esm)
|
||||||
{
|
{
|
||||||
esm.getHNT(mData, "DATA", 12);
|
esm.getHNT(mData, "DATA", 12);
|
||||||
|
|
|
@ -31,6 +31,10 @@ struct Pathgrid
|
||||||
unsigned char mAutogenerated; // autogenerated vs. user coloring flag?
|
unsigned char mAutogenerated; // autogenerated vs. user coloring flag?
|
||||||
unsigned char mConnectionNum; // number of connections for this point
|
unsigned char mConnectionNum; // number of connections for this point
|
||||||
short mUnknown;
|
short mUnknown;
|
||||||
|
Point& operator=(const float[3]);
|
||||||
|
Point(const float[3]);
|
||||||
|
Point();
|
||||||
|
Point(int x, int y, int z) : mX(x), mY(y), mZ(z) {}
|
||||||
}; // 16 bytes
|
}; // 16 bytes
|
||||||
|
|
||||||
struct Edge // path grid edge
|
struct Edge // path grid edge
|
||||||
|
|
|
@ -33,6 +33,7 @@ Edmondo Tommasina (edmondo)
|
||||||
Eduard Cot (trombonecot)
|
Eduard Cot (trombonecot)
|
||||||
Eli2
|
Eli2
|
||||||
Emanuel Guével (potatoesmaster)
|
Emanuel Guével (potatoesmaster)
|
||||||
|
Fil Krynicki (filkry)
|
||||||
gugus/gus
|
gugus/gus
|
||||||
Jacob Essex (Yacoby)
|
Jacob Essex (Yacoby)
|
||||||
Jannik Heller (scrawl)
|
Jannik Heller (scrawl)
|
||||||
|
|
Loading…
Reference in a new issue