forked from teamnwah/openmw-tes3coop
Merge branch 'master' of https://github.com/zinnschlag/openmw into sdl_input2
Conflicts: apps/openmw/mwinput/inputmanagerimp.cpp
This commit is contained in:
commit
4c8a04d9cb
34 changed files with 1093 additions and 749 deletions
|
@ -4,6 +4,10 @@ if (APPLE)
|
|||
set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app")
|
||||
|
||||
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}")
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-F /Library/Frameworks")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "-F /Library/Frameworks")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "-F /Library/Frameworks")
|
||||
endif (APPLE)
|
||||
|
||||
# Macros
|
||||
|
@ -15,7 +19,7 @@ include (OpenMWMacros)
|
|||
# Version
|
||||
|
||||
set (OPENMW_VERSION_MAJOR 0)
|
||||
set (OPENMW_VERSION_MINOR 23)
|
||||
set (OPENMW_VERSION_MINOR 24)
|
||||
set (OPENMW_VERSION_RELEASE 0)
|
||||
|
||||
set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
||||
|
|
|
@ -310,6 +310,8 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
|
|||
|
||||
bool MainDialog::setupLauncherSettings()
|
||||
{
|
||||
mLauncherSettings.setMultiValueEnabled(true);
|
||||
|
||||
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
|
||||
|
||||
QStringList paths;
|
||||
|
@ -427,6 +429,8 @@ bool MainDialog::setupGameSettings()
|
|||
|
||||
bool MainDialog::setupGraphicsSettings()
|
||||
{
|
||||
mGraphicsSettings.setMultiValueEnabled(false);
|
||||
|
||||
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
|
||||
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string());
|
||||
|
||||
|
|
|
@ -103,8 +103,8 @@ bool GameSettings::readFile(QTextStream &stream)
|
|||
|
||||
if (keyRe.indexIn(line) != -1) {
|
||||
|
||||
QString key = keyRe.cap(1);
|
||||
QString value = keyRe.cap(2);
|
||||
QString key = keyRe.cap(1).trimmed();
|
||||
QString value = keyRe.cap(2).trimmed();
|
||||
|
||||
// Don't remove existing data entries
|
||||
if (key != QLatin1String("data"))
|
||||
|
|
|
@ -14,7 +14,7 @@ class SettingsBase
|
|||
{
|
||||
|
||||
public:
|
||||
SettingsBase() {}
|
||||
SettingsBase() { mMultiValue = false; }
|
||||
~SettingsBase() {}
|
||||
|
||||
inline QString value(const QString &key, const QString &defaultValue = QString())
|
||||
|
@ -36,6 +36,11 @@ public:
|
|||
mSettings.insertMulti(key, value);
|
||||
}
|
||||
|
||||
inline void setMultiValueEnabled(bool enable)
|
||||
{
|
||||
mMultiValue = enable;
|
||||
}
|
||||
|
||||
inline void remove(const QString &key)
|
||||
{
|
||||
mSettings.remove(key);
|
||||
|
@ -66,8 +71,8 @@ public:
|
|||
|
||||
if (keyRe.indexIn(line) != -1) {
|
||||
|
||||
QString key = keyRe.cap(1);
|
||||
QString value = keyRe.cap(2);
|
||||
QString key = keyRe.cap(1).trimmed();
|
||||
QString value = keyRe.cap(2).trimmed();
|
||||
|
||||
if (!sectionPrefix.isEmpty())
|
||||
key.prepend(sectionPrefix);
|
||||
|
@ -75,8 +80,13 @@ public:
|
|||
mSettings.remove(key);
|
||||
|
||||
QStringList values = mCache.values(key);
|
||||
|
||||
if (!values.contains(value)) {
|
||||
mCache.insertMulti(key, value);
|
||||
if (mMultiValue) {
|
||||
mCache.insertMulti(key, value);
|
||||
} else {
|
||||
mCache.insert(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,6 +104,8 @@ public:
|
|||
private:
|
||||
Map mSettings;
|
||||
Map mCache;
|
||||
|
||||
bool mMultiValue;
|
||||
};
|
||||
|
||||
#endif // SETTINGSBASE_HPP
|
||||
|
|
|
@ -79,6 +79,7 @@ opencs_units (view/settings
|
|||
abstractwidget
|
||||
usersettingsdialog
|
||||
editorpage
|
||||
windowpage
|
||||
)
|
||||
|
||||
opencs_units_noqt (view/settings
|
||||
|
|
|
@ -61,6 +61,17 @@ void CS::Editor::setupDataFiles()
|
|||
QString path = QString::fromStdString(iter->string());
|
||||
mFileDialog.addFiles(path);
|
||||
}
|
||||
|
||||
//Settings setup
|
||||
QStringList settingFiles;
|
||||
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
|
||||
|
||||
settingFiles.append(QString("opencs.cfg"));
|
||||
settingFiles.append(userPath + QString("opencs.cfg"));
|
||||
|
||||
mUserSettings.setSettingsFiles(settingFiles);
|
||||
mUserSettings.readSettings();
|
||||
|
||||
}
|
||||
|
||||
void CS::Editor::createDocument()
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "view/doc/viewmanager.hpp"
|
||||
#include "view/doc/startup.hpp"
|
||||
#include "view/doc/filedialog.hpp"
|
||||
#include "model/settings/usersettings.hpp"
|
||||
|
||||
namespace CS
|
||||
{
|
||||
|
@ -17,6 +18,7 @@ namespace CS
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
CSMSettings::UserSettings mUserSettings;
|
||||
CSMDoc::DocumentManager mDocumentManager;
|
||||
CSVDoc::ViewManager mViewManager;
|
||||
CSVDoc::StartupDialogue mStartup;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <QMap>
|
||||
#include <QMessageBox>
|
||||
#include <QTextCodec>
|
||||
#include <QDebug>
|
||||
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
|
@ -29,17 +30,25 @@ namespace boost
|
|||
} /* namespace boost */
|
||||
#endif /* (BOOST_VERSION <= 104600) */
|
||||
|
||||
CSMSettings::UserSettings *CSMSettings::UserSettings::mUserSettingsInstance = 0;
|
||||
|
||||
CSMSettings::UserSettings::UserSettings()
|
||||
{
|
||||
assert(!mUserSettingsInstance);
|
||||
mUserSettingsInstance = this;
|
||||
}
|
||||
|
||||
CSMSettings::UserSettings::~UserSettings()
|
||||
{
|
||||
mUserSettingsInstance = 0;
|
||||
}
|
||||
|
||||
QFile *CSMSettings::UserSettings::openFile (const QString &filename)
|
||||
CSMSettings::SectionMap CSMSettings::UserSettings::getSettingsMap() const
|
||||
{
|
||||
return mSectionMap;
|
||||
}
|
||||
|
||||
QFile *CSMSettings::UserSettings::openFile (const QString &filename) const
|
||||
{
|
||||
QFile *file = new QFile(filename);
|
||||
|
||||
|
@ -63,7 +72,7 @@ QFile *CSMSettings::UserSettings::openFile (const QString &filename)
|
|||
return file;
|
||||
}
|
||||
|
||||
bool CSMSettings::UserSettings::writeFile(QFile *file, QMap<QString, CSMSettings::SettingList *> &settings)
|
||||
bool CSMSettings::UserSettings::writeFile(QFile *file, QMap<QString, CSMSettings::SettingList *> &settings) const
|
||||
{
|
||||
if (!file)
|
||||
return false;
|
||||
|
@ -88,7 +97,7 @@ bool CSMSettings::UserSettings::writeFile(QFile *file, QMap<QString, CSMSettings
|
|||
return true;
|
||||
}
|
||||
|
||||
void CSMSettings::UserSettings::getSettings(QTextStream &stream, SectionMap §ions)
|
||||
void CSMSettings::UserSettings::getSettings(QTextStream &stream, SectionMap §ions) const
|
||||
{
|
||||
//looks for a square bracket, "'\\["
|
||||
//that has one or more "not nothing" in it, "([^]]+)"
|
||||
|
@ -135,3 +144,70 @@ void CSMSettings::UserSettings::getSettings(QTextStream &stream, SectionMap &sec
|
|||
}
|
||||
sections.insert(section, settings);
|
||||
}
|
||||
|
||||
void CSMSettings::UserSettings::readSettings()
|
||||
{
|
||||
CSMSettings::SectionMap sectionMap;
|
||||
|
||||
foreach (const QString &path, mSettingsFiles)
|
||||
{
|
||||
qDebug() << "Loading config file:" << qPrintable(path);
|
||||
QFile file(path);
|
||||
|
||||
if (file.exists())
|
||||
{
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle(tr("Error opening OpenCS configuration file"));
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(QObject::tr("<br><b>Could not open %0 for reading</b><br><br> \
|
||||
Please make sure you have the right permissions \
|
||||
and try again.<br>").arg(file.fileName()));
|
||||
msgBox.exec();
|
||||
return;
|
||||
}
|
||||
|
||||
QTextStream stream(&file);
|
||||
stream.setCodec(QTextCodec::codecForName("UTF-8"));
|
||||
|
||||
|
||||
getSettings(stream, mSectionMap);
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void CSMSettings::UserSettings::setSettingsFiles(QStringList files)
|
||||
{
|
||||
mSettingsFiles = files;
|
||||
}
|
||||
|
||||
QStringList CSMSettings::UserSettings::getSettingsFiles () const
|
||||
{
|
||||
return mSettingsFiles;
|
||||
}
|
||||
|
||||
QString CSMSettings::UserSettings::getSettingValue(QString section, QString setting) const
|
||||
{
|
||||
if(mSectionMap.find(section) == mSectionMap.end())
|
||||
return QString();
|
||||
|
||||
CSMSettings::SettingMap *settings = mSectionMap.value(section);
|
||||
|
||||
if(settings->find(setting) == settings->end())
|
||||
return QString();
|
||||
|
||||
CSMSettings::SettingContainer *settingContainer = settings->value(setting);
|
||||
|
||||
return settingContainer->getValue();
|
||||
}
|
||||
|
||||
const CSMSettings::UserSettings& CSMSettings::UserSettings::instance()
|
||||
{
|
||||
assert(mUserSettingsInstance);
|
||||
return *mUserSettingsInstance;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,22 +24,27 @@ namespace CSMSettings {
|
|||
|
||||
public:
|
||||
|
||||
static UserSettings &instance()
|
||||
{
|
||||
static UserSettings instance;
|
||||
UserSettings();
|
||||
~UserSettings();
|
||||
|
||||
return instance;
|
||||
}
|
||||
static const UserSettings& instance();
|
||||
|
||||
QFile *openFile (const QString &);
|
||||
bool writeFile(QFile *file, QMap<QString, SettingList *> §ions);
|
||||
void getSettings (QTextStream &stream, SectionMap &settings);
|
||||
void readSettings();
|
||||
void setSettingsFiles(QStringList files);
|
||||
|
||||
QFile *openFile (const QString &) const;
|
||||
bool writeFile(QFile *file, QMap<QString, SettingList *> §ions) const;
|
||||
void getSettings (QTextStream &stream, SectionMap &settings) const;
|
||||
QStringList getSettingsFiles () const;
|
||||
CSMSettings::SectionMap getSettingsMap() const;
|
||||
QString getSettingValue(QString section, QString setting) const;
|
||||
|
||||
private:
|
||||
|
||||
UserSettings *mUserSettingsInstance;
|
||||
UserSettings();
|
||||
~UserSettings();
|
||||
static UserSettings *mUserSettingsInstance;
|
||||
|
||||
CSMSettings::SectionMap mSectionMap;
|
||||
QStringList mSettingsFiles;
|
||||
|
||||
UserSettings (UserSettings const &); //not implemented
|
||||
void operator= (UserSettings const &); //not implemented
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <QMdiArea>
|
||||
#include <QDockWidget>
|
||||
#include <QtGui/QApplication>
|
||||
#include <QDebug>
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
#include "../world/subviews.hpp"
|
||||
|
@ -179,7 +180,12 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to
|
|||
: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1),
|
||||
mViewTotal (totalViews)
|
||||
{
|
||||
resize (300, 300); /// \todo get default size from settings and set reasonable minimal size
|
||||
QString width = CSMSettings::UserSettings::instance().getSettingValue(QString("Window Size"), QString("Width"));
|
||||
QString height = CSMSettings::UserSettings::instance().getSettingValue(QString("Window Size"), QString("Height"));
|
||||
if(width==QString() || height==QString())
|
||||
resize(800, 600);
|
||||
else
|
||||
resize (width.toInt(), height.toInt());
|
||||
|
||||
mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks);
|
||||
|
||||
|
|
|
@ -9,20 +9,21 @@
|
|||
#include <QFile>
|
||||
#include <QPushButton>
|
||||
#include <QDockWidget>
|
||||
#include <QDebug>
|
||||
|
||||
#include "blankpage.hpp"
|
||||
#include "editorpage.hpp"
|
||||
#include "windowpage.hpp"
|
||||
#include "../../model/settings/support.hpp"
|
||||
|
||||
#include "settingwidget.hpp"
|
||||
#include <QDebug>
|
||||
|
||||
CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) :
|
||||
QMainWindow (parent), mStackedWidget (0)
|
||||
{
|
||||
setWindowTitle(QString::fromUtf8 ("User Settings"));
|
||||
buildPages();
|
||||
setWidgetStates (loadSettings());
|
||||
setWidgetStates (CSMSettings::UserSettings::instance().getSettingsMap());
|
||||
positionWindow ();
|
||||
|
||||
connect (mListWidget,
|
||||
|
@ -76,9 +77,10 @@ void CSVSettings::UserSettingsDialog::buildPages()
|
|||
setDockOptions (QMainWindow::AllowNestedDocks);
|
||||
//uncomment to test with sample editor page.
|
||||
//createSamplePage();
|
||||
createPage<BlankPage>("Page1");
|
||||
/*createPage<BlankPage>("Page1");
|
||||
createPage<BlankPage>("Page2");
|
||||
createPage<BlankPage>("Page3");
|
||||
createPage<BlankPage>("Page3");*/
|
||||
createWindowPage();
|
||||
}
|
||||
|
||||
void CSVSettings::UserSettingsDialog::createSamplePage()
|
||||
|
@ -95,6 +97,20 @@ void CSVSettings::UserSettingsDialog::createSamplePage()
|
|||
&(CSMSettings::UserSettings::instance()), SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)));
|
||||
}
|
||||
|
||||
void CSVSettings::UserSettingsDialog::createWindowPage()
|
||||
{
|
||||
//add pages to stackedwidget and items to listwidget
|
||||
CSVSettings::AbstractPage *page
|
||||
= new CSVSettings::WindowPage(this);
|
||||
|
||||
mStackedWidget->addWidget (page);
|
||||
|
||||
new QListWidgetItem (page->objectName(), mListWidget);
|
||||
|
||||
connect ( page, SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)),
|
||||
&(CSMSettings::UserSettings::instance()), SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)));
|
||||
}
|
||||
|
||||
void CSVSettings::UserSettingsDialog::positionWindow ()
|
||||
{
|
||||
QRect scr = QApplication::desktop()->screenGeometry();
|
||||
|
@ -103,46 +119,6 @@ void CSVSettings::UserSettingsDialog::positionWindow ()
|
|||
|
||||
}
|
||||
|
||||
CSMSettings::SectionMap CSVSettings::UserSettingsDialog::loadSettings ()
|
||||
{
|
||||
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
|
||||
|
||||
mPaths.append(QString("opencs.cfg"));
|
||||
mPaths.append(userPath + QString("opencs.cfg"));
|
||||
|
||||
CSMSettings::SectionMap settingsMap;
|
||||
|
||||
foreach (const QString &path, mPaths)
|
||||
{
|
||||
qDebug() << "Loading config file:" << qPrintable(path);
|
||||
QFile file(path);
|
||||
|
||||
if (file.exists())
|
||||
{
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle(tr("Error opening OpenCS configuration file"));
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(QObject::tr("<br><b>Could not open %0 for reading</b><br><br> \
|
||||
Please make sure you have the right permissions \
|
||||
and try again.<br>").arg(file.fileName()));
|
||||
msgBox.exec();
|
||||
return settingsMap;
|
||||
}
|
||||
|
||||
QTextStream stream(&file);
|
||||
stream.setCodec(QTextCodec::codecForName("UTF-8"));
|
||||
|
||||
CSMSettings::UserSettings::instance().getSettings(stream, settingsMap);
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
return settingsMap;
|
||||
}
|
||||
|
||||
void CSVSettings::UserSettingsDialog::writeSettings()
|
||||
{
|
||||
|
@ -154,7 +130,9 @@ void CSVSettings::UserSettingsDialog::writeSettings()
|
|||
settings [page->objectName()] = page->getSettings();
|
||||
}
|
||||
|
||||
CSMSettings::UserSettings::instance().writeFile(CSMSettings::UserSettings::instance().openFile(mPaths.back()), settings);
|
||||
QStringList paths = CSMSettings::UserSettings::instance().getSettingsFiles();
|
||||
|
||||
CSMSettings::UserSettings::instance().writeFile(CSMSettings::UserSettings::instance().openFile(paths.back()), settings);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ namespace CSVSettings {
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
QStringList mPaths;
|
||||
QListWidget *mListWidget;
|
||||
QStackedWidget *mStackedWidget;
|
||||
Files::ConfigurationManager mCfgMgr;
|
||||
|
@ -41,10 +40,12 @@ namespace CSVSettings {
|
|||
void setWidgetStates (CSMSettings::SectionMap settingsMap);
|
||||
void buildPages();
|
||||
void positionWindow ();
|
||||
CSMSettings::SectionMap loadSettings();
|
||||
void writeSettings();
|
||||
void createSamplePage();
|
||||
|
||||
//Pages
|
||||
void createWindowPage();
|
||||
|
||||
template <typename T>
|
||||
void createPage (const QString &title)
|
||||
{
|
||||
|
|
114
apps/opencs/view/settings/windowpage.cpp
Normal file
114
apps/opencs/view/settings/windowpage.cpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
#include "windowpage.hpp"
|
||||
|
||||
#include <QList>
|
||||
#include <QListView>
|
||||
#include <QGroupBox>
|
||||
#include <QRadioButton>
|
||||
#include <QDockWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QGridLayout>
|
||||
#include <QStyle>
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#include <QPlastiqueStyle>
|
||||
#endif
|
||||
|
||||
#include "../../model/settings/usersettings.hpp"
|
||||
#include "groupblock.hpp"
|
||||
#include "toggleblock.hpp"
|
||||
|
||||
CSVSettings::WindowPage::WindowPage(QWidget *parent):
|
||||
AbstractPage("Window Size", parent)
|
||||
{
|
||||
// Hacks to get the stylesheet look properly
|
||||
#ifdef Q_OS_MAC
|
||||
QPlastiqueStyle *style = new QPlastiqueStyle;
|
||||
//profilesComboBox->setStyle(style);
|
||||
#endif
|
||||
|
||||
setupUi();
|
||||
}
|
||||
|
||||
void CSVSettings::WindowPage::setupUi()
|
||||
{
|
||||
GroupBlockDef customWindowSize (QString ("Custom Window Size"));
|
||||
GroupBlockDef definedWindowSize (QString ("Pre-Defined Window Size"));
|
||||
GroupBlockDef windowSizeToggle (QString ("Window Size"));
|
||||
CustomBlockDef windowSize (QString ("Window Size"));
|
||||
|
||||
|
||||
///////////////////////////////
|
||||
//custom window size properties
|
||||
///////////////////////////////
|
||||
|
||||
//custom width
|
||||
SettingsItemDef *widthItem = new SettingsItemDef ("Width", "640");
|
||||
widthItem->widget = WidgetDef (Widget_LineEdit);
|
||||
widthItem->widget.widgetWidth = 45;
|
||||
|
||||
//custom height
|
||||
SettingsItemDef *heightItem = new SettingsItemDef ("Height", "480");
|
||||
heightItem->widget = WidgetDef (Widget_LineEdit);
|
||||
heightItem->widget.widgetWidth = 45;
|
||||
heightItem->widget.caption = "x";
|
||||
|
||||
customWindowSize.properties << widthItem << heightItem;
|
||||
customWindowSize.widgetOrientation = Orient_Horizontal;
|
||||
customWindowSize.isVisible = false;
|
||||
|
||||
|
||||
//pre-defined
|
||||
SettingsItemDef *widthByHeightItem = new SettingsItemDef ("Window Size", "640x480");
|
||||
WidgetDef widthByHeightWidget = WidgetDef (Widget_ComboBox);
|
||||
widthByHeightWidget.widgetWidth = 90;
|
||||
*(widthByHeightItem->valueList) << "640x480" << "800x600" << "1024x768" << "1440x900";
|
||||
|
||||
QStringList *widthProxy = new QStringList;
|
||||
QStringList *heightProxy = new QStringList;
|
||||
|
||||
(*widthProxy) << "Width" << "640" << "800" << "1024" << "1440";
|
||||
(*heightProxy) << "Height" << "480" << "600" << "768" << "900";
|
||||
|
||||
*(widthByHeightItem->proxyList) << widthProxy << heightProxy;
|
||||
|
||||
widthByHeightItem->widget = widthByHeightWidget;
|
||||
|
||||
definedWindowSize.properties << widthByHeightItem;
|
||||
definedWindowSize.isProxy = true;
|
||||
definedWindowSize.isVisible = false;
|
||||
|
||||
// window size toggle
|
||||
windowSizeToggle.captions << "Pre-Defined" << "Custom";
|
||||
windowSizeToggle.widgetOrientation = Orient_Vertical;
|
||||
windowSizeToggle.isVisible = false;
|
||||
|
||||
//define a widget for each group in the toggle
|
||||
for (int i = 0; i < 2; i++)
|
||||
windowSizeToggle.widgets << new WidgetDef (Widget_RadioButton);
|
||||
|
||||
windowSizeToggle.widgets.at(0)->isDefault = false;
|
||||
|
||||
windowSize.blockDefList << &windowSizeToggle << &definedWindowSize << &customWindowSize;
|
||||
windowSize.defaultValue = "Custom";
|
||||
|
||||
QGridLayout *pageLayout = new QGridLayout(this);
|
||||
|
||||
setLayout (pageLayout);
|
||||
|
||||
mAbstractBlocks << buildBlock<ToggleBlock> (windowSize);
|
||||
|
||||
foreach (AbstractBlock *block, mAbstractBlocks)
|
||||
{
|
||||
connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)),
|
||||
this, SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)) );
|
||||
}
|
||||
}
|
||||
|
||||
void CSVSettings::WindowPage::initializeWidgets (const CSMSettings::SettingMap &settings)
|
||||
{
|
||||
//iterate each item in each blocks in this section
|
||||
//validate the corresponding setting against the defined valuelist if any.
|
||||
for (AbstractBlockList::Iterator it_block = mAbstractBlocks.begin();
|
||||
it_block != mAbstractBlocks.end(); ++it_block)
|
||||
(*it_block)->updateSettings (settings);
|
||||
}
|
28
apps/opencs/view/settings/windowpage.hpp
Normal file
28
apps/opencs/view/settings/windowpage.hpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef WINDOWPAGE_H
|
||||
#define WINDOWPAGE_H
|
||||
|
||||
#include "abstractpage.hpp"
|
||||
|
||||
class QGroupBox;
|
||||
|
||||
namespace CSVSettings {
|
||||
|
||||
class UserSettings;
|
||||
class AbstractBlock;
|
||||
|
||||
class WindowPage : public AbstractPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
WindowPage(QWidget *parent = 0);
|
||||
|
||||
void setupUi();
|
||||
void initializeWidgets (const CSMSettings::SettingMap &settings);
|
||||
|
||||
signals:
|
||||
void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue);
|
||||
};
|
||||
}
|
||||
#endif //WINDOWPAGE_H
|
|
@ -130,26 +130,12 @@ namespace MWGui
|
|||
|
||||
void BookWindow::onNextPageButtonClicked (MyGUI::Widget* sender)
|
||||
{
|
||||
if ((mCurrentPage+1)*2 < mPages.size())
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("book page2", 1.0, 1.0);
|
||||
|
||||
++mCurrentPage;
|
||||
|
||||
updatePages();
|
||||
}
|
||||
nextPage();
|
||||
}
|
||||
|
||||
void BookWindow::onPrevPageButtonClicked (MyGUI::Widget* sender)
|
||||
{
|
||||
if (mCurrentPage > 0)
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("book page", 1.0, 1.0);
|
||||
|
||||
--mCurrentPage;
|
||||
|
||||
updatePages();
|
||||
}
|
||||
prevPage();
|
||||
}
|
||||
|
||||
void BookWindow::updatePages()
|
||||
|
@ -194,5 +180,28 @@ namespace MWGui
|
|||
if (button->getAlign().isRight())
|
||||
button->setPosition(button->getPosition() + MyGUI::IntPoint(diff.width,0));
|
||||
}
|
||||
|
||||
void BookWindow::nextPage()
|
||||
{
|
||||
if ((mCurrentPage+1)*2 < mPages.size())
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("book page2", 1.0, 1.0);
|
||||
|
||||
++mCurrentPage;
|
||||
|
||||
updatePages();
|
||||
}
|
||||
}
|
||||
void BookWindow::prevPage()
|
||||
{
|
||||
if (mCurrentPage > 0)
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("book page", 1.0, 1.0);
|
||||
|
||||
--mCurrentPage;
|
||||
|
||||
updatePages();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ namespace MWGui
|
|||
|
||||
void open(MWWorld::Ptr book);
|
||||
void setTakeButtonShow(bool show);
|
||||
|
||||
void nextPage();
|
||||
void prevPage();
|
||||
void setInventoryAllowed(bool allowed);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -251,10 +251,8 @@ namespace MWGui
|
|||
MyGUI::Gui::getInstance().destroyWidget(mParent->getChildAt(0));
|
||||
}
|
||||
|
||||
boost::algorithm::replace_all(text, "\n", "\n");
|
||||
boost::algorithm::replace_all(text, "\r", "\r");
|
||||
boost::algorithm::replace_all(text, "<BR>", "\n\n");
|
||||
boost::algorithm::replace_all(text, "<P>", "\n\n"); // tweaking by adding another newline to see if that spaces out better
|
||||
boost::algorithm::replace_all(text, "<BR>", "\n");
|
||||
boost::algorithm::replace_all(text, "<P>", "\n\n");
|
||||
boost::algorithm::trim_left(text);
|
||||
|
||||
// remove trailing "
|
||||
|
|
|
@ -183,7 +183,7 @@ namespace
|
|||
if (!MWBase::Environment::get().getWindowManager ()->getJournalAllowed ())
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->popGuiMode ();
|
||||
}
|
||||
}
|
||||
mModel->load ();
|
||||
|
||||
setBookMode ();
|
||||
|
@ -433,7 +433,6 @@ namespace
|
|||
void notifyClose(MyGUI::Widget* _sender)
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0);
|
||||
|
||||
MWBase::Environment::get().getWindowManager ()->popGuiMode ();
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,10 @@ namespace MWGui
|
|||
{
|
||||
}
|
||||
|
||||
LocalMapBase::~LocalMapBase()
|
||||
{
|
||||
}
|
||||
|
||||
void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop)
|
||||
{
|
||||
mLocalMap = widget;
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace MWGui
|
|||
{
|
||||
public:
|
||||
LocalMapBase();
|
||||
virtual ~LocalMapBase();
|
||||
void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop=false);
|
||||
|
||||
void setCellPrefix(const std::string& prefix);
|
||||
|
|
|
@ -416,6 +416,10 @@ namespace MWGui
|
|||
mAddEffectDialog.setVisible (false);
|
||||
}
|
||||
|
||||
EffectEditorBase::~EffectEditorBase()
|
||||
{
|
||||
}
|
||||
|
||||
void EffectEditorBase::startEditing ()
|
||||
{
|
||||
// get the list of magic effects that are known to the player
|
||||
|
|
|
@ -84,7 +84,7 @@ namespace MWGui
|
|||
{
|
||||
public:
|
||||
EffectEditorBase();
|
||||
|
||||
virtual ~EffectEditorBase();
|
||||
|
||||
protected:
|
||||
std::map<int, short> mButtonMapping; // maps button ID to effect ID
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwgui/bookwindow.hpp"
|
||||
|
||||
using namespace ICS;
|
||||
|
||||
|
@ -488,6 +489,15 @@ namespace MWInput
|
|||
mMouseWheel = int(arg.z);
|
||||
|
||||
MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel);
|
||||
|
||||
//if the player is reading a book and flicking the mouse wheel
|
||||
if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Book && arg.zrel)
|
||||
{
|
||||
if (arg.zrel < 0)
|
||||
MWBase::Environment::get().getWindowManager()->getBookWindow()->nextPage();
|
||||
else
|
||||
MWBase::Environment::get().getWindowManager()->getBookWindow()->prevPage();
|
||||
}
|
||||
}
|
||||
|
||||
if (mMouseLookEnabled)
|
||||
|
@ -636,7 +646,7 @@ namespace MWInput
|
|||
// Toggle between game mode and journal mode
|
||||
bool gameMode = !mWindows.isGuiMode();
|
||||
|
||||
if(gameMode)
|
||||
if(gameMode && MWBase::Environment::get().getWindowManager ()->getJournalAllowed())
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0);
|
||||
mWindows.pushGuiMode(MWGui::GM_Journal);
|
||||
|
|
|
@ -13,8 +13,9 @@ namespace
|
|||
{
|
||||
float sgn(float a)
|
||||
{
|
||||
if(a > 0) return 1.0;
|
||||
else return -1.0;
|
||||
if(a > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,151 +25,156 @@ namespace
|
|||
TODO: Take account for actors being in different cells.
|
||||
*/
|
||||
|
||||
MWMechanics::AiEscort::AiEscort(const std::string &actorId,int duration, float x, float y, float z)
|
||||
: mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration)
|
||||
namespace MWMechanics
|
||||
{
|
||||
mMaxDist = 470;
|
||||
|
||||
// The CS Help File states that if a duration is givin, the AI package will run for that long
|
||||
// BUT if a location is givin, it "trumps" the duration so it will simply escort to that location.
|
||||
if(mX != 0 || mY != 0 || mZ != 0)
|
||||
mDuration = 0;
|
||||
|
||||
else
|
||||
AiEscort::AiEscort(const std::string &actorId, int duration, float x, float y, float z)
|
||||
: mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration)
|
||||
{
|
||||
MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100);
|
||||
}
|
||||
}
|
||||
|
||||
MWMechanics::AiEscort::AiEscort(const std::string &actorId,const std::string &cellId,int duration, float x, float y, float z)
|
||||
: mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration)
|
||||
{
|
||||
mMaxDist = 470;
|
||||
|
||||
// The CS Help File states that if a duration is givin, the AI package will run for that long
|
||||
// BUT if a location is givin, it "trumps" the duration so it will simply escort to that location.
|
||||
if(mX != 0 || mY != 0 || mZ != 0)
|
||||
mDuration = 0;
|
||||
|
||||
else
|
||||
{
|
||||
MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MWMechanics::AiEscort *MWMechanics::AiEscort::clone() const
|
||||
{
|
||||
return new AiEscort(*this);
|
||||
}
|
||||
|
||||
bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor)
|
||||
{
|
||||
// If AiEscort has ran for as long or longer then the duration specified
|
||||
// and the duration is not infinite, the package is complete.
|
||||
if(mDuration != 0)
|
||||
{
|
||||
MWWorld::TimeStamp current = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
unsigned int currentSecond = ((current.getHour() - int(current.getHour())) * 100);
|
||||
if(currentSecond - mStartingSecond >= mDuration)
|
||||
return true;
|
||||
}
|
||||
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY;
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
const ESM::Pathgrid *pathgrid =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
|
||||
|
||||
|
||||
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
||||
{
|
||||
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiEscort.
|
||||
// FIXME: This *should* pause the AiEscort package instead of terminating it.
|
||||
if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / 2. - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
|
||||
{
|
||||
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiEscort.
|
||||
// FIXME: This *should* pause the AiEscort package instead of terminating it.
|
||||
if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / 2. - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!mPathFinder.isPathConstructed() || cellChange)
|
||||
{
|
||||
cellX = actor.getCell()->mCell->mData.mX;
|
||||
cellY = actor.getCell()->mCell->mData.mY;
|
||||
float xCell = 0;
|
||||
float yCell = 0;
|
||||
if (actor.getCell()->mCell->isExterior())
|
||||
{
|
||||
xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE;
|
||||
yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE;
|
||||
}
|
||||
|
||||
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,pathgrid,xCell,yCell);
|
||||
}
|
||||
|
||||
if(mPathFinder.checkIfNextPointReached(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 float* const leaderPos = actor.getRefData().getPosition().pos;
|
||||
const float* const followerPos = follower.getRefData().getPosition().pos;
|
||||
double differenceBetween[3];
|
||||
|
||||
for (short i = 0; i < 3; ++i)
|
||||
differenceBetween[i] = (leaderPos[i] - followerPos[i]);
|
||||
|
||||
float distanceBetweenResult =
|
||||
(differenceBetween[0] * differenceBetween[0]) + (differenceBetween[1] * differenceBetween[1]) + (differenceBetween[2] * differenceBetween[2]);
|
||||
|
||||
if(distanceBetweenResult <= mMaxDist * mMaxDist)
|
||||
{
|
||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]);
|
||||
MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||
mMaxDist = 470;
|
||||
|
||||
// The CS Help File states that if a duration is givin, the AI package will run for that long
|
||||
// BUT if a location is givin, it "trumps" the duration so it will simply escort to that location.
|
||||
if(mX != 0 || mY != 0 || mZ != 0)
|
||||
mDuration = 0;
|
||||
|
||||
else
|
||||
{
|
||||
MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
AiEscort::AiEscort(const std::string &actorId, const std::string &cellId,int duration, float x, float y, float z)
|
||||
: mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration)
|
||||
{
|
||||
// Stop moving if the player is to far away
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
mMaxDist = 330;
|
||||
mMaxDist = 470;
|
||||
|
||||
// The CS Help File states that if a duration is givin, the AI package will run for that long
|
||||
// BUT if a location is givin, it "trumps" the duration so it will simply escort to that location.
|
||||
if(mX != 0 || mY != 0 || mZ != 0)
|
||||
mDuration = 0;
|
||||
|
||||
else
|
||||
{
|
||||
MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int MWMechanics::AiEscort::getTypeId() const
|
||||
{
|
||||
return 2;
|
||||
|
||||
AiEscort *MWMechanics::AiEscort::clone() const
|
||||
{
|
||||
return new AiEscort(*this);
|
||||
}
|
||||
|
||||
bool AiEscort::execute (const MWWorld::Ptr& actor)
|
||||
{
|
||||
// If AiEscort has ran for as long or longer then the duration specified
|
||||
// and the duration is not infinite, the package is complete.
|
||||
if(mDuration != 0)
|
||||
{
|
||||
MWWorld::TimeStamp current = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
unsigned int currentSecond = ((current.getHour() - int(current.getHour())) * 100);
|
||||
if(currentSecond - mStartingSecond >= mDuration)
|
||||
return true;
|
||||
}
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY;
|
||||
const ESM::Pathgrid *pathgrid =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
|
||||
|
||||
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
||||
{
|
||||
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiEscort.
|
||||
// FIXME: This *should* pause the AiEscort package instead of terminating it.
|
||||
if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE /
|
||||
2.0 - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
|
||||
{
|
||||
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiEscort.
|
||||
// FIXME: This *should* pause the AiEscort package instead of terminating it.
|
||||
if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE /
|
||||
2.0 - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!mPathFinder.isPathConstructed() || cellChange)
|
||||
{
|
||||
cellX = actor.getCell()->mCell->mData.mX;
|
||||
cellY = actor.getCell()->mCell->mData.mY;
|
||||
float xCell = 0;
|
||||
float yCell = 0;
|
||||
if (actor.getCell()->mCell->isExterior())
|
||||
{
|
||||
xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE;
|
||||
yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE;
|
||||
}
|
||||
|
||||
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, pathgrid, xCell, yCell, 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 float* const leaderPos = actor.getRefData().getPosition().pos;
|
||||
const float* const followerPos = follower.getRefData().getPosition().pos;
|
||||
double differenceBetween[3];
|
||||
|
||||
for (short counter = 0; counter < 3; counter++)
|
||||
differenceBetween[counter] = (leaderPos[counter] - followerPos[counter]);
|
||||
|
||||
float distanceBetweenResult =
|
||||
(differenceBetween[0] * differenceBetween[0]) + (differenceBetween[1] * differenceBetween[1]) + (differenceBetween[2] *
|
||||
differenceBetween[2]);
|
||||
|
||||
if(distanceBetweenResult <= mMaxDist * mMaxDist)
|
||||
{
|
||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||
mMaxDist = 470;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stop moving if the player is to far away
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
mMaxDist = 330;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int AiEscort::getTypeId() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,99 +2,106 @@
|
|||
|
||||
#include "movement.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
float sgn(float a)
|
||||
{
|
||||
if(a > 0) return 1.;
|
||||
else return -1.;
|
||||
if(a > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
MWMechanics::AiTravel::AiTravel(float x, float y, float z)
|
||||
: mX(x),mY(y),mZ(z),mPathFinder()
|
||||
namespace MWMechanics
|
||||
{
|
||||
}
|
||||
AiTravel::AiTravel(float x, float y, float z)
|
||||
: mX(x),mY(y),mZ(z),mPathFinder()
|
||||
{
|
||||
}
|
||||
|
||||
MWMechanics::AiTravel *MWMechanics::AiTravel::clone() const
|
||||
{
|
||||
return new AiTravel(*this);
|
||||
}
|
||||
AiTravel *MWMechanics::AiTravel::clone() const
|
||||
{
|
||||
return new AiTravel(*this);
|
||||
}
|
||||
|
||||
bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor)
|
||||
{
|
||||
const ESM::Pathgrid *pathgrid =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
|
||||
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
bool AiTravel::execute (const MWWorld::Ptr& actor)
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY;
|
||||
const ESM::Pathgrid *pathgrid =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
||||
{
|
||||
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
|
||||
//check if actor is near the border of an inactive cell. If so, disable aitravel.
|
||||
if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 200))
|
||||
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
||||
{
|
||||
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
|
||||
//check if actor is near the border of an inactive cell. If so, disable aitravel.
|
||||
if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE /
|
||||
2.0 - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
|
||||
{
|
||||
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
|
||||
//check if actor is near the border of an inactive cell. If so, disable aitravel.
|
||||
if(sideY * (pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE /
|
||||
2.0 - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!mPathFinder.isPathConstructed() || cellChange)
|
||||
{
|
||||
cellX = actor.getCell()->mCell->mData.mX;
|
||||
cellY = actor.getCell()->mCell->mData.mY;
|
||||
float xCell = 0;
|
||||
float yCell = 0;
|
||||
|
||||
if (actor.getCell()->mCell->isExterior())
|
||||
{
|
||||
xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE;
|
||||
yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE;
|
||||
}
|
||||
|
||||
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, pathgrid, xCell, yCell, true);
|
||||
}
|
||||
|
||||
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||
|
||||
return false;
|
||||
}
|
||||
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
|
||||
|
||||
int AiTravel::getTypeId() const
|
||||
{
|
||||
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
|
||||
//check if actor is near the border of an inactive cell. If so, disable aitravel.
|
||||
if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!mPathFinder.isPathConstructed() ||cellChange)
|
||||
{
|
||||
cellX = actor.getCell()->mCell->mData.mX;
|
||||
cellY = actor.getCell()->mCell->mData.mY;
|
||||
float xCell = 0;
|
||||
float yCell = 0;
|
||||
if (actor.getCell()->mCell->isExterior())
|
||||
{
|
||||
xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE;
|
||||
yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE;
|
||||
}
|
||||
|
||||
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,pathgrid,xCell,yCell);
|
||||
}
|
||||
|
||||
if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2]))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]);
|
||||
MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int MWMechanics::AiTravel::getTypeId() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -14,310 +14,324 @@ namespace
|
|||
{
|
||||
float sgn(float a)
|
||||
{
|
||||
if(a > 0) return 1.0;
|
||||
else return -1.0;
|
||||
if(a > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
MWMechanics::AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat):
|
||||
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
|
||||
namespace MWMechanics
|
||||
{
|
||||
for(unsigned short counter = 0; counter < mIdle.size(); counter++)
|
||||
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat):
|
||||
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
|
||||
{
|
||||
if(mIdle[counter] >= 127 || mIdle[counter] < 0)
|
||||
mIdle[counter] = 0;
|
||||
}
|
||||
|
||||
if(mDistance < 0)
|
||||
mDistance = 0;
|
||||
if(mDuration < 0)
|
||||
mDuration = 0;
|
||||
if(mDuration == 0)
|
||||
mTimeOfDay = 0;
|
||||
|
||||
srand(time(NULL));
|
||||
mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
mPlayedIdle = 0;
|
||||
mPathgrid = NULL;
|
||||
mIdleChanceMultiplier =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fIdleChanceMultiplier")->getFloat();
|
||||
|
||||
mStoredAvailableNodes = false;
|
||||
mChooseAction = true;
|
||||
mIdleNow = false;
|
||||
mMoveNow = false;
|
||||
mWalking = false;
|
||||
}
|
||||
|
||||
MWMechanics::AiPackage * MWMechanics::AiWander::clone() const
|
||||
{
|
||||
return new AiWander(*this);
|
||||
}
|
||||
|
||||
bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor)
|
||||
{
|
||||
if(mDuration)
|
||||
{
|
||||
// End package if duration is complete or mid-night hits:
|
||||
MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
if(currentTime.getHour() >= mStartTime.getHour() + mDuration)
|
||||
for(unsigned short counter = 0; counter < mIdle.size(); counter++)
|
||||
{
|
||||
if(!mRepeat)
|
||||
{
|
||||
stopWalking(actor, mPathFinder);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
mStartTime = currentTime;
|
||||
if(mIdle[counter] >= 127 || mIdle[counter] < 0)
|
||||
mIdle[counter] = 0;
|
||||
}
|
||||
else if(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())
|
||||
{
|
||||
if(!mRepeat)
|
||||
{
|
||||
stopWalking(actor, mPathFinder);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
mStartTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
|
||||
if(!mStoredAvailableNodes)
|
||||
{
|
||||
mStoredAvailableNodes = true;
|
||||
mPathgrid =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
|
||||
|
||||
mCellX = actor.getCell()->mCell->mData.mX;
|
||||
mCellY = actor.getCell()->mCell->mData.mY;
|
||||
|
||||
if(!mPathgrid)
|
||||
mDistance = 0;
|
||||
else if(mPathgrid->mPoints.empty())
|
||||
if(mDistance < 0)
|
||||
mDistance = 0;
|
||||
if(mDuration < 0)
|
||||
mDuration = 0;
|
||||
if(mDuration == 0)
|
||||
mTimeOfDay = 0;
|
||||
|
||||
if(mDistance)
|
||||
{
|
||||
mXCell = 0;
|
||||
mYCell = 0;
|
||||
if(actor.getCell()->mCell->isExterior())
|
||||
{
|
||||
mXCell = mCellX * ESM::Land::REAL_SIZE;
|
||||
mYCell = mCellY * ESM::Land::REAL_SIZE;
|
||||
}
|
||||
|
||||
Ogre::Vector3 npcPos(actor.getRefData().getPosition().pos);
|
||||
npcPos[0] = npcPos[0] - mXCell;
|
||||
npcPos[1] = npcPos[1] - mYCell;
|
||||
|
||||
for(unsigned int counter = 0; counter < mPathgrid->mPoints.size(); counter++)
|
||||
{
|
||||
Ogre::Vector3 nodePos(mPathgrid->mPoints[counter].mX, mPathgrid->mPoints[counter].mY, mPathgrid->mPoints[counter].mZ);
|
||||
if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance)
|
||||
mAllowedNodes.push_back(mPathgrid->mPoints[counter]);
|
||||
}
|
||||
if(!mAllowedNodes.empty())
|
||||
{
|
||||
Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ);
|
||||
float closestNode = npcPos.squaredDistance(firstNodePos);
|
||||
unsigned int index = 0;
|
||||
for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++)
|
||||
{
|
||||
Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY, mAllowedNodes[counterThree].mZ);
|
||||
float tempDist = npcPos.squaredDistance(nodePos);
|
||||
if(tempDist < closestNode)
|
||||
index = counterThree;
|
||||
}
|
||||
mCurrentNode = mAllowedNodes[index];
|
||||
mAllowedNodes.erase(mAllowedNodes.begin() + index);
|
||||
}
|
||||
|
||||
if(mAllowedNodes.empty())
|
||||
mDistance = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
bool cellChange = actor.getCell()->mCell->mData.mX != mCellX || actor.getCell()->mCell->mData.mY != mCellY;
|
||||
|
||||
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
||||
{
|
||||
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiWander.
|
||||
// FIXME: This *should* pause the AiWander package instead of terminating it.
|
||||
if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / 2.0 - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
|
||||
{
|
||||
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiWander.
|
||||
// FIXME: This *should* pause the AiWander package instead of terminating it.
|
||||
if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / 2.0 - 200))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles.
|
||||
if(mDistance && (cellChange || (mCellX != actor.getCell()->mCell->mData.mX || mCellY != actor.getCell()->mCell->mData.mY)))
|
||||
mDistance = 0;
|
||||
|
||||
if(mChooseAction)
|
||||
{
|
||||
srand(time(NULL));
|
||||
mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
mPlayedIdle = 0;
|
||||
unsigned short idleRoll = 0;
|
||||
mPathgrid = NULL;
|
||||
mIdleChanceMultiplier =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fIdleChanceMultiplier")->getFloat();
|
||||
|
||||
for(unsigned int counter = 1; counter < mIdle.size(); counter++)
|
||||
mStoredAvailableNodes = false;
|
||||
mChooseAction = true;
|
||||
mIdleNow = false;
|
||||
mMoveNow = false;
|
||||
mWalking = false;
|
||||
}
|
||||
|
||||
AiPackage * MWMechanics::AiWander::clone() const
|
||||
{
|
||||
return new AiWander(*this);
|
||||
}
|
||||
|
||||
bool AiWander::execute (const MWWorld::Ptr& actor)
|
||||
{
|
||||
if(mDuration)
|
||||
{
|
||||
unsigned short idleChance = mIdleChanceMultiplier * mIdle[counter];
|
||||
unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / mIdleChanceMultiplier));
|
||||
if(randSelect < idleChance && randSelect > idleRoll)
|
||||
// End package if duration is complete or mid-night hits:
|
||||
MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
if(currentTime.getHour() >= mStartTime.getHour() + mDuration)
|
||||
{
|
||||
mPlayedIdle = counter;
|
||||
idleRoll = randSelect;
|
||||
if(!mRepeat)
|
||||
{
|
||||
stopWalking(actor);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
mStartTime = currentTime;
|
||||
}
|
||||
else if(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())
|
||||
{
|
||||
if(!mRepeat)
|
||||
{
|
||||
stopWalking(actor);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
mStartTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
if(!mPlayedIdle && mDistance)
|
||||
{
|
||||
mChooseAction = false;
|
||||
mMoveNow = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander:
|
||||
MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
mStartTime = currentTime;
|
||||
playIdle(actor, mPlayedIdle + 1);
|
||||
mChooseAction = false;
|
||||
mIdleNow = true;
|
||||
}
|
||||
}
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
|
||||
if(mIdleNow)
|
||||
{
|
||||
if(!checkIdle(actor, mPlayedIdle + 1))
|
||||
if(!mStoredAvailableNodes)
|
||||
{
|
||||
mStoredAvailableNodes = true;
|
||||
mPathgrid =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
|
||||
|
||||
mCellX = actor.getCell()->mCell->mData.mX;
|
||||
mCellY = actor.getCell()->mCell->mData.mY;
|
||||
|
||||
if(!mPathgrid)
|
||||
mDistance = 0;
|
||||
else if(mPathgrid->mPoints.empty())
|
||||
mDistance = 0;
|
||||
|
||||
if(mDistance)
|
||||
{
|
||||
mXCell = 0;
|
||||
mYCell = 0;
|
||||
if(actor.getCell()->mCell->isExterior())
|
||||
{
|
||||
mXCell = mCellX * ESM::Land::REAL_SIZE;
|
||||
mYCell = mCellY * ESM::Land::REAL_SIZE;
|
||||
}
|
||||
|
||||
Ogre::Vector3 npcPos(actor.getRefData().getPosition().pos);
|
||||
npcPos[0] = npcPos[0] - mXCell;
|
||||
npcPos[1] = npcPos[1] - mYCell;
|
||||
|
||||
for(unsigned int counter = 0; counter < mPathgrid->mPoints.size(); counter++)
|
||||
{
|
||||
Ogre::Vector3 nodePos(mPathgrid->mPoints[counter].mX, mPathgrid->mPoints[counter].mY,
|
||||
mPathgrid->mPoints[counter].mZ);
|
||||
if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance)
|
||||
mAllowedNodes.push_back(mPathgrid->mPoints[counter]);
|
||||
}
|
||||
if(!mAllowedNodes.empty())
|
||||
{
|
||||
Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ);
|
||||
float closestNode = npcPos.squaredDistance(firstNodePos);
|
||||
unsigned int index = 0;
|
||||
for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++)
|
||||
{
|
||||
Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY,
|
||||
mAllowedNodes[counterThree].mZ);
|
||||
float tempDist = npcPos.squaredDistance(nodePos);
|
||||
if(tempDist < closestNode)
|
||||
index = counterThree;
|
||||
}
|
||||
mCurrentNode = mAllowedNodes[index];
|
||||
mAllowedNodes.erase(mAllowedNodes.begin() + index);
|
||||
}
|
||||
|
||||
if(mAllowedNodes.empty())
|
||||
mDistance = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
bool cellChange = actor.getCell()->mCell->mData.mX != mCellX || actor.getCell()->mCell->mData.mY != mCellY;
|
||||
|
||||
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
||||
{
|
||||
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiWander.
|
||||
// FIXME: This *should* pause the AiWander package instead of terminating it.
|
||||
if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE /
|
||||
2.0 - 200))
|
||||
{
|
||||
stopWalking(actor);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
|
||||
{
|
||||
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
|
||||
// Check if actor is near the border of an inactive cell. If so, disable AiWander.
|
||||
// FIXME: This *should* pause the AiWander package instead of terminating it.
|
||||
if(sideY * (pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE /
|
||||
2.0 - 200))
|
||||
{
|
||||
stopWalking(actor);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles.
|
||||
if(mDistance && (cellChange || (mCellX != actor.getCell()->mCell->mData.mX || mCellY != actor.getCell()->mCell->mData.mY)))
|
||||
mDistance = 0;
|
||||
|
||||
if(mChooseAction)
|
||||
{
|
||||
mPlayedIdle = 0;
|
||||
mIdleNow = false;
|
||||
mChooseAction = true;
|
||||
}
|
||||
}
|
||||
unsigned short idleRoll = 0;
|
||||
|
||||
if(mMoveNow && mDistance)
|
||||
{
|
||||
if(!mPathFinder.isPathConstructed())
|
||||
for(unsigned int counter = 1; counter < mIdle.size(); counter++)
|
||||
{
|
||||
unsigned short idleChance = mIdleChanceMultiplier * mIdle[counter];
|
||||
unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / mIdleChanceMultiplier));
|
||||
if(randSelect < idleChance && randSelect > idleRoll)
|
||||
{
|
||||
mPlayedIdle = counter;
|
||||
idleRoll = randSelect;
|
||||
}
|
||||
}
|
||||
|
||||
if(!mPlayedIdle && mDistance)
|
||||
{
|
||||
mChooseAction = false;
|
||||
mMoveNow = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander:
|
||||
MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
mStartTime = currentTime;
|
||||
playIdle(actor, mPlayedIdle + 1);
|
||||
mChooseAction = false;
|
||||
mIdleNow = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(mIdleNow)
|
||||
{
|
||||
unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size());
|
||||
Ogre::Vector3 destNodePos(mAllowedNodes[randNode].mX, mAllowedNodes[randNode].mY, mAllowedNodes[randNode].mZ);
|
||||
|
||||
// Remove this node as an option and add back the previously used node (stops NPC from picking the same node):
|
||||
ESM::Pathgrid::Point temp = mAllowedNodes[randNode];
|
||||
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
||||
mAllowedNodes.push_back(mCurrentNode);
|
||||
mCurrentNode = temp;
|
||||
|
||||
ESM::Pathgrid::Point dest;
|
||||
dest.mX = destNodePos[0] + mXCell;
|
||||
dest.mY = destNodePos[1] + mYCell;
|
||||
dest.mZ = destNodePos[2];
|
||||
|
||||
ESM::Pathgrid::Point start;
|
||||
start.mX = pos.pos[0];
|
||||
start.mY = pos.pos[1];
|
||||
start.mZ = pos.pos[2];
|
||||
|
||||
mPathFinder.buildPath(start,dest,mPathgrid,mXCell,mYCell);
|
||||
mWalking = true;
|
||||
if(!checkIdle(actor, mPlayedIdle + 1))
|
||||
{
|
||||
mPlayedIdle = 0;
|
||||
mIdleNow = false;
|
||||
mChooseAction = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(mWalking)
|
||||
{
|
||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]);
|
||||
MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||
|
||||
// Unclog path nodes by allowing the NPC to be a small distance away from the center. This way two NPCs can be
|
||||
// at the same path node at the same time and both will complete instead of endlessly walking into eachother:
|
||||
Ogre::Vector3 destNodePos(mCurrentNode.mX, mCurrentNode.mY, mCurrentNode.mZ);
|
||||
Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos);
|
||||
actorPos[0] = actorPos[0] - mXCell;
|
||||
actorPos[1] = actorPos[1] - mYCell;
|
||||
float distance = actorPos.squaredDistance(destNodePos);
|
||||
|
||||
if(distance < 1200 || mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2]))
|
||||
if(mMoveNow && mDistance)
|
||||
{
|
||||
stopWalking(actor, mPathFinder);
|
||||
mMoveNow = false;
|
||||
mWalking = false;
|
||||
mChooseAction = true;
|
||||
if(!mPathFinder.isPathConstructed())
|
||||
{
|
||||
unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size());
|
||||
Ogre::Vector3 destNodePos(mAllowedNodes[randNode].mX, mAllowedNodes[randNode].mY, mAllowedNodes[randNode].mZ);
|
||||
|
||||
ESM::Pathgrid::Point dest;
|
||||
dest.mX = destNodePos[0] + mXCell;
|
||||
dest.mY = destNodePos[1] + mYCell;
|
||||
dest.mZ = destNodePos[2];
|
||||
|
||||
ESM::Pathgrid::Point start;
|
||||
start.mX = pos.pos[0];
|
||||
start.mY = pos.pos[1];
|
||||
start.mZ = pos.pos[2];
|
||||
|
||||
mPathFinder.buildPath(start, dest, mPathgrid, mXCell, mYCell, false);
|
||||
|
||||
if(mPathFinder.isPathConstructed())
|
||||
{
|
||||
// Remove this node as an option and add back the previously used node (stops NPC from picking the same node):
|
||||
ESM::Pathgrid::Point temp = mAllowedNodes[randNode];
|
||||
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
||||
mAllowedNodes.push_back(mCurrentNode);
|
||||
mCurrentNode = temp;
|
||||
|
||||
mMoveNow = false;
|
||||
mWalking = true;
|
||||
}
|
||||
// Choose a different node and delete this one from possible nodes because it is uncreachable:
|
||||
else
|
||||
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
if(mWalking)
|
||||
{
|
||||
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle,false);
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||
|
||||
int MWMechanics::AiWander::getTypeId() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// Unclog path nodes by allowing the NPC to be a small distance away from the center. This way two NPCs can be
|
||||
// at the same path node at the same time and both will complete instead of endlessly walking into eachother:
|
||||
Ogre::Vector3 destNodePos(mCurrentNode.mX, mCurrentNode.mY, mCurrentNode.mZ);
|
||||
Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos);
|
||||
actorPos[0] = actorPos[0] - mXCell;
|
||||
actorPos[1] = actorPos[1] - mYCell;
|
||||
float distance = actorPos.squaredDistance(destNodePos);
|
||||
|
||||
void MWMechanics::AiWander::stopWalking(const MWWorld::Ptr& actor, PathFinder& path)
|
||||
{
|
||||
PathFinder pathClearer;
|
||||
path = pathClearer;
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
}
|
||||
if(distance < 1200 || mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
||||
{
|
||||
stopWalking(actor);
|
||||
mMoveNow = false;
|
||||
mWalking = false;
|
||||
mChooseAction = true;
|
||||
}
|
||||
}
|
||||
|
||||
void MWMechanics::AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect)
|
||||
{
|
||||
if(idleSelect == 2)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle2", 0, 1);
|
||||
else if(idleSelect == 3)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1);
|
||||
else if(idleSelect == 4)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle4", 0, 1);
|
||||
else if(idleSelect == 5)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle5", 0, 1);
|
||||
else if(idleSelect == 6)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle6", 0, 1);
|
||||
else if(idleSelect == 7)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle7", 0, 1);
|
||||
else if(idleSelect == 8)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle8", 0, 1);
|
||||
else if(idleSelect == 9)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle9", 0, 1);
|
||||
}
|
||||
|
||||
bool MWMechanics::AiWander::checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect)
|
||||
{
|
||||
if(idleSelect == 2)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle2");
|
||||
else if(idleSelect == 3)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle3");
|
||||
else if(idleSelect == 4)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle4");
|
||||
else if(idleSelect == 5)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle5");
|
||||
else if(idleSelect == 6)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle6");
|
||||
else if(idleSelect == 7)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle7");
|
||||
else if(idleSelect == 8)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle8");
|
||||
else if(idleSelect == 9)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle9");
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
int AiWander::getTypeId() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AiWander::stopWalking(const MWWorld::Ptr& actor)
|
||||
{
|
||||
mPathFinder.clearPath();
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
}
|
||||
|
||||
void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect)
|
||||
{
|
||||
if(idleSelect == 2)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle2", 0, 1);
|
||||
else if(idleSelect == 3)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1);
|
||||
else if(idleSelect == 4)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle4", 0, 1);
|
||||
else if(idleSelect == 5)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle5", 0, 1);
|
||||
else if(idleSelect == 6)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle6", 0, 1);
|
||||
else if(idleSelect == 7)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle7", 0, 1);
|
||||
else if(idleSelect == 8)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle8", 0, 1);
|
||||
else if(idleSelect == 9)
|
||||
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle9", 0, 1);
|
||||
}
|
||||
|
||||
bool AiWander::checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect)
|
||||
{
|
||||
if(idleSelect == 2)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle2");
|
||||
else if(idleSelect == 3)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle3");
|
||||
else if(idleSelect == 4)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle4");
|
||||
else if(idleSelect == 5)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle5");
|
||||
else if(idleSelect == 6)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle6");
|
||||
else if(idleSelect == 7)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle7");
|
||||
else if(idleSelect == 8)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle8");
|
||||
else if(idleSelect == 9)
|
||||
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle9");
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace MWMechanics
|
|||
///< 0: Wander
|
||||
|
||||
private:
|
||||
void stopWalking(const MWWorld::Ptr& actor, PathFinder& path);
|
||||
void stopWalking(const MWWorld::Ptr& actor);
|
||||
void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
|
||||
bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
|
||||
|
||||
|
|
|
@ -3,164 +3,134 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
||||
#include "OgreMath.h"
|
||||
|
||||
#include <boost/graph/dijkstra_shortest_paths.hpp>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include "boost/tuple/tuple.hpp"
|
||||
#include "OgreMath.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
//helpers functions
|
||||
float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z)
|
||||
struct found_path {};
|
||||
|
||||
typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS,
|
||||
boost::property<boost::vertex_index_t, int, ESM::Pathgrid::Point>, boost::property<boost::edge_weight_t, float> >
|
||||
PathGridGraph;
|
||||
typedef boost::property_map<PathGridGraph, boost::edge_weight_t>::type WeightMap;
|
||||
typedef PathGridGraph::vertex_descriptor PointID;
|
||||
typedef PathGridGraph::edge_descriptor PointConnectionID;
|
||||
|
||||
class goalVisited : public boost::default_dijkstra_visitor
|
||||
{
|
||||
return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z));
|
||||
public:
|
||||
goalVisited(PointID goal) {mGoal = goal;};
|
||||
void examine_vertex(PointID u, const PathGridGraph g) {if(u == mGoal) throw found_path();};
|
||||
|
||||
private:
|
||||
PointID mGoal;
|
||||
};
|
||||
|
||||
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)
|
||||
float distance(ESM::Pathgrid::Point point, float x, float y, float z)
|
||||
{
|
||||
return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - 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 distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b)
|
||||
{
|
||||
return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ));
|
||||
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);
|
||||
}
|
||||
|
||||
static float sgn(float a)
|
||||
{
|
||||
if(a>0) return 1.;
|
||||
else return -1.;
|
||||
if(a > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z)
|
||||
int getClosestPoint(const ESM::Pathgrid* grid, float x, float y, float z)
|
||||
{
|
||||
if(!grid) return -1;
|
||||
if(grid->mPoints.empty()) return -1;
|
||||
if(!grid || grid->mPoints.empty())
|
||||
return -1;
|
||||
|
||||
float m = distance(grid->mPoints[0],x,y,z);
|
||||
int i0 = 0;
|
||||
float distanceBetween = distance(grid->mPoints[0], x, y, z);
|
||||
int closestIndex = 0;
|
||||
|
||||
for(unsigned int i=1; i<grid->mPoints.size();++i)
|
||||
for(unsigned int counter = 1; counter < grid->mPoints.size(); counter++)
|
||||
{
|
||||
if(distance(grid->mPoints[i],x,y,z)<m)
|
||||
if(distance(grid->mPoints[counter], x, y, z) < distanceBetween)
|
||||
{
|
||||
m = distance(grid->mPoints[i],x,y,z);
|
||||
i0 = i;
|
||||
distanceBetween = distance(grid->mPoints[counter], x, y, z);
|
||||
closestIndex = counter;
|
||||
}
|
||||
}
|
||||
return i0;
|
||||
|
||||
return closestIndex;
|
||||
}
|
||||
|
||||
typedef boost::adjacency_list<boost::vecS,boost::vecS,boost::undirectedS,
|
||||
boost::property<boost::vertex_index_t,int,ESM::Pathgrid::Point>,boost::property<boost::edge_weight_t,float> > PathGridGraph;
|
||||
typedef boost::property_map<PathGridGraph, boost::edge_weight_t>::type WeightMap;
|
||||
typedef PathGridGraph::vertex_descriptor PointID;
|
||||
typedef PathGridGraph::edge_descriptor PointConnectionID;
|
||||
|
||||
struct found_path {};
|
||||
|
||||
/*class goalVisited : public boost::default_astar_visitor
|
||||
{
|
||||
public:
|
||||
goalVisited(PointID goal) : mGoal(goal) {}
|
||||
|
||||
void examine_vertex(PointID u, const PathGridGraph g)
|
||||
{
|
||||
if(u == mGoal)
|
||||
throw found_path();
|
||||
}
|
||||
private:
|
||||
PointID mGoal;
|
||||
};
|
||||
|
||||
class DistanceHeuristic : public boost::atasr_heuristic <PathGridGraph, float>
|
||||
{
|
||||
public:
|
||||
DistanceHeuristic(const PathGridGraph & l, PointID goal)
|
||||
: mGraph(l), mGoal(goal) {}
|
||||
|
||||
float operator()(PointID u)
|
||||
{
|
||||
const ESM::Pathgrid::Point & U = mGraph[u];
|
||||
const ESM::Pathgrid::Point & V = mGraph[mGoal];
|
||||
float dx = U.mX - V.mX;
|
||||
float dy = U.mY - V.mY;
|
||||
float dz = U.mZ - V.mZ;
|
||||
return sqrt(dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
private:
|
||||
const PathGridGraph & mGraph;
|
||||
PointID mGoal;
|
||||
};*/
|
||||
|
||||
class goalVisited : public boost::default_dijkstra_visitor
|
||||
{
|
||||
public:
|
||||
goalVisited(PointID goal) : mGoal(goal) {}
|
||||
|
||||
void examine_vertex(PointID u, const PathGridGraph g)
|
||||
{
|
||||
if(u == mGoal)
|
||||
throw found_path();
|
||||
}
|
||||
private:
|
||||
PointID mGoal;
|
||||
};
|
||||
|
||||
|
||||
PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0)
|
||||
PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid, float xCell = 0, float yCell = 0)
|
||||
{
|
||||
PathGridGraph graph;
|
||||
|
||||
for(unsigned int i = 0;i<pathgrid->mPoints.size();++i)
|
||||
for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
|
||||
{
|
||||
PointID pID = boost::add_vertex(graph);
|
||||
graph[pID].mX = pathgrid->mPoints[i].mX + xCell;
|
||||
graph[pID].mY = pathgrid->mPoints[i].mY + yCell;
|
||||
graph[pID].mZ = pathgrid->mPoints[i].mZ;
|
||||
graph[pID].mX = pathgrid->mPoints[counter].mX + xCell;
|
||||
graph[pID].mY = pathgrid->mPoints[counter].mY + yCell;
|
||||
graph[pID].mZ = pathgrid->mPoints[counter].mZ;
|
||||
}
|
||||
|
||||
for(unsigned int i = 0;i<pathgrid->mEdges.size();++i)
|
||||
for(unsigned int counterTwo = 0; counterTwo < pathgrid->mEdges.size(); counterTwo++)
|
||||
{
|
||||
PointID u = pathgrid->mEdges[i].mV0;
|
||||
PointID v = pathgrid->mEdges[i].mV1;
|
||||
PointID u = pathgrid->mEdges[counterTwo].mV0;
|
||||
PointID v = pathgrid->mEdges[counterTwo].mV1;
|
||||
|
||||
PointConnectionID edge;
|
||||
bool done;
|
||||
boost::tie(edge,done) = boost::add_edge(u,v,graph);
|
||||
boost::tie(edge, done) = boost::add_edge(u, v, graph);
|
||||
WeightMap weightmap = boost::get(boost::edge_weight, graph);
|
||||
weightmap[edge] = distance(graph[u],graph[v]);
|
||||
|
||||
weightmap[edge] = distance(graph[u], graph[v]);
|
||||
}
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
std::list<ESM::Pathgrid::Point> findPath(PointID start,PointID end,PathGridGraph graph){
|
||||
std::list<ESM::Pathgrid::Point> findPath(PointID start, PointID end, PathGridGraph graph)
|
||||
{
|
||||
std::vector<PointID> p(boost::num_vertices(graph));
|
||||
std::vector<float> d(boost::num_vertices(graph));
|
||||
std::list<ESM::Pathgrid::Point> shortest_path;
|
||||
|
||||
try {
|
||||
boost::dijkstra_shortest_paths
|
||||
(
|
||||
graph,
|
||||
start,
|
||||
boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph))
|
||||
);
|
||||
try
|
||||
{
|
||||
boost::dijkstra_shortest_paths(graph, start,
|
||||
boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end)));
|
||||
}
|
||||
|
||||
} catch(found_path fg) {
|
||||
for(PointID v = end;; v = p[v]) {
|
||||
catch(found_path fg)
|
||||
{
|
||||
for(PointID v = end; ; v = p[v])
|
||||
{
|
||||
shortest_path.push_front(graph[v]);
|
||||
if(p[v] == v)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return shortest_path;
|
||||
}
|
||||
|
||||
//end of helpers functions
|
||||
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
|
@ -170,55 +140,81 @@ namespace MWMechanics
|
|||
mIsPathConstructed = false;
|
||||
}
|
||||
|
||||
void PathFinder::buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint,
|
||||
const ESM::Pathgrid* pathGrid,float xCell,float yCell)
|
||||
void PathFinder::clearPath()
|
||||
{
|
||||
//first check if there is an obstacle
|
||||
if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX,startPoint.mY,startPoint.mZ,
|
||||
endPoint.mX,endPoint.mY,endPoint.mZ) )
|
||||
{
|
||||
int start = getClosestPoint(pathGrid,startPoint.mX - xCell,startPoint.mY - yCell,startPoint.mZ);
|
||||
int end = getClosestPoint(pathGrid,endPoint.mX - xCell,endPoint.mY - yCell,endPoint.mZ);
|
||||
if(!mPath.empty())
|
||||
mPath.clear();
|
||||
mIsPathConstructed = false;
|
||||
}
|
||||
|
||||
if(start != -1 && end != -1)
|
||||
void PathFinder::buildPath(ESM::Pathgrid::Point startPoint, ESM::Pathgrid::Point endPoint,
|
||||
const ESM::Pathgrid* pathGrid, float xCell, float yCell, bool allowShortcuts)
|
||||
{
|
||||
if(allowShortcuts)
|
||||
{
|
||||
if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX, startPoint.mY, startPoint.mZ, endPoint.mX, endPoint.mY,
|
||||
endPoint.mZ))
|
||||
allowShortcuts = false;
|
||||
}
|
||||
|
||||
if(!allowShortcuts)
|
||||
{
|
||||
int startNode = getClosestPoint(pathGrid, startPoint.mX - xCell, startPoint.mY - yCell,startPoint.mZ);
|
||||
int endNode = getClosestPoint(pathGrid, endPoint.mX - xCell, endPoint.mY - yCell, endPoint.mZ);
|
||||
|
||||
if(startNode != -1 && endNode != -1)
|
||||
{
|
||||
PathGridGraph graph = buildGraph(pathGrid,xCell,yCell);
|
||||
mPath = findPath(start,end,graph);
|
||||
PathGridGraph graph = buildGraph(pathGrid, xCell, yCell);
|
||||
mPath = findPath(startNode, endNode, graph);
|
||||
|
||||
if(!mPath.empty())
|
||||
{
|
||||
mPath.push_back(endPoint);
|
||||
mIsPathConstructed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
mPath.push_back(endPoint);
|
||||
mIsPathConstructed = true;
|
||||
}
|
||||
|
||||
float PathFinder::getZAngleToNext(float x,float y,float z)
|
||||
{
|
||||
if(mPath.empty())
|
||||
else
|
||||
{
|
||||
return 0;/// shouldn't happen!
|
||||
mPath.push_back(endPoint);
|
||||
mIsPathConstructed = true;
|
||||
}
|
||||
ESM::Pathgrid::Point nextPoint = *mPath.begin();
|
||||
float dX = nextPoint.mX - x;
|
||||
float dY = nextPoint.mY - y;
|
||||
float h = sqrt(dX*dX+dY*dY);
|
||||
return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees();
|
||||
|
||||
if(mPath.empty())
|
||||
mIsPathConstructed = false;
|
||||
}
|
||||
|
||||
bool PathFinder::checkIfNextPointReached(float x,float y,float z)
|
||||
float PathFinder::getZAngleToNext(float x, float y)
|
||||
{
|
||||
// This should never happen (programmers should have an if statement checking mIsPathConstructed that prevents this call
|
||||
// if otherwise).
|
||||
if(mPath.empty())
|
||||
return 0;
|
||||
|
||||
ESM::Pathgrid::Point nextPoint = *mPath.begin();
|
||||
float directionX = nextPoint.mX - x;
|
||||
float directionY = nextPoint.mY - y;
|
||||
float directionResult = sqrt(directionX * directionX + directionY * directionY);
|
||||
|
||||
return Ogre::Radian(acos(directionY / directionResult) * sgn(asin(directionX / directionResult))).valueDegrees();
|
||||
}
|
||||
|
||||
bool PathFinder::checkPathCompleted(float x, float y, float z)
|
||||
{
|
||||
if(mPath.empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ESM::Pathgrid::Point nextPoint = *mPath.begin();
|
||||
if(distanceZCorrected(nextPoint,x,y,z) < 20)
|
||||
if(distanceZCorrected(nextPoint, x, y, z) < 40)
|
||||
{
|
||||
mPath.pop_front();
|
||||
if(mPath.empty())
|
||||
{
|
||||
mIsPathConstructed = false;
|
||||
return true;
|
||||
}
|
||||
nextPoint = *mPath.begin();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -226,8 +222,10 @@ namespace MWMechanics
|
|||
{
|
||||
return mPath;
|
||||
}
|
||||
|
||||
bool PathFinder::isPathConstructed()
|
||||
{
|
||||
return mIsPathConstructed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,22 +8,24 @@ namespace MWMechanics
|
|||
{
|
||||
class PathFinder
|
||||
{
|
||||
public:
|
||||
PathFinder();
|
||||
public:
|
||||
PathFinder();
|
||||
|
||||
void buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint,
|
||||
const ESM::Pathgrid* pathGrid,float xCell = 0,float yCell = 0);
|
||||
void clearPath();
|
||||
void buildPath(ESM::Pathgrid::Point startPoint, ESM::Pathgrid::Point endPoint,
|
||||
const ESM::Pathgrid* pathGrid, float xCell = 0, float yCell = 0, bool allowShortcuts = 1);
|
||||
|
||||
bool checkIfNextPointReached(float x,float y,float z);//returns true if the last point of the path has been reached.
|
||||
float getZAngleToNext(float x,float y,float z);
|
||||
bool checkPathCompleted(float x, float y, float z);
|
||||
///< \Returns true if the last point of the path has been reached.
|
||||
float getZAngleToNext(float x, float y);
|
||||
|
||||
std::list<ESM::Pathgrid::Point> getPath();
|
||||
bool isPathConstructed();
|
||||
std::list<ESM::Pathgrid::Point> getPath();
|
||||
bool isPathConstructed();
|
||||
|
||||
private:
|
||||
std::list<ESM::Pathgrid::Point> mPath;
|
||||
bool mIsPathConstructed;
|
||||
private:
|
||||
std::list<ESM::Pathgrid::Point> mPath;
|
||||
bool mIsPathConstructed;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -401,29 +401,24 @@ void RenderingManager::setWaterHeight(const float height)
|
|||
|
||||
void RenderingManager::skyEnable ()
|
||||
{
|
||||
if(mSkyManager)
|
||||
mSkyManager->enable();
|
||||
|
||||
mOcclusionQuery->setSunNode(mSkyManager->getSunNode());
|
||||
}
|
||||
|
||||
void RenderingManager::skyDisable ()
|
||||
{
|
||||
if(mSkyManager)
|
||||
mSkyManager->disable();
|
||||
mSkyManager->disable();
|
||||
}
|
||||
|
||||
void RenderingManager::skySetHour (double hour)
|
||||
{
|
||||
if(mSkyManager)
|
||||
mSkyManager->setHour(hour);
|
||||
mSkyManager->setHour(hour);
|
||||
}
|
||||
|
||||
|
||||
void RenderingManager::skySetDate (int day, int month)
|
||||
{
|
||||
if(mSkyManager)
|
||||
mSkyManager->setDate(day, month);
|
||||
mSkyManager->setDate(day, month);
|
||||
}
|
||||
|
||||
int RenderingManager::skyGetMasserPhase() const
|
||||
|
@ -438,8 +433,7 @@ int RenderingManager::skyGetSecundaPhase() const
|
|||
}
|
||||
|
||||
void RenderingManager::skySetMoonColour (bool red){
|
||||
if(mSkyManager)
|
||||
mSkyManager->setMoonColour(red);
|
||||
mSkyManager->setMoonColour(red);
|
||||
}
|
||||
|
||||
bool RenderingManager::toggleRenderMode(int mode)
|
||||
|
|
|
@ -32,9 +32,16 @@ namespace MWRender
|
|||
|
||||
extern "C"
|
||||
{
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libswscale/swscale.h>
|
||||
|
||||
// From libavformat version 55.0.100 and onward the declaration of av_gettime() is removed from libavformat/avformat.h and moved
|
||||
// to libavutil/time.h
|
||||
// https://github.com/FFmpeg/FFmpeg/commit/06a83505992d5f49846c18507a6c3eb8a47c650e
|
||||
#if AV_VERSION_INT(55, 0, 100) <= AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO)
|
||||
#include <libavutil/time.h>
|
||||
#endif
|
||||
}
|
||||
|
||||
#define MAX_AUDIOQ_SIZE (5 * 16 * 1024)
|
||||
|
|
|
@ -32,6 +32,7 @@ Jacob Essex (Yacoby)
|
|||
Jannik Heller (scrawl)
|
||||
Jason Hooks (jhooks)
|
||||
Joel Graff (graffy)
|
||||
John Blomberg (fstp)
|
||||
Jordan Milne
|
||||
Julien Voisin (jvoisin/ap0)
|
||||
Karl-Felix Glatzer (k1ll)
|
||||
|
|
|
@ -2,9 +2,17 @@
|
|||
<ui version="4.0">
|
||||
<class>PlayPage</class>
|
||||
<widget class="QWidget" name="PlayPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>274</width>
|
||||
<height>317</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QFrame" name="Scroll">
|
||||
<widget class="QWidget" name="Scroll" native="true">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">#Scroll {
|
||||
background-image: url(":/images/playpage-background.png");
|
||||
|
@ -13,15 +21,6 @@
|
|||
}
|
||||
</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>30</number>
|
||||
|
|
50
readme.txt
50
readme.txt
|
@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind
|
|||
OpenMW is an attempt at recreating the engine for the popular role-playing game
|
||||
Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work.
|
||||
|
||||
Version: 0.23.0
|
||||
Version: 0.24.0
|
||||
License: GPL (see GPL3.txt for more information)
|
||||
Website: http://www.openmw.org
|
||||
|
||||
|
@ -94,6 +94,54 @@ Allowed options:
|
|||
|
||||
CHANGELOG
|
||||
|
||||
0.24.0
|
||||
|
||||
Bug #284: Book's text misalignment
|
||||
Bug #445: Camera able to get slightly below floor / terrain
|
||||
Bug #582: Seam issue in Red Mountain
|
||||
Bug #632: Journal Next Button shows white square
|
||||
Bug #653: IndexedStore ignores index
|
||||
Bug #694: Parser does not recognize float values starting with .
|
||||
Bug #699: Resource handling broken with Ogre 1.9 trunk
|
||||
Bug #718: components/esm/loadcell is using the mwworld subsystem
|
||||
Bug #729: Levelled item list tries to add nonexistent item
|
||||
Bug #730: Arrow buttons in the settings menu do not work.
|
||||
Bug #732: Erroneous behavior when binding keys
|
||||
Bug #733: Unclickable dialogue topic
|
||||
Bug #734: Book empty line problem
|
||||
Bug #738: OnDeath only works with implicit references
|
||||
Bug #740: Script compiler fails on scripts with special names
|
||||
Bug #742: Wait while no clipping
|
||||
Bug #743: Problem with changeweather console command
|
||||
Bug #744: No wait dialogue after starting a new game
|
||||
Bug #748: Player is not able to unselect objects with the console
|
||||
Bug #751: AddItem should only spawn a message box when called from dialogue
|
||||
Bug #752: The enter button has several functions in trade and looting that is not impelemted.
|
||||
Bug #753: Fargoth's Ring Quest Strange Behavior
|
||||
Bug #755: Launcher writes duplicate lines into settings.cfg
|
||||
Bug #759: Second quest in mages guild does not work
|
||||
Bug #763: Enchantment cast cost is wrong
|
||||
Bug #770: The "Take" and "Close" buttons in the scroll GUI are stretched incorrectly
|
||||
Bug #773: AIWander Isn't Being Passed The Correct idle Values
|
||||
Bug #778: The journal can be opened at the start of a new game
|
||||
Bug #779: Divayth Fyr starts as dead
|
||||
Bug #787: "Batch count" on detailed FPS counter gets cut-off
|
||||
Bug #788: chargen scroll layout does not match vanilla
|
||||
Feature #60: Atlethics Skill
|
||||
Feature #65: Security Skill
|
||||
Feature #74: Interaction with non-load-doors
|
||||
Feature #98: Render Weapon and Shield
|
||||
Feature #102: AI Package: Escort, EscortCell
|
||||
Feature #182: Advanced Journal GUI
|
||||
Feature #288: Trading enhancements
|
||||
Feature #405: Integrate "new game" into the menu
|
||||
Feature #537: Highlight dialogue topic links
|
||||
Feature #658: Rotate, RotateWorld script instructions and local rotations
|
||||
Feature #690: Animation Layering
|
||||
Feature #722: Night Eye/Blind magic effects
|
||||
Feature #735: Move, MoveWorld script instructions.
|
||||
Feature #760: Non-removable corpses
|
||||
|
||||
0.23.0
|
||||
|
||||
Bug #522: Player collides with placeable items
|
||||
|
|
Loading…
Reference in a new issue