mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-18 13:12:50 +00:00
Fixed conflicts
Merge branch 'cs-windows' of https://github.com/Glorf/openmw Conflicts: apps/opencs/model/settings/usersettings.cpp apps/opencs/model/settings/usersettings.hpp apps/opencs/view/settings/usersettingsdialog.cpp
This commit is contained in:
commit
f87eb67968
@ -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}")
|
||||
@ -181,6 +185,12 @@ if (UNIX AND NOT APPLE)
|
||||
find_package (Threads)
|
||||
endif()
|
||||
|
||||
include (CheckIncludeFileCXX)
|
||||
check_include_file_cxx(unordered_map HAVE_UNORDERED_MAP)
|
||||
if (HAVE_UNORDERED_MAP)
|
||||
add_definitions(-DHAVE_UNORDERED_MAP)
|
||||
endif ()
|
||||
|
||||
|
||||
set(BOOST_COMPONENTS system filesystem program_options thread date_time wave)
|
||||
|
||||
|
@ -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
|
||||
|
@ -80,6 +80,7 @@ opencs_units (view/settings
|
||||
usersettingsdialog
|
||||
samplepage
|
||||
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,8 +7,11 @@
|
||||
#include <QMap>
|
||||
#include <QMessageBox>
|
||||
#include <QTextCodec>
|
||||
|
||||
#include <QFile>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
#include "settingcontainer.hpp"
|
||||
@ -32,8 +35,11 @@ namespace boost
|
||||
} /* namespace boost */
|
||||
#endif /* (BOOST_VERSION <= 104600) */
|
||||
|
||||
CSMSettings::UserSettings *CSMSettings::UserSettings::mUserSettingsInstance = 0;
|
||||
|
||||
CSMSettings::UserSettings::UserSettings()
|
||||
{
|
||||
assert(!mUserSettingsInstance);
|
||||
mUserSettingsInstance = this;
|
||||
|
||||
mReadWriteMessage = QObject::tr("<br><b>Could not open or create file for writing</b><br><br> \
|
||||
@ -45,9 +51,18 @@ CSMSettings::UserSettings::UserSettings()
|
||||
|
||||
CSMSettings::UserSettings::~UserSettings()
|
||||
{
|
||||
mUserSettingsInstance = 0;
|
||||
}
|
||||
|
||||
QTextStream *CSMSettings::UserSettings::openFileStream (const QString &filePath, bool isReadOnly)
|
||||
|
||||
//QTextStream *CSMSettings::UserSettings::openFileStream (const QString &filePath, bool isReadOnly)
|
||||
|
||||
CSMSettings::SectionMap CSMSettings::UserSettings::getSettingsMap() const
|
||||
{
|
||||
return mSectionMap;
|
||||
}
|
||||
|
||||
QFile *CSMSettings::UserSettings::openFile (const QString &filename) const
|
||||
{
|
||||
QFile *file = new QFile(filePath);
|
||||
|
||||
@ -91,6 +106,9 @@ QTextStream *CSMSettings::UserSettings::openFileStream (const QString &filePath,
|
||||
}
|
||||
|
||||
bool CSMSettings::UserSettings::writeFile(QMap<QString, CSMSettings::SettingList *> &settings)
|
||||
|
||||
//bool CSMSettings::UserSettings::writeFile(QFile *file, QMap<QString, CSMSettings::SettingList *> &settings) const
|
||||
|
||||
{
|
||||
QTextStream *stream = openFileStream(mPaths.back());
|
||||
|
||||
@ -111,7 +129,11 @@ bool CSMSettings::UserSettings::writeFile(QMap<QString, CSMSettings::SettingList
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const CSMSettings::SectionMap &CSMSettings::UserSettings::getSettings()
|
||||
|
||||
//void CSMSettings::UserSettings::getSettings(QTextStream &stream, SectionMap §ions) const
|
||||
|
||||
{
|
||||
return mSectionSettings;
|
||||
}
|
||||
@ -218,3 +240,70 @@ void CSMSettings::UserSettings::updateSettings (const QString §ionName, cons
|
||||
emit signalUpdateEditorSetting (setting->objectName(), setting->getValue());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -36,13 +36,15 @@ namespace CSMSettings {
|
||||
|
||||
public:
|
||||
|
||||
static UserSettings &instance()
|
||||
{
|
||||
static UserSettings instance;
|
||||
UserSettings();
|
||||
~UserSettings();
|
||||
|
||||
return instance;
|
||||
}
|
||||
static const UserSettings& instance();
|
||||
|
||||
void readSettings();
|
||||
void setSettingsFiles(QStringList files);
|
||||
|
||||
<<<<<<< HEAD
|
||||
bool writeFile(QMap<QString, SettingList *> §ions);
|
||||
const SectionMap &getSettings ();
|
||||
void updateSettings (const QString §ionName, const QString &settingName = "");
|
||||
@ -52,6 +54,21 @@ namespace CSMSettings {
|
||||
|
||||
UserSettings();
|
||||
~UserSettings();
|
||||
=======
|
||||
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:
|
||||
|
||||
static UserSettings *mUserSettingsInstance;
|
||||
|
||||
CSMSettings::SectionMap mSectionMap;
|
||||
QStringList mSettingsFiles;
|
||||
>>>>>>> df1f1bd5c81d94a1ea2693000ec5dc589b069826
|
||||
|
||||
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,10 +9,19 @@
|
||||
#include <QFile>
|
||||
#include <QPushButton>
|
||||
#include <QDockWidget>
|
||||
<<<<<<< HEAD
|
||||
#include <QGridLayout>
|
||||
|
||||
#include "blankpage.hpp"
|
||||
#include "samplepage.hpp"
|
||||
=======
|
||||
#include <QDebug>
|
||||
|
||||
#include "blankpage.hpp"
|
||||
#include "editorpage.hpp"
|
||||
#include "windowpage.hpp"
|
||||
#include "../../model/settings/support.hpp"
|
||||
>>>>>>> df1f1bd5c81d94a1ea2693000ec5dc589b069826
|
||||
|
||||
#include "../../model/settings/support.hpp"
|
||||
#include <boost/filesystem/path.hpp>
|
||||
@ -23,7 +32,11 @@ CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) :
|
||||
{
|
||||
setWindowTitle(QString::fromUtf8 ("User Settings"));
|
||||
buildPages();
|
||||
<<<<<<< HEAD
|
||||
setWidgetStates ();
|
||||
=======
|
||||
setWidgetStates (CSMSettings::UserSettings::instance().getSettingsMap());
|
||||
>>>>>>> df1f1bd5c81d94a1ea2693000ec5dc589b069826
|
||||
positionWindow ();
|
||||
|
||||
connect (mListWidget,
|
||||
@ -85,11 +98,17 @@ void CSVSettings::UserSettingsDialog::buildPages()
|
||||
setDockOptions (QMainWindow::AllowNestedDocks);
|
||||
|
||||
//uncomment to test with sample editor page.
|
||||
<<<<<<< HEAD
|
||||
// TODO: Reimplement sample page using createPage function
|
||||
//createPage<SamplePage>("Sample");
|
||||
createPage<EditorPage>("Editor");
|
||||
=======
|
||||
//createSamplePage();
|
||||
/*createPage<BlankPage>("Page1");
|
||||
>>>>>>> df1f1bd5c81d94a1ea2693000ec5dc589b069826
|
||||
createPage<BlankPage>("Page2");
|
||||
createPage<BlankPage>("Page3");
|
||||
createPage<BlankPage>("Page3");*/
|
||||
createWindowPage();
|
||||
}
|
||||
|
||||
void CSVSettings::UserSettingsDialog::createSamplePage()
|
||||
@ -108,6 +127,22 @@ void CSVSettings::UserSettingsDialog::createSamplePage()
|
||||
new QListWidgetItem (page->objectName(), mListWidget);
|
||||
}
|
||||
|
||||
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 &)));
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
void CSVSettings::UserSettingsDialog::positionWindow ()
|
||||
{
|
||||
QRect scr = QApplication::desktop()->screenGeometry();
|
||||
@ -116,6 +151,8 @@ void CSVSettings::UserSettingsDialog::positionWindow ()
|
||||
|
||||
}
|
||||
|
||||
|
||||
>>>>>>> df1f1bd5c81d94a1ea2693000ec5dc589b069826
|
||||
void CSVSettings::UserSettingsDialog::writeSettings()
|
||||
{
|
||||
QMap<QString, CSMSettings::SettingList *> settings;
|
||||
@ -126,7 +163,13 @@ void CSVSettings::UserSettingsDialog::writeSettings()
|
||||
settings [page->objectName()] = page->getSettings();
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
CSMSettings::UserSettings::instance().writeFile(settings);
|
||||
=======
|
||||
QStringList paths = CSMSettings::UserSettings::instance().getSettingsFiles();
|
||||
|
||||
CSMSettings::UserSettings::instance().writeFile(CSMSettings::UserSettings::instance().openFile(paths.back()), settings);
|
||||
>>>>>>> df1f1bd5c81d94a1ea2693000ec5dc589b069826
|
||||
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,6 @@ namespace CSVSettings {
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QStringList mPaths;
|
||||
QListWidget *mListWidget;
|
||||
QStackedWidget *mStackedWidget;
|
||||
|
||||
@ -42,6 +41,9 @@ namespace CSVSettings {
|
||||
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
|
@ -33,7 +33,7 @@ add_openmw_dir (mwgui
|
||||
enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons
|
||||
merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks
|
||||
keywordsearch itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
|
||||
tradeitemmodel companionitemmodel pickpocketitemmodel
|
||||
tradeitemmodel companionitemmodel pickpocketitemmodel fontloader
|
||||
)
|
||||
|
||||
add_openmw_dir (mwdialogue
|
||||
|
@ -380,7 +380,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||
|
||||
mEnvironment.setWindowManager (new MWGui::WindowManager(
|
||||
mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"),
|
||||
mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage));
|
||||
mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding));
|
||||
if (mNewGame)
|
||||
mEnvironment.getWindowManager()->setNewGame(true);
|
||||
|
||||
|
@ -112,6 +112,8 @@ namespace MWBase
|
||||
virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0;
|
||||
///< Skip the animation for the given MW-reference for one frame. Calls to this function for
|
||||
/// references that are currently not in the scene should be ignored.
|
||||
|
||||
virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -342,6 +342,8 @@ namespace MWBase
|
||||
|
||||
virtual void getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out) = 0;
|
||||
///< get all containers in active cells owned by this Npc
|
||||
virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out) = 0;
|
||||
///< get all items in active cells owned by this Npc
|
||||
|
||||
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0;
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/magiceffects.hpp"
|
||||
#include "../mwmechanics/movement.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
@ -29,6 +30,7 @@ namespace
|
||||
{
|
||||
MWMechanics::CreatureStats mCreatureStats;
|
||||
MWWorld::ContainerStore mContainerStore;
|
||||
MWMechanics::Movement mMovement;
|
||||
|
||||
virtual MWWorld::CustomData *clone() const;
|
||||
};
|
||||
@ -47,6 +49,18 @@ namespace MWClass
|
||||
{
|
||||
std::auto_ptr<CustomData> data (new CustomData);
|
||||
|
||||
static bool inited = false;
|
||||
if(!inited)
|
||||
{
|
||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
|
||||
|
||||
fMinWalkSpeedCreature = gmst.find("fMinWalkSpeedCreature");
|
||||
fMaxWalkSpeedCreature = gmst.find("fMaxWalkSpeedCreature");
|
||||
|
||||
inited = true;
|
||||
}
|
||||
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||
|
||||
// creature stats
|
||||
@ -181,6 +195,42 @@ namespace MWClass
|
||||
return true;
|
||||
}
|
||||
|
||||
float Creature::getSpeed(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
||||
float walkSpeed = fMinWalkSpeedCreature->getFloat() + 0.01 * stats.getAttribute(ESM::Attribute::Speed).getModified()
|
||||
* (fMaxWalkSpeedCreature->getFloat() - fMinWalkSpeedCreature->getFloat());
|
||||
/// \todo what about the rest?
|
||||
return walkSpeed;
|
||||
}
|
||||
|
||||
MWMechanics::Movement& Creature::getMovementSettings (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ensureCustomData (ptr);
|
||||
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mMovement;
|
||||
}
|
||||
|
||||
Ogre::Vector3 Creature::getMovementVector (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
MWMechanics::Movement &movement = getMovementSettings(ptr);
|
||||
Ogre::Vector3 vec(movement.mPosition);
|
||||
movement.mPosition[0] = 0.0f;
|
||||
movement.mPosition[1] = 0.0f;
|
||||
movement.mPosition[2] = 0.0f;
|
||||
return vec;
|
||||
}
|
||||
|
||||
Ogre::Vector3 Creature::getRotationVector (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
MWMechanics::Movement &movement = getMovementSettings(ptr);
|
||||
Ogre::Vector3 vec(movement.mRotation);
|
||||
movement.mRotation[0] = 0.0f;
|
||||
movement.mRotation[1] = 0.0f;
|
||||
movement.mRotation[2] = 0.0f;
|
||||
return vec;
|
||||
}
|
||||
|
||||
MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
@ -249,4 +299,7 @@ namespace MWClass
|
||||
|
||||
return MWWorld::Ptr(&cell.mCreatures.insert(*ref), &cell);
|
||||
}
|
||||
|
||||
const ESM::GameSetting* Creature::fMinWalkSpeedCreature;
|
||||
const ESM::GameSetting* Creature::fMaxWalkSpeedCreature;
|
||||
}
|
||||
|
@ -12,6 +12,9 @@ namespace MWClass
|
||||
virtual MWWorld::Ptr
|
||||
copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const;
|
||||
|
||||
static const ESM::GameSetting *fMinWalkSpeedCreature;
|
||||
static const ESM::GameSetting *fMaxWalkSpeedCreature;
|
||||
|
||||
public:
|
||||
|
||||
virtual std::string getId (const MWWorld::Ptr& ptr) const;
|
||||
@ -66,6 +69,18 @@ namespace MWClass
|
||||
|
||||
virtual bool isPersistent (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const;
|
||||
///< Return desired movement.
|
||||
|
||||
virtual Ogre::Vector3 getMovementVector (const MWWorld::Ptr& ptr) const;
|
||||
///< Return desired movement vector (determined based on movement settings,
|
||||
/// stance and stats).
|
||||
|
||||
virtual Ogre::Vector3 getRotationVector (const MWWorld::Ptr& ptr) const;
|
||||
///< Return desired rotations, as euler angles.
|
||||
|
||||
float getSpeed (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
|
@ -223,6 +223,9 @@ struct TypesetBookImpl::Typesetter : BookTypesetter
|
||||
|
||||
Style * createStyle (char const * fontName, Colour fontColour)
|
||||
{
|
||||
if (strcmp(fontName, "") == 0)
|
||||
return createStyle(MyGUI::FontManager::getInstance().getDefaultFont().c_str(), fontColour);
|
||||
|
||||
for (Styles::iterator i = mBook->mStyles.begin (); i != mBook->mStyles.end (); ++i)
|
||||
if (i->match (fontName, fontColour, fontColour, fontColour, 0))
|
||||
return &*i;
|
||||
@ -405,7 +408,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter
|
||||
while (!stream.eof () && !ucsLineBreak (stream.peek ()) && ucsBreakingSpace (stream.peek ()))
|
||||
{
|
||||
MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ());
|
||||
space_width += gi->advance;
|
||||
if (gi)
|
||||
space_width += gi->advance + gi->bearingX;
|
||||
stream.consume ();
|
||||
}
|
||||
|
||||
@ -414,7 +418,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter
|
||||
while (!stream.eof () && !ucsLineBreak (stream.peek ()) && !ucsBreakingSpace (stream.peek ()))
|
||||
{
|
||||
MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ());
|
||||
word_width += gi->advance + gi->bearingX;
|
||||
if (gi)
|
||||
word_width += gi->advance + gi->bearingX;
|
||||
word_height = line_height;
|
||||
++character_count;
|
||||
stream.consume ();
|
||||
@ -628,6 +633,9 @@ namespace
|
||||
{
|
||||
MyGUI::GlyphInfo* gi = mFont->getGlyphInfo (ch);
|
||||
|
||||
if (!gi)
|
||||
return;
|
||||
|
||||
MyGUI::FloatRect vr;
|
||||
|
||||
vr.left = mCursor.left + gi->bearingX;
|
||||
@ -647,7 +655,8 @@ namespace
|
||||
{
|
||||
MyGUI::GlyphInfo* gi = mFont->getGlyphInfo (ch);
|
||||
|
||||
mCursor.left += gi->bearingX + gi->advance;
|
||||
if (gi)
|
||||
mCursor.left += gi->bearingX + gi->advance;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -3,11 +3,39 @@
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool stacks (const MWWorld::Ptr& left, const MWWorld::Ptr& right)
|
||||
{
|
||||
if (left == right)
|
||||
return true;
|
||||
|
||||
// If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure
|
||||
if (left.getContainerStore() && right.getContainerStore())
|
||||
return left.getContainerStore()->stacks(left, right)
|
||||
&& right.getContainerStore()->stacks(left, right);
|
||||
|
||||
if (left.getContainerStore())
|
||||
return left.getContainerStore()->stacks(left, right);
|
||||
if (right.getContainerStore())
|
||||
return right.getContainerStore()->stacks(left, right);
|
||||
|
||||
MWWorld::ContainerStore store;
|
||||
return store.stacks(left, right);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
ContainerItemModel::ContainerItemModel(const std::vector<MWWorld::Ptr>& itemSources)
|
||||
ContainerItemModel::ContainerItemModel(const std::vector<MWWorld::Ptr>& itemSources, const std::vector<MWWorld::Ptr>& worldItems)
|
||||
: mItemSources(itemSources)
|
||||
, mWorldItems(worldItems)
|
||||
{
|
||||
assert (mItemSources.size());
|
||||
}
|
||||
@ -65,8 +93,7 @@ void ContainerItemModel::removeItem (const ItemStack& item, size_t count)
|
||||
|
||||
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
|
||||
{
|
||||
// If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure
|
||||
if (*it == item.mBase || (store.stacks(*it, item.mBase) && item.mBase.getContainerStore()->stacks(*it, item.mBase)))
|
||||
if (stacks(*it, item.mBase))
|
||||
{
|
||||
int refCount = it->getRefData().getCount();
|
||||
it->getRefData().setCount(std::max(0, refCount - toRemove));
|
||||
@ -76,6 +103,21 @@ void ContainerItemModel::removeItem (const ItemStack& item, size_t count)
|
||||
}
|
||||
}
|
||||
}
|
||||
for (std::vector<MWWorld::Ptr>::iterator source = mWorldItems.begin(); source != mWorldItems.end(); ++source)
|
||||
{
|
||||
if (stacks(*source, item.mBase))
|
||||
{
|
||||
int refCount = source->getRefData().getCount();
|
||||
if (refCount - toRemove <= 0)
|
||||
MWBase::Environment::get().getWorld()->deleteObject(*source);
|
||||
else
|
||||
source->getRefData().setCount(std::max(0, refCount - toRemove));
|
||||
toRemove -= refCount;
|
||||
if (toRemove <= 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error("Not enough items to remove could be found");
|
||||
}
|
||||
|
||||
@ -91,8 +133,7 @@ void ContainerItemModel::update()
|
||||
std::vector<ItemStack>::iterator itemStack = mItems.begin();
|
||||
for (; itemStack != mItems.end(); ++itemStack)
|
||||
{
|
||||
// If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure
|
||||
if (store.stacks(itemStack->mBase, *it) && it->getContainerStore()->stacks(itemStack->mBase, *it))
|
||||
if (stacks(*it, itemStack->mBase))
|
||||
{
|
||||
// we already have an item stack of this kind, add to it
|
||||
itemStack->mCount += it->getRefData().getCount();
|
||||
@ -108,6 +149,26 @@ void ContainerItemModel::update()
|
||||
}
|
||||
}
|
||||
}
|
||||
for (std::vector<MWWorld::Ptr>::iterator source = mWorldItems.begin(); source != mWorldItems.end(); ++source)
|
||||
{
|
||||
std::vector<ItemStack>::iterator itemStack = mItems.begin();
|
||||
for (; itemStack != mItems.end(); ++itemStack)
|
||||
{
|
||||
if (stacks(*source, itemStack->mBase))
|
||||
{
|
||||
// we already have an item stack of this kind, add to it
|
||||
itemStack->mCount += source->getRefData().getCount();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (itemStack == mItems.end())
|
||||
{
|
||||
// no stack yet, create one
|
||||
ItemStack newItem (*source, this, source->getRefData().getCount());
|
||||
mItems.push_back(newItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ namespace MWGui
|
||||
class ContainerItemModel : public ItemModel
|
||||
{
|
||||
public:
|
||||
ContainerItemModel (const std::vector<MWWorld::Ptr>& itemSources);
|
||||
ContainerItemModel (const std::vector<MWWorld::Ptr>& itemSources, const std::vector<MWWorld::Ptr>& worldItems);
|
||||
///< @note The order of elements \a itemSources matters here. The first element has the highest priority for removal,
|
||||
/// while the last element will be used to add new items to.
|
||||
|
||||
@ -28,6 +28,7 @@ namespace MWGui
|
||||
|
||||
private:
|
||||
std::vector<MWWorld::Ptr> mItemSources;
|
||||
std::vector<MWWorld::Ptr> mWorldItems;
|
||||
|
||||
std::vector<ItemStack> mItems;
|
||||
};
|
||||
|
@ -115,7 +115,7 @@ namespace MWGui
|
||||
|
||||
void Response::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map<std::string, Link*>& topicLinks) const
|
||||
{
|
||||
BookTypesetter::Style* title = typesetter->createStyle("EB Garamond", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f));
|
||||
BookTypesetter::Style* title = typesetter->createStyle("", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f));
|
||||
typesetter->sectionBreak(9);
|
||||
if (mTitle != "")
|
||||
typesetter->write(title, to_utf8_span(mTitle.c_str()));
|
||||
@ -159,7 +159,7 @@ namespace MWGui
|
||||
|
||||
if (hyperLinks.size() && MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation())
|
||||
{
|
||||
BookTypesetter::Style* style = typesetter->createStyle("EB Garamond", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f));
|
||||
BookTypesetter::Style* style = typesetter->createStyle("", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f));
|
||||
size_t formatted = 0; // points to the first character that is not laid out yet
|
||||
for (std::map<Range, intptr_t>::iterator it = hyperLinks.begin(); it != hyperLinks.end(); ++it)
|
||||
{
|
||||
@ -197,7 +197,7 @@ namespace MWGui
|
||||
|
||||
void Response::addTopicLink(BookTypesetter::Ptr typesetter, intptr_t topicId, size_t begin, size_t end) const
|
||||
{
|
||||
BookTypesetter::Style* style = typesetter->createStyle("EB Garamond", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f));
|
||||
BookTypesetter::Style* style = typesetter->createStyle("", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f));
|
||||
|
||||
const MyGUI::Colour linkHot (143/255.f, 155/255.f, 218/255.f);
|
||||
const MyGUI::Colour linkNormal (112/255.f, 126/255.f, 207/255.f);
|
||||
@ -215,7 +215,7 @@ namespace MWGui
|
||||
|
||||
void Message::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map<std::string, Link*>& topicLinks) const
|
||||
{
|
||||
BookTypesetter::Style* title = typesetter->createStyle("EB Garamond", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f));
|
||||
BookTypesetter::Style* title = typesetter->createStyle("", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f));
|
||||
typesetter->sectionBreak(9);
|
||||
typesetter->write(title, to_utf8_span(mText.c_str()));
|
||||
}
|
||||
@ -465,7 +465,7 @@ namespace MWGui
|
||||
(*it)->write(typesetter, &mKeywordSearch, mTopicLinks);
|
||||
|
||||
|
||||
BookTypesetter::Style* body = typesetter->createStyle("EB Garamond", MyGUI::Colour::White);
|
||||
BookTypesetter::Style* body = typesetter->createStyle("", MyGUI::Colour::White);
|
||||
|
||||
// choices
|
||||
const MyGUI::Colour linkHot (223/255.f, 201/255.f, 159/255.f);
|
||||
|
@ -61,30 +61,32 @@ namespace MWGui
|
||||
void EnchantingDialog::updateLabels()
|
||||
{
|
||||
std::stringstream enchantCost;
|
||||
enchantCost << std::setprecision(1) << std::fixed << mEnchanting.getEnchantCost();
|
||||
enchantCost << std::setprecision(1) << std::fixed << mEnchanting.getEnchantPoints();
|
||||
mEnchantmentPoints->setCaption(enchantCost.str() + " / " + boost::lexical_cast<std::string>(mEnchanting.getMaxEnchantValue()));
|
||||
|
||||
mCharge->setCaption(boost::lexical_cast<std::string>(mEnchanting.getGemCharge()));
|
||||
|
||||
mCastCost->setCaption(boost::lexical_cast<std::string>(mEnchanting.getEnchantCost()));
|
||||
std::stringstream castCost;
|
||||
castCost << std::setprecision(1) << std::fixed << mEnchanting.getCastCost();
|
||||
mCastCost->setCaption(boost::lexical_cast<std::string>(castCost.str()));
|
||||
|
||||
mPrice->setCaption(boost::lexical_cast<std::string>(mEnchanting.getEnchantPrice()));
|
||||
|
||||
switch(mEnchanting.getEnchantType())
|
||||
switch(mEnchanting.getCastStyle())
|
||||
{
|
||||
case 0:
|
||||
case ESM::Enchantment::CastOnce:
|
||||
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastOnce","Cast Once"));
|
||||
mAddEffectDialog.constantEffect=false;
|
||||
break;
|
||||
case 1:
|
||||
case ESM::Enchantment::WhenStrikes:
|
||||
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenStrikes", "When Strikes"));
|
||||
mAddEffectDialog.constantEffect=false;
|
||||
break;
|
||||
case 2:
|
||||
case ESM::Enchantment::WhenUsed:
|
||||
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenUsed", "When Used"));
|
||||
mAddEffectDialog.constantEffect=false;
|
||||
break;
|
||||
case 3:
|
||||
case ESM::Enchantment::ConstantEffect:
|
||||
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastConstant", "Cast Constant"));
|
||||
mAddEffectDialog.constantEffect=true;
|
||||
break;
|
||||
@ -169,7 +171,7 @@ namespace MWGui
|
||||
image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveItem);
|
||||
|
||||
mEnchanting.setOldItem(item);
|
||||
mEnchanting.nextEnchantType();
|
||||
mEnchanting.nextCastStyle();
|
||||
updateLabels();
|
||||
}
|
||||
|
||||
@ -248,7 +250,7 @@ namespace MWGui
|
||||
|
||||
void EnchantingDialog::onTypeButtonClicked(MyGUI::Widget* sender)
|
||||
{
|
||||
mEnchanting.nextEnchantType();
|
||||
mEnchanting.nextCastStyle();
|
||||
updateLabels();
|
||||
}
|
||||
|
||||
@ -278,7 +280,7 @@ namespace MWGui
|
||||
return;
|
||||
}
|
||||
|
||||
if (mEnchanting.getEnchantCost() > mEnchanting.getMaxEnchantValue())
|
||||
if (mEnchanting.getEnchantPoints() > mEnchanting.getMaxEnchantValue())
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage29}");
|
||||
return;
|
||||
|
238
apps/openmw/mwgui/fontloader.cpp
Normal file
238
apps/openmw/mwgui/fontloader.cpp
Normal file
@ -0,0 +1,238 @@
|
||||
#include "fontloader.hpp"
|
||||
|
||||
#include <OgreResourceGroupManager.h>
|
||||
#include <OgreTextureManager.h>
|
||||
|
||||
#include <MyGUI_ResourceManager.h>
|
||||
#include <MyGUI_FontManager.h>
|
||||
#include <MyGUI_ResourceManualFont.h>
|
||||
#include <MyGUI_XmlDocument.h>
|
||||
#include <MyGUI_FactoryManager.h>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
unsigned long utf8ToUnicode(const std::string& utf8)
|
||||
{
|
||||
size_t i = 0;
|
||||
unsigned long unicode;
|
||||
size_t todo;
|
||||
unsigned char ch = utf8[i++];
|
||||
if (ch <= 0x7F)
|
||||
{
|
||||
unicode = ch;
|
||||
todo = 0;
|
||||
}
|
||||
else if (ch <= 0xBF)
|
||||
{
|
||||
throw std::logic_error("not a UTF-8 string");
|
||||
}
|
||||
else if (ch <= 0xDF)
|
||||
{
|
||||
unicode = ch&0x1F;
|
||||
todo = 1;
|
||||
}
|
||||
else if (ch <= 0xEF)
|
||||
{
|
||||
unicode = ch&0x0F;
|
||||
todo = 2;
|
||||
}
|
||||
else if (ch <= 0xF7)
|
||||
{
|
||||
unicode = ch&0x07;
|
||||
todo = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::logic_error("not a UTF-8 string");
|
||||
}
|
||||
for (size_t j = 0; j < todo; ++j)
|
||||
{
|
||||
unsigned char ch = utf8[i++];
|
||||
if (ch < 0x80 || ch > 0xBF)
|
||||
throw std::logic_error("not a UTF-8 string");
|
||||
unicode <<= 6;
|
||||
unicode += ch & 0x3F;
|
||||
}
|
||||
if (unicode >= 0xD800 && unicode <= 0xDFFF)
|
||||
throw std::logic_error("not a UTF-8 string");
|
||||
if (unicode > 0x10FFFF)
|
||||
throw std::logic_error("not a UTF-8 string");
|
||||
|
||||
return unicode;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
FontLoader::FontLoader(ToUTF8::FromType encoding)
|
||||
{
|
||||
if (encoding == ToUTF8::WINDOWS_1252)
|
||||
mEncoding = ToUTF8::CP437;
|
||||
else
|
||||
mEncoding = encoding;
|
||||
}
|
||||
|
||||
void FontLoader::loadAllFonts()
|
||||
{
|
||||
Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups ();
|
||||
for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it)
|
||||
{
|
||||
Ogre::StringVectorPtr resourcesInThisGroup = Ogre::ResourceGroupManager::getSingleton ().findResourceNames (*it, "*.fnt");
|
||||
for (Ogre::StringVector::iterator resource = resourcesInThisGroup->begin(); resource != resourcesInThisGroup->end(); ++resource)
|
||||
{
|
||||
loadFont(*resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
} Point;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float u1; // appears unused, always 0
|
||||
Point top_left;
|
||||
Point top_right;
|
||||
Point bottom_left;
|
||||
Point bottom_right;
|
||||
float width;
|
||||
float height;
|
||||
float u2; // appears unused, always 0
|
||||
float kerning;
|
||||
float ascent;
|
||||
} GlyphInfo;
|
||||
|
||||
void FontLoader::loadFont(const std::string &fileName)
|
||||
{
|
||||
Ogre::DataStreamPtr file = Ogre::ResourceGroupManager::getSingleton().openResource(fileName);
|
||||
|
||||
float fontSize;
|
||||
int one;
|
||||
file->read(&fontSize, sizeof(fontSize));
|
||||
|
||||
file->read(&one, sizeof(int));
|
||||
assert(one == 1);
|
||||
file->read(&one, sizeof(int));
|
||||
assert(one == 1);
|
||||
|
||||
char name_[284];
|
||||
file->read(name_, sizeof(name_));
|
||||
std::string name(name_);
|
||||
|
||||
GlyphInfo data[256];
|
||||
file->read(data, sizeof(data));
|
||||
file->close();
|
||||
|
||||
// Create the font texture
|
||||
std::string bitmapFilename = "Fonts/" + std::string(name) + ".tex";
|
||||
Ogre::DataStreamPtr bitmapFile = Ogre::ResourceGroupManager::getSingleton().openResource(bitmapFilename);
|
||||
|
||||
int width, height;
|
||||
bitmapFile->read(&width, sizeof(int));
|
||||
bitmapFile->read(&height, sizeof(int));
|
||||
|
||||
std::vector<Ogre::uchar> textureData;
|
||||
textureData.resize(width*height*4);
|
||||
bitmapFile->read(&textureData[0], width*height*4);
|
||||
bitmapFile->close();
|
||||
|
||||
std::string textureName = name;
|
||||
Ogre::Image image;
|
||||
image.loadDynamicImage(&textureData[0], width, height, Ogre::PF_BYTE_RGBA);
|
||||
Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual(textureName,
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
Ogre::TEX_TYPE_2D,
|
||||
width, height, 0, Ogre::PF_BYTE_RGBA);
|
||||
texture->loadImage(image);
|
||||
|
||||
// Register the font with MyGUI
|
||||
MyGUI::ResourceManualFont* font = static_cast<MyGUI::ResourceManualFont*>(
|
||||
MyGUI::FactoryManager::getInstance().createObject("Resource", "ResourceManualFont"));
|
||||
// We need to emulate loading from XML because the data members are private as of mygui 3.2.0
|
||||
MyGUI::xml::Document xmlDocument;
|
||||
MyGUI::xml::ElementPtr root = xmlDocument.createRoot("ResourceManualFont");
|
||||
|
||||
if (name.size() >= 5 && Misc::StringUtils::ciEqual(name.substr(0, 5), "magic"))
|
||||
root->addAttribute("name", "Magic Cards");
|
||||
else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "century"))
|
||||
root->addAttribute("name", "Century Gothic");
|
||||
else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "daedric"))
|
||||
root->addAttribute("name", "Daedric");
|
||||
else
|
||||
return; // no point in loading it, since there is no way of using additional fonts
|
||||
|
||||
MyGUI::xml::ElementPtr defaultHeight = root->createChild("Property");
|
||||
defaultHeight->addAttribute("key", "DefaultHeight");
|
||||
defaultHeight->addAttribute("value", fontSize);
|
||||
MyGUI::xml::ElementPtr source = root->createChild("Property");
|
||||
source->addAttribute("key", "Source");
|
||||
source->addAttribute("value", std::string(textureName));
|
||||
MyGUI::xml::ElementPtr codes = root->createChild("Codes");
|
||||
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
int x1 = data[i].top_left.x*width;
|
||||
int y1 = data[i].top_left.y*height;
|
||||
int w = data[i].top_right.x*width - x1;
|
||||
int h = data[i].bottom_left.y*height - y1;
|
||||
|
||||
ToUTF8::Utf8Encoder encoder(mEncoding);
|
||||
unsigned long unicodeVal = utf8ToUnicode(encoder.getUtf8(std::string(1, (unsigned char)(i))));
|
||||
|
||||
MyGUI::xml::ElementPtr code = codes->createChild("Code");
|
||||
code->addAttribute("index", unicodeVal);
|
||||
code->addAttribute("coord", MyGUI::utility::toString(x1) + " "
|
||||
+ MyGUI::utility::toString(y1) + " "
|
||||
+ MyGUI::utility::toString(w) + " "
|
||||
+ MyGUI::utility::toString(h));
|
||||
code->addAttribute("advance", data[i].width);
|
||||
code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " "
|
||||
+ MyGUI::utility::toString((fontSize-data[i].ascent)));
|
||||
|
||||
// ASCII vertical bar, use this as text input cursor
|
||||
if (i == 124)
|
||||
{
|
||||
MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code");
|
||||
cursorCode->addAttribute("index", MyGUI::FontCodeType::Cursor);
|
||||
cursorCode->addAttribute("coord", MyGUI::utility::toString(x1) + " "
|
||||
+ MyGUI::utility::toString(y1) + " "
|
||||
+ MyGUI::utility::toString(w) + " "
|
||||
+ MyGUI::utility::toString(h));
|
||||
cursorCode->addAttribute("advance", data[i].width);
|
||||
cursorCode->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " "
|
||||
+ MyGUI::utility::toString((fontSize-data[i].ascent)));
|
||||
}
|
||||
}
|
||||
|
||||
// These are required as well, but the fonts don't provide them
|
||||
for (int i=0; i<3; ++i)
|
||||
{
|
||||
MyGUI::FontCodeType::Enum type;
|
||||
if(i == 0)
|
||||
type = MyGUI::FontCodeType::Selected;
|
||||
else if (i == 1)
|
||||
type = MyGUI::FontCodeType::SelectedBack;
|
||||
else if (i == 2)
|
||||
type = MyGUI::FontCodeType::NotDefined;
|
||||
|
||||
MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code");
|
||||
cursorCode->addAttribute("index", type);
|
||||
cursorCode->addAttribute("coord", "0 0 0 0");
|
||||
cursorCode->addAttribute("advance", "0");
|
||||
cursorCode->addAttribute("bearing", "0 0");
|
||||
|
||||
}
|
||||
|
||||
font->deserialization(root, MyGUI::Version(3,2,0));
|
||||
|
||||
MyGUI::ResourceManager::getInstance().addResource(font);
|
||||
}
|
||||
|
||||
}
|
25
apps/openmw/mwgui/fontloader.hpp
Normal file
25
apps/openmw/mwgui/fontloader.hpp
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef MWGUI_FONTLOADER_H
|
||||
#define MWGUI_FONTLOADER_H
|
||||
|
||||
#include <components/to_utf8/to_utf8.hpp>
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
|
||||
/// @brief loads Morrowind's .fnt/.tex fonts for use with MyGUI and Ogre
|
||||
class FontLoader
|
||||
{
|
||||
public:
|
||||
FontLoader (ToUTF8::FromType encoding);
|
||||
void loadAllFonts ();
|
||||
|
||||
private:
|
||||
ToUTF8::FromType mEncoding;
|
||||
|
||||
void loadFont (const std::string& fileName);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -202,14 +202,14 @@ namespace MWGui
|
||||
|
||||
float BookTextParser::widthForCharGlyph(unsigned unicodeChar) const
|
||||
{
|
||||
std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont);
|
||||
std::string fontName(mTextStyle.mFont == "Default" ? MyGUI::FontManager::getInstance().getDefaultFont() : mTextStyle.mFont);
|
||||
return MyGUI::FontManager::getInstance().getByName(fontName)
|
||||
->getGlyphInfo(unicodeChar)->width;
|
||||
}
|
||||
|
||||
float BookTextParser::currentFontHeight() const
|
||||
{
|
||||
std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont);
|
||||
std::string fontName(mTextStyle.mFont == "Default" ? MyGUI::FontManager::getInstance().getDefaultFont() : mTextStyle.mFont);
|
||||
return MyGUI::FontManager::getInstance().getByName(fontName)->getDefaultHeight();
|
||||
}
|
||||
|
||||
@ -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 "
|
||||
|
@ -13,8 +13,6 @@ namespace MWGui
|
||||
, mType(Type_Normal)
|
||||
, mBase(base)
|
||||
{
|
||||
assert(base.getContainerStore());
|
||||
|
||||
if (MWWorld::Class::get(base).getEnchantment(base) != "")
|
||||
mFlags |= Flag_Enchanted;
|
||||
}
|
||||
@ -31,18 +29,42 @@ namespace MWGui
|
||||
{
|
||||
if(mBase == other.mBase)
|
||||
return true;
|
||||
return mBase.getContainerStore()->stacks(mBase, other.mBase)
|
||||
&& other.mBase.getContainerStore()->stacks(mBase, other.mBase);
|
||||
|
||||
// If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure
|
||||
if (mBase.getContainerStore() && other.mBase.getContainerStore())
|
||||
return mBase.getContainerStore()->stacks(mBase, other.mBase)
|
||||
&& other.mBase.getContainerStore()->stacks(mBase, other.mBase);
|
||||
|
||||
if (mBase.getContainerStore())
|
||||
return mBase.getContainerStore()->stacks(mBase, other.mBase);
|
||||
if (other.mBase.getContainerStore())
|
||||
return other.mBase.getContainerStore()->stacks(mBase, other.mBase);
|
||||
|
||||
MWWorld::ContainerStore store;
|
||||
return store.stacks(mBase, other.mBase);
|
||||
|
||||
}
|
||||
|
||||
bool operator == (const ItemStack& left, const ItemStack& right)
|
||||
{
|
||||
if (left.mType != right.mType)
|
||||
return false;
|
||||
|
||||
if(left.mBase == right.mBase)
|
||||
return true;
|
||||
return left.mBase.getContainerStore()->stacks(left.mBase, right.mBase)
|
||||
&& right.mBase.getContainerStore()->stacks(left.mBase, right.mBase);
|
||||
|
||||
// If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure
|
||||
if (left.mBase.getContainerStore() && right.mBase.getContainerStore())
|
||||
return left.mBase.getContainerStore()->stacks(left.mBase, right.mBase)
|
||||
&& right.mBase.getContainerStore()->stacks(left.mBase, right.mBase);
|
||||
|
||||
if (left.mBase.getContainerStore())
|
||||
return left.mBase.getContainerStore()->stacks(left.mBase, right.mBase);
|
||||
if (right.mBase.getContainerStore())
|
||||
return right.mBase.getContainerStore()->stacks(left.mBase, right.mBase);
|
||||
|
||||
MWWorld::ContainerStore store;
|
||||
return store.stacks(left.mBase, right.mBase);
|
||||
}
|
||||
|
||||
ItemModel::ItemModel()
|
||||
|
@ -189,14 +189,14 @@ book JournalBooks::createEmptyJournalBook ()
|
||||
{
|
||||
BookTypesetter::Ptr typesetter = createTypesetter ();
|
||||
|
||||
BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f));
|
||||
BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
|
||||
BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f));
|
||||
BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black);
|
||||
|
||||
typesetter->write (header, to_utf8_span ("You have no journal entries!"));
|
||||
typesetter->lineBreak ();
|
||||
typesetter->write (body, to_utf8_span ("You should have gone though the starting quest and got an initial quest."));
|
||||
|
||||
BookTypesetter::Style* big = typesetter->createStyle ("EB Garamond 24", MyGUI::Colour::Black);
|
||||
BookTypesetter::Style* big = typesetter->createStyle ("", MyGUI::Colour::Black);
|
||||
BookTypesetter::Style* test = typesetter->createStyle ("MonoFont", MyGUI::Colour::Blue);
|
||||
|
||||
typesetter->sectionBreak (20);
|
||||
@ -231,8 +231,8 @@ book JournalBooks::createJournalBook ()
|
||||
{
|
||||
BookTypesetter::Ptr typesetter = createTypesetter ();
|
||||
|
||||
BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f));
|
||||
BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
|
||||
BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f));
|
||||
BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black);
|
||||
|
||||
mModel->visitJournalEntries (0, AddJournalEntry (typesetter, body, header, true));
|
||||
|
||||
@ -243,8 +243,8 @@ book JournalBooks::createTopicBook (uintptr_t topicId)
|
||||
{
|
||||
BookTypesetter::Ptr typesetter = createTypesetter ();
|
||||
|
||||
BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f));
|
||||
BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
|
||||
BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f));
|
||||
BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black);
|
||||
|
||||
mModel->visitTopicName (topicId, AddTopicName (typesetter, header));
|
||||
|
||||
@ -259,8 +259,8 @@ book JournalBooks::createQuestBook (uintptr_t questId)
|
||||
{
|
||||
BookTypesetter::Ptr typesetter = createTypesetter ();
|
||||
|
||||
BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f));
|
||||
BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
|
||||
BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f));
|
||||
BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black);
|
||||
|
||||
mModel->visitQuestName (questId, AddQuestName (typesetter, header));
|
||||
|
||||
@ -275,7 +275,7 @@ book JournalBooks::createTopicIndexBook ()
|
||||
|
||||
typesetter->setSectionAlignment (BookTypesetter::AlignCenter);
|
||||
|
||||
BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
|
||||
BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black);
|
||||
|
||||
for (int i = 0; i < 26; ++i)
|
||||
{
|
||||
@ -300,7 +300,7 @@ book JournalBooks::createTopicIndexBook ()
|
||||
book JournalBooks::createTopicIndexBook (char character)
|
||||
{
|
||||
BookTypesetter::Ptr typesetter = BookTypesetter::create (0x7FFFFFFF, 0x7FFFFFFF);
|
||||
BookTypesetter::Style* style = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
|
||||
BookTypesetter::Style* style = typesetter->createStyle ("", MyGUI::Colour::Black);
|
||||
|
||||
mModel->visitTopicNamesStartingWith (character, AddTopicLink (typesetter, style));
|
||||
|
||||
@ -310,7 +310,7 @@ book JournalBooks::createTopicIndexBook (char character)
|
||||
book JournalBooks::createQuestIndexBook (bool activeOnly)
|
||||
{
|
||||
BookTypesetter::Ptr typesetter = BookTypesetter::create (0x7FFFFFFF, 0x7FFFFFFF);
|
||||
BookTypesetter::Style* base = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
|
||||
BookTypesetter::Style* base = typesetter->createStyle ("", MyGUI::Colour::Black);
|
||||
|
||||
mModel->visitQuestNames (activeOnly, AddQuestLink (typesetter, base));
|
||||
|
||||
|
@ -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);
|
||||
|
@ -71,7 +71,7 @@ namespace MWGui
|
||||
if (item.mType == ItemStack::Type_Equipped && !mShowEquipped)
|
||||
return false;
|
||||
|
||||
int category;
|
||||
int category = 0;
|
||||
if (base.getTypeName() == typeid(ESM::Armor).name()
|
||||
|| base.getTypeName() == typeid(ESM::Clothing).name())
|
||||
category = Category_Apparel;
|
||||
@ -106,6 +106,7 @@ namespace MWGui
|
||||
if ((mFilter & Filter_OnlyEnchantable) && (item.mFlags & ItemStack::Flag_Enchanted
|
||||
|| (base.getTypeName() != typeid(ESM::Armor).name()
|
||||
&& base.getTypeName() != typeid(ESM::Clothing).name()
|
||||
&& base.getTypeName() != typeid(ESM::Weapon).name()
|
||||
&& base.getTypeName() != typeid(ESM::Book).name())))
|
||||
return false;
|
||||
if ((mFilter & Filter_OnlyEnchantable) && base.getTypeName() == typeid(ESM::Book).name()
|
||||
|
@ -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
|
||||
|
@ -88,8 +88,10 @@ namespace MWGui
|
||||
MWBase::Environment::get().getWorld()->getContainersOwnedBy(actor, itemSources);
|
||||
// Important: actor goes last, so that items purchased by the merchant go into his inventory
|
||||
itemSources.push_back(actor);
|
||||
std::vector<MWWorld::Ptr> worldItems;
|
||||
MWBase::Environment::get().getWorld()->getItemsOwnedBy(actor, worldItems);
|
||||
|
||||
mTradeModel = new TradeItemModel(new ContainerItemModel(itemSources), mPtr);
|
||||
mTradeModel = new TradeItemModel(new ContainerItemModel(itemSources, worldItems), mPtr);
|
||||
mSortModel = new SortFilterItemModel(mTradeModel);
|
||||
mItemView->setModel (mSortModel);
|
||||
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "inventorywindow.hpp"
|
||||
#include "bookpage.hpp"
|
||||
#include "itemview.hpp"
|
||||
#include "fontloader.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
@ -49,7 +50,7 @@ namespace MWGui
|
||||
WindowManager::WindowManager(
|
||||
const Compiler::Extensions& extensions, int fpsLevel, OEngine::Render::OgreRenderer *ogre,
|
||||
const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts,
|
||||
Translation::Storage& translationDataStorage)
|
||||
Translation::Storage& translationDataStorage, ToUTF8::FromType encoding)
|
||||
: mGuiManager(NULL)
|
||||
, mRendering(ogre)
|
||||
, mHud(NULL)
|
||||
@ -109,6 +110,10 @@ namespace MWGui
|
||||
mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath);
|
||||
mGui = mGuiManager->getGui();
|
||||
|
||||
// Load fonts
|
||||
FontLoader fontLoader (encoding);
|
||||
fontLoader.loadAllFonts();
|
||||
|
||||
//Register own widgets with MyGUI
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWSkill>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWAttribute>("Widget");
|
||||
|
@ -83,7 +83,7 @@ namespace MWGui
|
||||
WindowManager(const Compiler::Extensions& extensions, int fpsLevel,
|
||||
OEngine::Render::OgreRenderer *mOgre, const std::string& logpath,
|
||||
const std::string& cacheDir, bool consoleOnlyScripts,
|
||||
Translation::Storage& translationDataStorage);
|
||||
Translation::Storage& translationDataStorage, ToUTF8::FromType encoding);
|
||||
virtual ~WindowManager();
|
||||
|
||||
/**
|
||||
|
@ -29,8 +29,11 @@ namespace MWMechanics
|
||||
calculateCreatureStatModifiers (ptr);
|
||||
|
||||
// AI
|
||||
CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
|
||||
creatureStats.getAiSequence().execute (ptr);
|
||||
if(!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
{
|
||||
CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
|
||||
creatureStats.getAiSequence().execute (ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused)
|
||||
@ -309,4 +312,12 @@ namespace MWMechanics
|
||||
if(iter != mActors.end())
|
||||
iter->second.skipAnim();
|
||||
}
|
||||
|
||||
bool Actors::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName)
|
||||
{
|
||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||
if(iter != mActors.end())
|
||||
return iter->second.isAnimPlaying(groupName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -82,6 +82,7 @@ namespace MWMechanics
|
||||
|
||||
void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number);
|
||||
void skipAnimation(const MWWorld::Ptr& ptr);
|
||||
bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "aiescort.hpp"
|
||||
|
||||
#include "character.hpp"
|
||||
#include "movement.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
@ -10,16 +9,13 @@
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
||||
#include <boost/graph/astar_search.hpp>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include "boost/tuple/tuple.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
float sgn(float a)
|
||||
{
|
||||
if(a>0) return 1.;
|
||||
else return -1.;
|
||||
if(a > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,74 +25,73 @@ 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);
|
||||
}
|
||||
}
|
||||
mMaxDist = 470;
|
||||
|
||||
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;
|
||||
|
||||
// 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);
|
||||
std::cout << "AiEscort: " << currentSecond << " time: " << currentSecond - mStartingSecond << std::endl;
|
||||
if(currentSecond - mStartingSecond >= mDuration)
|
||||
else
|
||||
{
|
||||
return true;
|
||||
MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||
mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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. - 200))
|
||||
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;
|
||||
@ -107,7 +102,8 @@ bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor)
|
||||
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))
|
||||
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;
|
||||
@ -115,68 +111,70 @@ bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor)
|
||||
}
|
||||
|
||||
|
||||
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())
|
||||
if(!mPathFinder.isPathConstructed() || cellChange)
|
||||
{
|
||||
xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE;
|
||||
yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE;
|
||||
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);
|
||||
}
|
||||
|
||||
ESM::Pathgrid::Point dest;
|
||||
dest.mX = mX;
|
||||
dest.mY = mY;
|
||||
dest.mZ = mZ;
|
||||
if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]))
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
ESM::Pathgrid::Point start;
|
||||
start.mX = pos.pos[0];
|
||||
start.mY = pos.pos[1];
|
||||
start.mZ = pos.pos[2];
|
||||
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];
|
||||
|
||||
mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell);
|
||||
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;
|
||||
}
|
||||
|
||||
if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2]))
|
||||
int AiEscort::getTypeId() const
|
||||
{
|
||||
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||
return true;
|
||||
return 2;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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 MWMechanics::AiEscort::getTypeId() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
@ -2,30 +2,9 @@
|
||||
#define GAME_MWMECHANICS_AIESCORT_H
|
||||
|
||||
#include "aipackage.hpp"
|
||||
#include "pathfinding.hpp"
|
||||
#include <string>
|
||||
|
||||
/* From CS:
|
||||
Escort
|
||||
|
||||
Makes the actor escort another actor to a location or for a specified period of time. During this time the actor will also protect the actor it is escorting.
|
||||
|
||||
If you are not doing this package with the player as the target, you’ll want to also put a follow package on the target Actor, since escorting an actor makes the escorter wait for the other actor. If the Target does not know they are supposed to follow, the escorter will most likely just stand there.
|
||||
|
||||
Target: The ActorID to Escort. Remember that since all ActorIDs share the same AI packages, putting this on an Actor with multiple references will cause ALL references of that actor to attempt to escort the same actor. Thus, this type of AI should only be placed on specific or unique sets of Actors.
|
||||
|
||||
Duration: The duration the actor should escort for. Trumped by providing a location.
|
||||
|
||||
Escort to: Check this to use location data for the escort.
|
||||
|
||||
Cell: The Cell to escort to.
|
||||
|
||||
XYZ: Like Travel, specify the XYZ location to escort to.
|
||||
|
||||
View Location: A red X will appear in the render window that you can move around with the standard render window object controls. Place the X on the escort destination.
|
||||
|
||||
|
||||
*/
|
||||
#include "pathfinding.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
@ -1,54 +1,48 @@
|
||||
#include "aitravel.hpp"
|
||||
#include <iostream>
|
||||
|
||||
#include "character.hpp"
|
||||
#include "movement.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "movement.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
|
||||
#include <boost/graph/astar_search.hpp>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include "boost/tuple/tuple.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
float sgn(float a)
|
||||
{
|
||||
if(a>0) return 1.;
|
||||
else return -1.;
|
||||
if(a > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
||||
AiTravel::AiTravel(float x, float y, float z)
|
||||
: mX(x),mY(y),mZ(z),mPathFinder()
|
||||
: mX(x),mY(y),mZ(z),mPathFinder()
|
||||
{
|
||||
}
|
||||
|
||||
AiTravel * AiTravel::clone() const
|
||||
AiTravel *MWMechanics::AiTravel::clone() const
|
||||
{
|
||||
return new AiTravel(*this);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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();
|
||||
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(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;
|
||||
@ -58,19 +52,21 @@ namespace MWMechanics
|
||||
{
|
||||
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))
|
||||
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)
|
||||
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;
|
||||
@ -87,16 +83,17 @@ namespace MWMechanics
|
||||
start.mY = pos.pos[1];
|
||||
start.mZ = pos.pos[2];
|
||||
|
||||
mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell);
|
||||
mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, true);
|
||||
}
|
||||
if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2]))
|
||||
|
||||
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],pos.pos[2]);
|
||||
MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false);
|
||||
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;
|
||||
@ -106,5 +103,5 @@ namespace MWMechanics
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define GAME_MWMECHANICS_AITRAVEL_H
|
||||
|
||||
#include "aipackage.hpp"
|
||||
|
||||
#include "pathfinding.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
@ -25,10 +26,7 @@ namespace MWMechanics
|
||||
int cellX;
|
||||
int cellY;
|
||||
|
||||
//bool isPathConstructed;
|
||||
//std::list<ESM::Pathgrid::Point> mPath;
|
||||
PathFinder mPathFinder;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,23 +1,337 @@
|
||||
#include "aiwander.hpp"
|
||||
#include <iostream>
|
||||
|
||||
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)
|
||||
#include "movement.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
||||
#include <OgreVector3.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
float sgn(float a)
|
||||
{
|
||||
if(a > 0)
|
||||
return 1.0;
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
MWMechanics::AiPackage * MWMechanics::AiWander::clone() const
|
||||
namespace MWMechanics
|
||||
{
|
||||
return new AiWander(*this);
|
||||
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)
|
||||
{
|
||||
for(unsigned short counter = 0; counter < mIdle.size(); counter++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
AiPackage * MWMechanics::AiWander::clone() const
|
||||
{
|
||||
return new AiWander(*this);
|
||||
}
|
||||
|
||||
bool 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
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;
|
||||
unsigned short idleRoll = 0;
|
||||
|
||||
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)
|
||||
{
|
||||
if(!checkIdle(actor, mPlayedIdle + 1))
|
||||
{
|
||||
mPlayedIdle = 0;
|
||||
mIdleNow = false;
|
||||
mChooseAction = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(mMoveNow && mDistance)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// 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.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
||||
{
|
||||
stopWalking(actor);
|
||||
mMoveNow = false;
|
||||
mWalking = false;
|
||||
mChooseAction = true;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor)
|
||||
{
|
||||
// Return completed
|
||||
return true;
|
||||
}
|
||||
|
||||
int MWMechanics::AiWander::getTypeId() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -4,6 +4,10 @@
|
||||
#include "aipackage.hpp"
|
||||
#include <vector>
|
||||
|
||||
#include "pathfinding.hpp"
|
||||
|
||||
#include "../mwworld/timestamp.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
class AiWander : public AiPackage
|
||||
@ -18,11 +22,42 @@ namespace MWMechanics
|
||||
///< 0: Wander
|
||||
|
||||
private:
|
||||
void stopWalking(const MWWorld::Ptr& actor);
|
||||
void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
|
||||
bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect);
|
||||
|
||||
int mDistance;
|
||||
int mDuration;
|
||||
int mTimeOfDay;
|
||||
std::vector<int> mIdle;
|
||||
bool mRepeat;
|
||||
|
||||
float mX;
|
||||
float mY;
|
||||
float mZ;
|
||||
|
||||
int mCellX;
|
||||
int mCellY;
|
||||
float mXCell;
|
||||
float mYCell;
|
||||
|
||||
bool mStoredAvailableNodes;
|
||||
bool mChooseAction;
|
||||
bool mIdleNow;
|
||||
bool mMoveNow;
|
||||
bool mWalking;
|
||||
|
||||
float mIdleChanceMultiplier;
|
||||
unsigned short mPlayedIdle;
|
||||
|
||||
MWWorld::TimeStamp mStartTime;
|
||||
|
||||
std::vector<ESM::Pathgrid::Point> mAllowedNodes;
|
||||
ESM::Pathgrid::Point mCurrentNode;
|
||||
|
||||
PathFinder mPathFinder;
|
||||
const ESM::Pathgrid *mPathgrid;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -461,15 +461,18 @@ void CharacterController::update(float duration, Movement &movement)
|
||||
|
||||
Ogre::Vector3 moved = mAnimation->runAnimation(duration);
|
||||
// Ensure we're moving in generally the right direction
|
||||
if((movement.mPosition[0] < 0.0f && movement.mPosition[0] < moved.x*2.0f) ||
|
||||
(movement.mPosition[0] > 0.0f && movement.mPosition[0] > moved.x*2.0f))
|
||||
moved.x = movement.mPosition[0];
|
||||
if((movement.mPosition[1] < 0.0f && movement.mPosition[1] < moved.y*2.0f) ||
|
||||
(movement.mPosition[1] > 0.0f && movement.mPosition[1] > moved.y*2.0f))
|
||||
moved.y = movement.mPosition[1];
|
||||
if((movement.mPosition[2] < 0.0f && movement.mPosition[2] < moved.z*2.0f) ||
|
||||
(movement.mPosition[2] > 0.0f && movement.mPosition[2] > moved.z*2.0f))
|
||||
moved.z = movement.mPosition[2];
|
||||
if (speed > 0.f)
|
||||
{
|
||||
if((movement.mPosition[0] < 0.0f && movement.mPosition[0] < moved.x*2.0f) ||
|
||||
(movement.mPosition[0] > 0.0f && movement.mPosition[0] > moved.x*2.0f))
|
||||
moved.x = movement.mPosition[0];
|
||||
if((movement.mPosition[1] < 0.0f && movement.mPosition[1] < moved.y*2.0f) ||
|
||||
(movement.mPosition[1] > 0.0f && movement.mPosition[1] > moved.y*2.0f))
|
||||
moved.y = movement.mPosition[1];
|
||||
if((movement.mPosition[2] < 0.0f && movement.mPosition[2] < moved.z*2.0f) ||
|
||||
(movement.mPosition[2] > 0.0f && movement.mPosition[2] > moved.z*2.0f))
|
||||
moved.z = movement.mPosition[2];
|
||||
}
|
||||
|
||||
movement.mPosition[0] = moved.x;
|
||||
movement.mPosition[1] = moved.y;
|
||||
@ -509,6 +512,14 @@ void CharacterController::skipAnim()
|
||||
mSkipAnim = true;
|
||||
}
|
||||
|
||||
bool CharacterController::isAnimPlaying(const std::string &groupName)
|
||||
{
|
||||
if(mAnimation == NULL)
|
||||
return false;
|
||||
else
|
||||
return mAnimation->isPlaying(groupName);
|
||||
}
|
||||
|
||||
|
||||
void CharacterController::clearAnimQueue()
|
||||
{
|
||||
|
@ -125,6 +125,7 @@ public:
|
||||
|
||||
void playGroup(const std::string &groupname, int mode, int count);
|
||||
void skipAnim();
|
||||
bool isAnimPlaying(const std::string &groupName);
|
||||
|
||||
void setState(CharacterState state);
|
||||
CharacterState getState() const
|
||||
|
@ -12,7 +12,7 @@
|
||||
namespace MWMechanics
|
||||
{
|
||||
Enchanting::Enchanting():
|
||||
mEnchantType(0)
|
||||
mCastStyle(ESM::Enchantment::CastOnce)
|
||||
{}
|
||||
|
||||
void Enchanting::setOldItem(MWWorld::Ptr oldItem)
|
||||
@ -41,9 +41,9 @@ namespace MWMechanics
|
||||
mEffectList=effectList;
|
||||
}
|
||||
|
||||
int Enchanting::getEnchantType() const
|
||||
int Enchanting::getCastStyle() const
|
||||
{
|
||||
return mEnchantType;
|
||||
return mCastStyle;
|
||||
}
|
||||
|
||||
void Enchanting::setSoulGem(MWWorld::Ptr soulGem)
|
||||
@ -74,12 +74,12 @@ namespace MWMechanics
|
||||
MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1);
|
||||
}
|
||||
|
||||
if(mEnchantType==3)
|
||||
if(mCastStyle==ESM::Enchantment::ConstantEffect)
|
||||
{
|
||||
enchantment.mData.mCharge=0;
|
||||
}
|
||||
enchantment.mData.mType = mEnchantType;
|
||||
enchantment.mData.mCost = getEnchantCost();
|
||||
enchantment.mData.mType = mCastStyle;
|
||||
enchantment.mData.mCost = getEnchantPoints();
|
||||
enchantment.mEffects = mEffectList;
|
||||
|
||||
const ESM::Enchantment *enchantmentPtr = MWBase::Environment::get().getWorld()->createRecord (enchantment);
|
||||
@ -98,87 +98,142 @@ namespace MWMechanics
|
||||
return true;
|
||||
}
|
||||
|
||||
void Enchanting::nextEnchantType()
|
||||
void Enchanting::nextCastStyle()
|
||||
{
|
||||
mEnchantType++;
|
||||
if (itemEmpty())
|
||||
{
|
||||
mEnchantType = 0;
|
||||
mCastStyle = ESM::Enchantment::WhenUsed;
|
||||
return;
|
||||
}
|
||||
if ((mObjectType == typeid(ESM::Armor).name())||(mObjectType == typeid(ESM::Clothing).name()))
|
||||
{
|
||||
int soulConstAmount = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("iSoulAmountForConstantEffect")->getInt();
|
||||
switch(mEnchantType)
|
||||
|
||||
const bool powerfulSoul = getGemCharge() >= \
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("iSoulAmountForConstantEffect")->getInt();
|
||||
if ((mObjectType == typeid(ESM::Armor).name()) || (mObjectType == typeid(ESM::Clothing).name()))
|
||||
{ // Armor or Clothing
|
||||
switch(mCastStyle)
|
||||
{
|
||||
case 1:
|
||||
mEnchantType = 2;
|
||||
case 3:
|
||||
if(getGemCharge()<soulConstAmount)
|
||||
mEnchantType=2;
|
||||
case 4:
|
||||
mEnchantType = 2;
|
||||
case ESM::Enchantment::WhenUsed:
|
||||
if (powerfulSoul)
|
||||
mCastStyle = ESM::Enchantment::ConstantEffect;
|
||||
return;
|
||||
default: // takes care of Constant effect too
|
||||
mCastStyle = ESM::Enchantment::WhenUsed;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(mObjectType == typeid(ESM::Weapon).name())
|
||||
{
|
||||
switch(mEnchantType)
|
||||
{ // Weapon
|
||||
switch(mCastStyle)
|
||||
{
|
||||
case 3:
|
||||
mEnchantType = 1;
|
||||
case ESM::Enchantment::WhenStrikes:
|
||||
mCastStyle = ESM::Enchantment::WhenUsed;
|
||||
return;
|
||||
case ESM::Enchantment::WhenUsed:
|
||||
if (powerfulSoul)
|
||||
mCastStyle = ESM::Enchantment::ConstantEffect;
|
||||
else
|
||||
mCastStyle = ESM::Enchantment::WhenStrikes;
|
||||
return;
|
||||
default: // takes care of Constant effect too
|
||||
mCastStyle = ESM::Enchantment::WhenStrikes;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(mObjectType == typeid(ESM::Book).name())
|
||||
{
|
||||
mEnchantType=0;
|
||||
{ // Scroll or Book
|
||||
mCastStyle = ESM::Enchantment::CastOnce;
|
||||
return;
|
||||
}
|
||||
|
||||
// Fail case
|
||||
mCastStyle = ESM::Enchantment::CastOnce;
|
||||
}
|
||||
|
||||
float Enchanting::getEnchantCost() const
|
||||
/*
|
||||
* Vanilla enchant cost formula:
|
||||
*
|
||||
* Touch/Self: (min + max) * baseCost * 0.025 * duration + area * baseCost * 0.025
|
||||
* Target: 1.5 * ((min + max) * baseCost * 0.025 * duration + area * baseCost * 0.025)
|
||||
* Constant eff: (min + max) * baseCost * 2.5 + area * baseCost * 0.025
|
||||
*
|
||||
* For multiple effects - cost of each effect is multiplied by number of effects that follows +1.
|
||||
*
|
||||
* Note: Minimal value inside formula for 'min' and 'max' is 1. So in vanilla:
|
||||
* (0 + 0) == (1 + 0) == (1 + 1) => 2 or (2 + 0) == (1 + 2) => 3
|
||||
*
|
||||
* Formula on UESPWiki is not entirely correct.
|
||||
*/
|
||||
float Enchanting::getEnchantPoints() const
|
||||
{
|
||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||
float cost = 0;
|
||||
std::vector<ESM::ENAMstruct> mEffects = mEffectList.mList;
|
||||
int i=mEffects.size();
|
||||
if(i<=0)
|
||||
if (mEffectList.mList.empty())
|
||||
// No effects added, cost = 0
|
||||
return 0;
|
||||
|
||||
/*
|
||||
Formula from http://www.uesp.net/wiki/Morrowind:Enchant
|
||||
*/
|
||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||
std::vector<ESM::ENAMstruct> mEffects = mEffectList.mList;
|
||||
|
||||
float enchantmentCost = 0;
|
||||
int effectsLeftCnt = mEffects.size();
|
||||
float baseCost, magnitudeCost, areaCost;
|
||||
int magMin, magMax, area;
|
||||
for (std::vector<ESM::ENAMstruct>::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it)
|
||||
{
|
||||
const ESM::MagicEffect* effect = store.get<ESM::MagicEffect>().find(it->mEffectID);
|
||||
baseCost = (store.get<ESM::MagicEffect>().find(it->mEffectID))->mData.mBaseCost;
|
||||
// To reflect vanilla behavior
|
||||
magMin = (it->mMagnMin == 0) ? 1 : it->mMagnMin;
|
||||
magMax = (it->mMagnMax == 0) ? 1 : it->mMagnMax;
|
||||
area = (it->mArea == 0) ? 1 : it->mArea;
|
||||
|
||||
float cost1 = ((it->mMagnMin + it->mMagnMax)*it->mDuration*effect->mData.mBaseCost*0.025);
|
||||
|
||||
float cost2 = (std::max(1, it->mArea)*0.125*effect->mData.mBaseCost);
|
||||
|
||||
if(mEnchantType==3)
|
||||
if (mCastStyle == ESM::Enchantment::ConstantEffect)
|
||||
{
|
||||
int constDurationMultipler = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fEnchantmentConstantDurationMult")->getFloat();
|
||||
cost1 *= constDurationMultipler;
|
||||
cost2 *= 2;
|
||||
magnitudeCost = (magMin + magMax) * baseCost * 2.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
magnitudeCost = (magMin + magMax) * it->mDuration * baseCost * 0.025;
|
||||
if(it->mRange == ESM::RT_Target)
|
||||
magnitudeCost *= 1.5;
|
||||
}
|
||||
if(effect->mData.mFlags & ESM::MagicEffect::CastTarget)
|
||||
cost1 *= 1.5;
|
||||
|
||||
float fullcost = cost1+cost2;
|
||||
fullcost*= i;
|
||||
i--;
|
||||
areaCost = area * 0.025 * baseCost;
|
||||
if (it->mRange == ESM::RT_Target)
|
||||
areaCost *= 1.5;
|
||||
|
||||
cost+=fullcost;
|
||||
enchantmentCost += (magnitudeCost + areaCost) * effectsLeftCnt;
|
||||
--effectsLeftCnt;
|
||||
}
|
||||
return cost;
|
||||
|
||||
return enchantmentCost;
|
||||
}
|
||||
|
||||
|
||||
float Enchanting::getCastCost() const
|
||||
{
|
||||
if (mCastStyle == ESM::Enchantment::ConstantEffect)
|
||||
return 0;
|
||||
|
||||
const float enchantCost = getEnchantPoints();
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
MWMechanics::NpcStats &stats = MWWorld::Class::get(player).getNpcStats(player);
|
||||
int eSkill = stats.getSkill(ESM::Skill::Enchant).getModified();
|
||||
|
||||
/*
|
||||
* Each point of enchant skill above/under 10 subtracts/adds
|
||||
* one percent of enchantment cost while minimum is 1.
|
||||
*/
|
||||
const float castCost = enchantCost - (enchantCost / 100) * (eSkill - 10);
|
||||
|
||||
return (castCost < 1) ? 1 : castCost;
|
||||
}
|
||||
|
||||
|
||||
int Enchanting::getEnchantPrice() const
|
||||
{
|
||||
if(mEnchanter.isEmpty())
|
||||
return 0;
|
||||
|
||||
float priceMultipler = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fEnchantmentValueMult")->getFloat();
|
||||
int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, (getEnchantCost() * priceMultipler), true);
|
||||
int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, (getEnchantPoints() * priceMultipler), true);
|
||||
return price;
|
||||
}
|
||||
|
||||
@ -201,16 +256,12 @@ namespace MWMechanics
|
||||
}
|
||||
bool Enchanting::soulEmpty() const
|
||||
{
|
||||
if (mSoulGemPtr.isEmpty())
|
||||
return true;
|
||||
return false;
|
||||
return mSoulGemPtr.isEmpty();
|
||||
}
|
||||
|
||||
bool Enchanting::itemEmpty() const
|
||||
{
|
||||
if(mOldItemPtr.isEmpty())
|
||||
return true;
|
||||
return false;
|
||||
return mOldItemPtr.isEmpty();
|
||||
}
|
||||
|
||||
void Enchanting::setSelfEnchanting(bool selfEnchanting)
|
||||
@ -235,8 +286,8 @@ namespace MWMechanics
|
||||
(0.25 * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified())
|
||||
+ (0.125 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()));
|
||||
|
||||
float chance2 = 2.5 * getEnchantCost();
|
||||
if(mEnchantType==3)
|
||||
float chance2 = 2.5 * getEnchantPoints();
|
||||
if(mCastStyle==ESM::Enchantment::ConstantEffect)
|
||||
{
|
||||
float constantChance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fEnchantmentConstantChanceMult")->getFloat();
|
||||
chance2 /= constantChance;
|
||||
|
@ -13,7 +13,7 @@ namespace MWMechanics
|
||||
MWWorld::Ptr mSoulGemPtr;
|
||||
MWWorld::Ptr mEnchanter;
|
||||
|
||||
int mEnchantType;
|
||||
int mCastStyle;
|
||||
|
||||
bool mSelfEnchanting;
|
||||
|
||||
@ -33,9 +33,10 @@ namespace MWMechanics
|
||||
void setEffect(ESM::EffectList effectList);
|
||||
void setSoulGem(MWWorld::Ptr soulGem);
|
||||
bool create(); //Return true if created, false if failed.
|
||||
void nextEnchantType(); //Set enchant type to next possible type (for mOldItemPtr object)
|
||||
int getEnchantType() const;
|
||||
float getEnchantCost() const;
|
||||
void nextCastStyle(); //Set enchant type to next possible type (for mOldItemPtr object)
|
||||
int getCastStyle() const;
|
||||
float getEnchantPoints() const;
|
||||
float getCastCost() const;
|
||||
int getEnchantPrice() const;
|
||||
float getMaxEnchantValue() const;
|
||||
int getGemCharge() const;
|
||||
|
@ -668,5 +668,12 @@ namespace MWMechanics
|
||||
else
|
||||
mObjects.skipAnimation(ptr);
|
||||
}
|
||||
bool MechanicsManager::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName)
|
||||
{
|
||||
if(MWWorld::Class::get(ptr).isActor())
|
||||
return mActors.checkAnimationPlaying(ptr, groupName);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -100,6 +100,7 @@ namespace MWMechanics
|
||||
|
||||
virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number);
|
||||
virtual void skipAnimation(const MWWorld::Ptr& ptr);
|
||||
virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -64,13 +64,16 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b
|
||||
{
|
||||
// select best shader mode
|
||||
bool openGL = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL") != std::string::npos);
|
||||
bool glES = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL ES") != std::string::npos);
|
||||
|
||||
// glsl is only supported in opengl mode and hlsl only in direct3d mode.
|
||||
if (Settings::Manager::getString("shader mode", "General") == ""
|
||||
|| (openGL && Settings::Manager::getString("shader mode", "General") == "hlsl")
|
||||
|| (!openGL && Settings::Manager::getString("shader mode", "General") == "glsl"))
|
||||
std::string currentMode = Settings::Manager::getString("shader mode", "General");
|
||||
if (currentMode == ""
|
||||
|| (openGL && currentMode == "hlsl")
|
||||
|| (!openGL && currentMode == "glsl")
|
||||
|| (glES && currentMode != "glsles"))
|
||||
{
|
||||
Settings::Manager::setString("shader mode", "General", openGL ? "glsl" : "hlsl");
|
||||
Settings::Manager::setString("shader mode", "General", openGL ? (glES ? "glsles" : "glsl") : "hlsl");
|
||||
}
|
||||
|
||||
mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5);
|
||||
@ -93,6 +96,8 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b
|
||||
std::string l = Settings::Manager::getString("shader mode", "General");
|
||||
if (l == "glsl")
|
||||
lang = sh::Language_GLSL;
|
||||
else if (l == "glsles")
|
||||
lang = sh::Language_GLSLES;
|
||||
else if (l == "hlsl")
|
||||
lang = sh::Language_HLSL;
|
||||
else
|
||||
@ -396,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
|
||||
@ -433,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)
|
||||
|
@ -1,8 +1,6 @@
|
||||
#ifndef GAME_SOUND_FFMPEG_DECODER_H
|
||||
#define GAME_SOUND_FFMPEG_DECODER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
// FIXME: This can't be right? The headers refuse to build without UINT64_C,
|
||||
// which only gets defined in stdint.h in either C99 mode or with this macro
|
||||
// defined...
|
||||
@ -14,6 +12,8 @@ extern "C"
|
||||
#include <libavformat/avformat.h>
|
||||
}
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "sound_decoder.hpp"
|
||||
|
||||
|
||||
|
@ -1724,4 +1724,31 @@ namespace MWWorld
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ListHandlesFunctor
|
||||
{
|
||||
std::vector<std::string> mHandles;
|
||||
|
||||
bool operator() (ESM::CellRef& ref, RefData& data)
|
||||
{
|
||||
Ogre::SceneNode* handle = data.getBaseNode();
|
||||
if (handle)
|
||||
mHandles.push_back(handle->getName());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void World::getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out)
|
||||
{
|
||||
const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells();
|
||||
for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt)
|
||||
{
|
||||
ListHandlesFunctor functor;
|
||||
(*cellIt)->forEach<ListHandlesFunctor>(functor);
|
||||
|
||||
for (std::vector<std::string>::iterator it = functor.mHandles.begin(); it != functor.mHandles.end(); ++it)
|
||||
if (Misc::StringUtils::ciEqual(searchPtrViaHandle(*it).mCellRef->mOwner, npc.getCellRef().mRefID))
|
||||
out.push_back(searchPtrViaHandle(*it));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -391,6 +391,8 @@ namespace MWWorld
|
||||
|
||||
virtual void getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out);
|
||||
///< get all containers in active cells owned by this Npc
|
||||
virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out);
|
||||
///< get all items in active cells owned by this Npc
|
||||
|
||||
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering);
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <boost/tr1/tr1/unordered_map>
|
||||
#elif defined HAVE_UNORDERED_MAP
|
||||
#include <unordered_map>
|
||||
#else
|
||||
#include <tr1/unordered_map>
|
||||
#endif
|
||||
@ -48,7 +50,11 @@ struct ConfigurationManager
|
||||
typedef Files::FixedPath<> FixedPathType;
|
||||
|
||||
typedef const boost::filesystem::path& (FixedPathType::*path_type_f)() const;
|
||||
typedef std::tr1::unordered_map<std::string, path_type_f> TokensMappingContainer;
|
||||
#if defined HAVE_UNORDERED_MAP
|
||||
typedef std::unordered_map<std::string, path_type_f> TokensMappingContainer;
|
||||
#else
|
||||
typedef std::tr1::unordered_map<std::string, path_type_f> TokensMappingContainer;
|
||||
#endif
|
||||
|
||||
void loadConfig(const boost::filesystem::path& path,
|
||||
boost::program_options::variables_map& variables,
|
||||
|
@ -46,7 +46,7 @@ void writeMissing(bool last)
|
||||
int write_table(const std::string &charset, const std::string &tableName)
|
||||
{
|
||||
// Write table header
|
||||
cout << "static char " << tableName << "[] =\n{\n";
|
||||
cout << "static signed char " << tableName << "[] =\n{\n";
|
||||
|
||||
// Open conversion system
|
||||
iconv_t cd = iconv_open ("UTF-8", charset.c_str());
|
||||
@ -106,6 +106,8 @@ int main()
|
||||
"\n";
|
||||
write_table("WINDOWS-1252", "windows_1252");
|
||||
|
||||
write_table("CP437", "cp437");
|
||||
|
||||
// Close namespace
|
||||
cout << "\n}\n\n";
|
||||
|
||||
|
@ -790,6 +790,265 @@ static signed char windows_1252[] =
|
||||
2, -61, -66, 0, 0, 0,
|
||||
2, -61, -65, 0, 0, 0
|
||||
};
|
||||
static signed char cp437[] =
|
||||
{
|
||||
1, 0, 0, 0, 0, 0,
|
||||
1, 1, 0, 0, 0, 0,
|
||||
1, 2, 0, 0, 0, 0,
|
||||
1, 3, 0, 0, 0, 0,
|
||||
1, 4, 0, 0, 0, 0,
|
||||
1, 5, 0, 0, 0, 0,
|
||||
1, 6, 0, 0, 0, 0,
|
||||
1, 7, 0, 0, 0, 0,
|
||||
1, 8, 0, 0, 0, 0,
|
||||
1, 9, 0, 0, 0, 0,
|
||||
1, 10, 0, 0, 0, 0,
|
||||
1, 11, 0, 0, 0, 0,
|
||||
1, 12, 0, 0, 0, 0,
|
||||
1, 13, 0, 0, 0, 0,
|
||||
1, 14, 0, 0, 0, 0,
|
||||
1, 15, 0, 0, 0, 0,
|
||||
1, 16, 0, 0, 0, 0,
|
||||
1, 17, 0, 0, 0, 0,
|
||||
1, 18, 0, 0, 0, 0,
|
||||
1, 19, 0, 0, 0, 0,
|
||||
1, 20, 0, 0, 0, 0,
|
||||
1, 21, 0, 0, 0, 0,
|
||||
1, 22, 0, 0, 0, 0,
|
||||
1, 23, 0, 0, 0, 0,
|
||||
1, 24, 0, 0, 0, 0,
|
||||
1, 25, 0, 0, 0, 0,
|
||||
1, 26, 0, 0, 0, 0,
|
||||
1, 27, 0, 0, 0, 0,
|
||||
1, 28, 0, 0, 0, 0,
|
||||
1, 29, 0, 0, 0, 0,
|
||||
1, 30, 0, 0, 0, 0,
|
||||
1, 31, 0, 0, 0, 0,
|
||||
1, 32, 0, 0, 0, 0,
|
||||
1, 33, 0, 0, 0, 0,
|
||||
1, 34, 0, 0, 0, 0,
|
||||
1, 35, 0, 0, 0, 0,
|
||||
1, 36, 0, 0, 0, 0,
|
||||
1, 37, 0, 0, 0, 0,
|
||||
1, 38, 0, 0, 0, 0,
|
||||
1, 39, 0, 0, 0, 0,
|
||||
1, 40, 0, 0, 0, 0,
|
||||
1, 41, 0, 0, 0, 0,
|
||||
1, 42, 0, 0, 0, 0,
|
||||
1, 43, 0, 0, 0, 0,
|
||||
1, 44, 0, 0, 0, 0,
|
||||
1, 45, 0, 0, 0, 0,
|
||||
1, 46, 0, 0, 0, 0,
|
||||
1, 47, 0, 0, 0, 0,
|
||||
1, 48, 0, 0, 0, 0,
|
||||
1, 49, 0, 0, 0, 0,
|
||||
1, 50, 0, 0, 0, 0,
|
||||
1, 51, 0, 0, 0, 0,
|
||||
1, 52, 0, 0, 0, 0,
|
||||
1, 53, 0, 0, 0, 0,
|
||||
1, 54, 0, 0, 0, 0,
|
||||
1, 55, 0, 0, 0, 0,
|
||||
1, 56, 0, 0, 0, 0,
|
||||
1, 57, 0, 0, 0, 0,
|
||||
1, 58, 0, 0, 0, 0,
|
||||
1, 59, 0, 0, 0, 0,
|
||||
1, 60, 0, 0, 0, 0,
|
||||
1, 61, 0, 0, 0, 0,
|
||||
1, 62, 0, 0, 0, 0,
|
||||
1, 63, 0, 0, 0, 0,
|
||||
1, 64, 0, 0, 0, 0,
|
||||
1, 65, 0, 0, 0, 0,
|
||||
1, 66, 0, 0, 0, 0,
|
||||
1, 67, 0, 0, 0, 0,
|
||||
1, 68, 0, 0, 0, 0,
|
||||
1, 69, 0, 0, 0, 0,
|
||||
1, 70, 0, 0, 0, 0,
|
||||
1, 71, 0, 0, 0, 0,
|
||||
1, 72, 0, 0, 0, 0,
|
||||
1, 73, 0, 0, 0, 0,
|
||||
1, 74, 0, 0, 0, 0,
|
||||
1, 75, 0, 0, 0, 0,
|
||||
1, 76, 0, 0, 0, 0,
|
||||
1, 77, 0, 0, 0, 0,
|
||||
1, 78, 0, 0, 0, 0,
|
||||
1, 79, 0, 0, 0, 0,
|
||||
1, 80, 0, 0, 0, 0,
|
||||
1, 81, 0, 0, 0, 0,
|
||||
1, 82, 0, 0, 0, 0,
|
||||
1, 83, 0, 0, 0, 0,
|
||||
1, 84, 0, 0, 0, 0,
|
||||
1, 85, 0, 0, 0, 0,
|
||||
1, 86, 0, 0, 0, 0,
|
||||
1, 87, 0, 0, 0, 0,
|
||||
1, 88, 0, 0, 0, 0,
|
||||
1, 89, 0, 0, 0, 0,
|
||||
1, 90, 0, 0, 0, 0,
|
||||
1, 91, 0, 0, 0, 0,
|
||||
1, 92, 0, 0, 0, 0,
|
||||
1, 93, 0, 0, 0, 0,
|
||||
1, 94, 0, 0, 0, 0,
|
||||
1, 95, 0, 0, 0, 0,
|
||||
1, 96, 0, 0, 0, 0,
|
||||
1, 97, 0, 0, 0, 0,
|
||||
1, 98, 0, 0, 0, 0,
|
||||
1, 99, 0, 0, 0, 0,
|
||||
1, 100, 0, 0, 0, 0,
|
||||
1, 101, 0, 0, 0, 0,
|
||||
1, 102, 0, 0, 0, 0,
|
||||
1, 103, 0, 0, 0, 0,
|
||||
1, 104, 0, 0, 0, 0,
|
||||
1, 105, 0, 0, 0, 0,
|
||||
1, 106, 0, 0, 0, 0,
|
||||
1, 107, 0, 0, 0, 0,
|
||||
1, 108, 0, 0, 0, 0,
|
||||
1, 109, 0, 0, 0, 0,
|
||||
1, 110, 0, 0, 0, 0,
|
||||
1, 111, 0, 0, 0, 0,
|
||||
1, 112, 0, 0, 0, 0,
|
||||
1, 113, 0, 0, 0, 0,
|
||||
1, 114, 0, 0, 0, 0,
|
||||
1, 115, 0, 0, 0, 0,
|
||||
1, 116, 0, 0, 0, 0,
|
||||
1, 117, 0, 0, 0, 0,
|
||||
1, 118, 0, 0, 0, 0,
|
||||
1, 119, 0, 0, 0, 0,
|
||||
1, 120, 0, 0, 0, 0,
|
||||
1, 121, 0, 0, 0, 0,
|
||||
1, 122, 0, 0, 0, 0,
|
||||
1, 123, 0, 0, 0, 0,
|
||||
1, 124, 0, 0, 0, 0,
|
||||
1, 125, 0, 0, 0, 0,
|
||||
1, 126, 0, 0, 0, 0,
|
||||
1, 127, 0, 0, 0, 0,
|
||||
2, -61, -121, 0, 0, 0,
|
||||
2, -61, -68, 0, 0, 0,
|
||||
2, -61, -87, 0, 0, 0,
|
||||
2, -61, -94, 0, 0, 0,
|
||||
2, -61, -92, 0, 0, 0,
|
||||
2, -61, -96, 0, 0, 0,
|
||||
2, -61, -91, 0, 0, 0,
|
||||
2, -61, -89, 0, 0, 0,
|
||||
2, -61, -86, 0, 0, 0,
|
||||
2, -61, -85, 0, 0, 0,
|
||||
2, -61, -88, 0, 0, 0,
|
||||
2, -61, -81, 0, 0, 0,
|
||||
2, -61, -82, 0, 0, 0,
|
||||
2, -61, -84, 0, 0, 0,
|
||||
2, -61, -124, 0, 0, 0,
|
||||
2, -61, -123, 0, 0, 0,
|
||||
2, -61, -119, 0, 0, 0,
|
||||
2, -61, -90, 0, 0, 0,
|
||||
2, -61, -122, 0, 0, 0,
|
||||
2, -61, -76, 0, 0, 0,
|
||||
2, -61, -74, 0, 0, 0,
|
||||
2, -61, -78, 0, 0, 0,
|
||||
2, -61, -69, 0, 0, 0,
|
||||
2, -61, -71, 0, 0, 0,
|
||||
2, -61, -65, 0, 0, 0,
|
||||
2, -61, -106, 0, 0, 0,
|
||||
2, -61, -100, 0, 0, 0,
|
||||
2, -62, -94, 0, 0, 0,
|
||||
2, -62, -93, 0, 0, 0,
|
||||
2, -62, -91, 0, 0, 0,
|
||||
3, -30, -126, -89, 0, 0,
|
||||
2, -58, -110, 0, 0, 0,
|
||||
2, -61, -95, 0, 0, 0,
|
||||
2, -61, -83, 0, 0, 0,
|
||||
2, -61, -77, 0, 0, 0,
|
||||
2, -61, -70, 0, 0, 0,
|
||||
2, -61, -79, 0, 0, 0,
|
||||
2, -61, -111, 0, 0, 0,
|
||||
2, -62, -86, 0, 0, 0,
|
||||
2, -62, -70, 0, 0, 0,
|
||||
2, -62, -65, 0, 0, 0,
|
||||
3, -30, -116, -112, 0, 0,
|
||||
2, -62, -84, 0, 0, 0,
|
||||
2, -62, -67, 0, 0, 0,
|
||||
2, -62, -68, 0, 0, 0,
|
||||
2, -62, -95, 0, 0, 0,
|
||||
2, -62, -85, 0, 0, 0,
|
||||
2, -62, -69, 0, 0, 0,
|
||||
3, -30, -106, -111, 0, 0,
|
||||
3, -30, -106, -110, 0, 0,
|
||||
3, -30, -106, -109, 0, 0,
|
||||
3, -30, -108, -126, 0, 0,
|
||||
3, -30, -108, -92, 0, 0,
|
||||
3, -30, -107, -95, 0, 0,
|
||||
3, -30, -107, -94, 0, 0,
|
||||
3, -30, -107, -106, 0, 0,
|
||||
3, -30, -107, -107, 0, 0,
|
||||
3, -30, -107, -93, 0, 0,
|
||||
3, -30, -107, -111, 0, 0,
|
||||
3, -30, -107, -105, 0, 0,
|
||||
3, -30, -107, -99, 0, 0,
|
||||
3, -30, -107, -100, 0, 0,
|
||||
3, -30, -107, -101, 0, 0,
|
||||
3, -30, -108, -112, 0, 0,
|
||||
3, -30, -108, -108, 0, 0,
|
||||
3, -30, -108, -76, 0, 0,
|
||||
3, -30, -108, -84, 0, 0,
|
||||
3, -30, -108, -100, 0, 0,
|
||||
3, -30, -108, -128, 0, 0,
|
||||
3, -30, -108, -68, 0, 0,
|
||||
3, -30, -107, -98, 0, 0,
|
||||
3, -30, -107, -97, 0, 0,
|
||||
3, -30, -107, -102, 0, 0,
|
||||
3, -30, -107, -108, 0, 0,
|
||||
3, -30, -107, -87, 0, 0,
|
||||
3, -30, -107, -90, 0, 0,
|
||||
3, -30, -107, -96, 0, 0,
|
||||
3, -30, -107, -112, 0, 0,
|
||||
3, -30, -107, -84, 0, 0,
|
||||
3, -30, -107, -89, 0, 0,
|
||||
3, -30, -107, -88, 0, 0,
|
||||
3, -30, -107, -92, 0, 0,
|
||||
3, -30, -107, -91, 0, 0,
|
||||
3, -30, -107, -103, 0, 0,
|
||||
3, -30, -107, -104, 0, 0,
|
||||
3, -30, -107, -110, 0, 0,
|
||||
3, -30, -107, -109, 0, 0,
|
||||
3, -30, -107, -85, 0, 0,
|
||||
3, -30, -107, -86, 0, 0,
|
||||
3, -30, -108, -104, 0, 0,
|
||||
3, -30, -108, -116, 0, 0,
|
||||
3, -30, -106, -120, 0, 0,
|
||||
3, -30, -106, -124, 0, 0,
|
||||
3, -30, -106, -116, 0, 0,
|
||||
3, -30, -106, -112, 0, 0,
|
||||
3, -30, -106, -128, 0, 0,
|
||||
2, -50, -79, 0, 0, 0,
|
||||
2, -61, -97, 0, 0, 0,
|
||||
2, -50, -109, 0, 0, 0,
|
||||
2, -49, -128, 0, 0, 0,
|
||||
2, -50, -93, 0, 0, 0,
|
||||
2, -49, -125, 0, 0, 0,
|
||||
2, -62, -75, 0, 0, 0,
|
||||
2, -49, -124, 0, 0, 0,
|
||||
2, -50, -90, 0, 0, 0,
|
||||
2, -50, -104, 0, 0, 0,
|
||||
2, -50, -87, 0, 0, 0,
|
||||
2, -50, -76, 0, 0, 0,
|
||||
3, -30, -120, -98, 0, 0,
|
||||
2, -49, -122, 0, 0, 0,
|
||||
2, -50, -75, 0, 0, 0,
|
||||
3, -30, -120, -87, 0, 0,
|
||||
3, -30, -119, -95, 0, 0,
|
||||
2, -62, -79, 0, 0, 0,
|
||||
3, -30, -119, -91, 0, 0,
|
||||
3, -30, -119, -92, 0, 0,
|
||||
3, -30, -116, -96, 0, 0,
|
||||
3, -30, -116, -95, 0, 0,
|
||||
2, -61, -73, 0, 0, 0,
|
||||
3, -30, -119, -120, 0, 0,
|
||||
2, -62, -80, 0, 0, 0,
|
||||
3, -30, -120, -103, 0, 0,
|
||||
2, -62, -73, 0, 0, 0,
|
||||
3, -30, -120, -102, 0, 0,
|
||||
3, -30, -127, -65, 0, 0,
|
||||
2, -62, -78, 0, 0, 0,
|
||||
3, -30, -106, -96, 0, 0,
|
||||
2, -62, -96, 0, 0, 0
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,12 @@ Utf8Encoder::Utf8Encoder(const FromType sourceEncoding):
|
||||
translationArray = ToUTF8::windows_1251;
|
||||
break;
|
||||
}
|
||||
case ToUTF8::CP437:
|
||||
{
|
||||
translationArray = ToUTF8::cp437;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
assert(0);
|
||||
|
@ -12,8 +12,9 @@ namespace ToUTF8
|
||||
{
|
||||
WINDOWS_1250, // Central ane Eastern European languages
|
||||
WINDOWS_1251, // Cyrillic languages
|
||||
WINDOWS_1252 // Used by English version of Morrowind (and
|
||||
WINDOWS_1252, // Used by English version of Morrowind (and
|
||||
// probably others)
|
||||
CP437 // Used for fonts (*.fnt) if data files encoding is 1252. Otherwise, uses the same encoding as the data files.
|
||||
};
|
||||
|
||||
FromType calculateEncoding(const std::string& encodingName);
|
||||
|
@ -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
extern/shiny/Docs/Materials.dox
vendored
2
extern/shiny/Docs/Materials.dox
vendored
@ -87,6 +87,8 @@
|
||||
Now, let's get into writing our shader! As you can guess from above, the filename should be 'example.shader'.
|
||||
Make sure to also copy the 'core.h' file to the same location. It is included in shiny's source tree under 'Extra/'.
|
||||
|
||||
Important: a newline at the end of the file is <b>required</b>. Many editors do this automatically or can be configured to do so. If there is no newline at the end of the file, and the last line is '#endif', you will get the rather cryptic error message " ill formed preprocessor directive: #endif" from boost::wave.
|
||||
|
||||
\code
|
||||
#include "core.h"
|
||||
|
||||
|
2
extern/shiny/Editor/Actions.hpp
vendored
2
extern/shiny/Editor/Actions.hpp
vendored
@ -10,7 +10,7 @@ namespace sh
|
||||
{
|
||||
public:
|
||||
virtual void execute() = 0;
|
||||
virtual ~Action();
|
||||
virtual ~Action() {}
|
||||
};
|
||||
|
||||
class ActionDeleteMaterial : public Action
|
||||
|
2
extern/shiny/Editor/Query.hpp
vendored
2
extern/shiny/Editor/Query.hpp
vendored
@ -15,7 +15,7 @@ class Query
|
||||
public:
|
||||
Query()
|
||||
: mDone(false) {}
|
||||
virtual ~Query();
|
||||
virtual ~Query() {}
|
||||
|
||||
void execute();
|
||||
|
||||
|
@ -58,11 +58,20 @@
|
||||
|
||||
#endif
|
||||
|
||||
#if SH_GLSL == 1
|
||||
#if SH_GLSL == 1 || SH_GLSLES == 1
|
||||
|
||||
#define shFract(val) fract(val)
|
||||
|
||||
#if SH_GLSLES == 1
|
||||
@version 100
|
||||
#else
|
||||
@version 120
|
||||
#endif
|
||||
|
||||
#if SH_GLSLES == 1 && SH_FRAGMENT_SHADER
|
||||
precision mediump int;
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
#define float2 vec2
|
||||
#define float3 vec3
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
<MyGUI type="Skin">
|
||||
<Skin name = "TextBox" size = "16 16">
|
||||
<Property key="FontName" value = "EB Garamond" />
|
||||
<Property key="FontHeight" value = "16" />
|
||||
<Property key="TextAlign" value = "ALIGN_DEFAULT" />
|
||||
<Property key="TextColour" value = "0.7 0.7 0.7" />
|
||||
|
@ -23,56 +23,21 @@
|
||||
</Codes>
|
||||
</Resource>
|
||||
|
||||
<Resource type="ResourceTrueTypeFont" name="EB Garamond 24">
|
||||
<Property key="Source" value="EBGaramond-Regular.ttf"/>
|
||||
<Property key="Size" value="24"/>
|
||||
<Property key="Resolution" value="72"/>
|
||||
<Resource type="ResourceTrueTypeFont" name="MonoFont">
|
||||
<Property key="Source" value="DejaVuLGCSansMono.ttf"/>
|
||||
<Property key="Size" value="18"/>
|
||||
<Property key="Resolution" value="50"/>
|
||||
<Property key="Antialias" value="false"/>
|
||||
<Property key="TabWidth" value="8"/>
|
||||
<Property key="OffsetHeight" value="0"/>
|
||||
<Codes>
|
||||
<Code range="33 126"/>
|
||||
<Code range="160"/> <!-- Non-breaking space -->
|
||||
<Code range="192 382"/> <!-- Central and Eastern European languages glyphs -->
|
||||
<Code range="192 382"/>
|
||||
<Code range="1025 1105"/>
|
||||
<Code range="2026"/> <!-- Ellipsis -->
|
||||
<Code range="8470"/>
|
||||
<Code range="8211"/> <!-- Minus -->
|
||||
<Code range="8216 8217"/> <!-- Single quotes -->
|
||||
<Code range="8220 8221"/> <!-- Right and Left Double Quotation mark -->
|
||||
<Code hide="128"/>
|
||||
<Code hide="1026 1039"/>
|
||||
<Code hide="1104"/>
|
||||
</Codes>
|
||||
</Resource>
|
||||
<Resource type="ResourceTrueTypeFont" name="Daedric">
|
||||
<!--<Property key="Source" value="Oblivion/Oblivion Worn.ttf"/>-->
|
||||
<Property key="Source" value="Oblivion/Oblivion.ttf"/>
|
||||
<Property key="Size" value="24"/>
|
||||
<Property key="Resolution" value="72"/>
|
||||
<Property key="Antialias" value="false"/>
|
||||
<Property key="TabWidth" value="8"/>
|
||||
<Property key="OffsetHeight" value="0"/>
|
||||
<Codes>
|
||||
<Code range="65 122"/>
|
||||
</Codes>
|
||||
</Resource>
|
||||
|
||||
<Resource type="ResourceTrueTypeFont" name="MonoFont">
|
||||
<Property key="Source" value="DejaVuLGCSansMono.ttf"/>
|
||||
<Property key="Size" value="18"/>
|
||||
<Property key="Resolution" value="50"/>
|
||||
<Property key="Antialias" value="false"/>
|
||||
<Property key="TabWidth" value="8"/>
|
||||
<Property key="OffsetHeight" value="0"/>
|
||||
<Codes>
|
||||
<Code range="33 126"/>
|
||||
<Code range="192 382"/>
|
||||
<Code range="1025 1105"/>
|
||||
<Code range="8470"/>
|
||||
<Code hide="128"/>
|
||||
<Code hide="1026 1039"/>
|
||||
<Code hide="1104"/>
|
||||
</Codes>
|
||||
</Resource>
|
||||
</MyGUI>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MyGUI>
|
||||
<MyGUI type="Font">
|
||||
<Property key="Default" value="EB Garamond"/>
|
||||
<Property key="Default" value="Magic Cards"/>
|
||||
|
||||
</MyGUI>
|
||||
<MyGUI type="Pointer">
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 840 B After Width: | Height: | Size: 862 B |
Binary file not shown.
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.7 KiB |
@ -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>
|
||||
|
@ -206,6 +206,7 @@ void OgreRenderer::configure(const std::string &logPath,
|
||||
pluginDir = absPluginPath.string();
|
||||
|
||||
Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mRoot);
|
||||
Files::loadOgrePlugin(pluginDir, "RenderSystem_GLES2", *mRoot);
|
||||
Files::loadOgrePlugin(pluginDir, "RenderSystem_GL3Plus", *mRoot);
|
||||
Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mRoot);
|
||||
Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot);
|
||||
|
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…
x
Reference in New Issue
Block a user