From cc9b7638913ee0a5494a27af2ff7669f3ed451aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 May 2015 17:20:49 +0200 Subject: [PATCH 001/419] Fix for StartScript regression (Fixes #2590) --- apps/openmw/mwworld/store.hpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index d6aeeb51e..ba8be733a 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -366,6 +366,19 @@ namespace MWWorld inserted.first->second = scpt; } + template <> + inline void Store::load(ESM::ESMReader &esm, const std::string &id) + { + ESM::StartScript s; + s.load(esm); + s.mId = Misc::StringUtils::toLower(s.mId); + std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); + if (inserted.second) + mShared.push_back(&inserted.first->second); + else + inserted.first->second = s; + } + template <> class Store : public StoreBase { From d05d7f51d9bc581581ce2d88ebec9ab3ca085e4e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 31 May 2015 14:20:13 +0200 Subject: [PATCH 002/419] increased version number --- CMakeLists.txt | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c19c57eb..95035e85e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 36) -set(OPENMW_VERSION_RELEASE 0) +set(OPENMW_VERSION_RELEASE 1) set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_TAGHASH "") diff --git a/README.md b/README.md index f62800e1f..833d9b282 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ OpenMW 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.36.0 +* Version: 0.36.1 * License: GPL (see docs/license/GPL3.txt for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net From e8e3407062caad86c3e0c9dc3af0ae7ad7921434 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 31 May 2015 14:21:21 +0200 Subject: [PATCH 003/419] updated changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 466c2ef25..b2e7dc25c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +0.36.1 +------ + + Bug #2590: Start scripts not added correctly + 0.36.0 ------ From 277113f75bac985fe7f7b0c88101bea558a5ea58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 18:05:48 +0200 Subject: [PATCH 004/419] Fix number of jobs in coverity script --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d3b54b179..0029863d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ addons: description: "" notification_email: scrawl@baseoftrash.de build_command_prepend: "cmake ." - build_command: "make -j3" + build_command: "make -j2" branch_pattern: coverity_scan matrix: include: From c30936c19b2c4cb12fd5c319f7d65361f48f6fa6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Jun 2015 20:52:03 +0200 Subject: [PATCH 005/419] Reduce number of jobs in coverity script further --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0029863d3..998d0d9d0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ addons: description: "" notification_email: scrawl@baseoftrash.de build_command_prepend: "cmake ." - build_command: "make -j2" + build_command: "make" branch_pattern: coverity_scan matrix: include: From 65ba072dcd69794ec86acb0a0987bede6862e94a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 1 Jul 2015 02:09:13 +0200 Subject: [PATCH 006/419] Disable most targets except for OpenMW in coverity script --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 998d0d9d0..cbfc5d489 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ addons: name: "OpenMW/openmw" description: "" notification_email: scrawl@baseoftrash.de - build_command_prepend: "cmake ." + build_command_prepend: "cmake . -DBUILD_OPENCS=FALSE -DBUILD_UNITTESTS=FALSE -DBUILD_WIZARD=FALSE -DBUILD_BSATOOL=FALSE -DBUILD_ESMTOOL=FALSE -DBUILD_LAUNCHER=FALSE -DBUILD_MWINIIMPORTER=FALSE" build_command: "make" branch_pattern: coverity_scan matrix: From 1949fe4bf9e132e208766142400bf0d18d6762ce Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 2 Jul 2015 15:47:12 +0300 Subject: [PATCH 007/419] Add the configuration widget for extended commands --- apps/opencs/CMakeLists.txt | 2 +- .../world/extendedcommandconfigurator.cpp | 184 ++++++++++++++++++ .../world/extendedcommandconfigurator.hpp | 68 +++++++ 3 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/world/extendedcommandconfigurator.cpp create mode 100644 apps/opencs/view/world/extendedcommandconfigurator.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index dc042cb99..c933cbf9d 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -64,7 +64,7 @@ opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator cellcreator referenceablecreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable - dialoguespinbox recordbuttonbar + dialoguespinbox recordbuttonbar extendedcommandconfigurator ) opencs_units_noqt (view/world diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp new file mode 100644 index 000000000..dfdb5f573 --- /dev/null +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -0,0 +1,184 @@ +#include "extendedcommandconfigurator.hpp" + +#include +#include +#include +#include + +#include "../../model/world/commanddispatcher.hpp" +#include "../../model/world/universalid.hpp" + +namespace +{ + QString getTypeGroupTitle(CSVWorld::ExtendedCommandConfigurator::Mode mode) + { + static const QString title = "Tables affected by "; + QString titleSuffix = "Extended Delete"; + if (mode == CSVWorld::ExtendedCommandConfigurator::Mode_Revert) + { + titleSuffix = "Extended Revert"; + } + return title + titleSuffix; + } +} + +CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Document &document, + const CSMWorld::UniversalId &id, + QWidget *parent) + : QWidget(parent), + mNumUsedCheckBoxes(0), + mMode(Mode_None) +{ + mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); + + mPerformButton = new QPushButton("Perform", this); + mPerformButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + connect(mPerformButton, SIGNAL(clicked(bool)), this, SLOT(performExtendedCommand())); + + mCancelButton = new QPushButton("Cancel", this); + mCancelButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + connect(mCancelButton, SIGNAL(clicked(bool)), this, SLOT(done())); + + mButtonLayout = new QHBoxLayout(); + mButtonLayout->setAlignment(Qt::AlignCenter); + mButtonLayout->addWidget(mPerformButton); + mButtonLayout->addWidget(mCancelButton); + + mTypeGroup = new QGroupBox(this); + + QGridLayout *groupLayout = new QGridLayout(mTypeGroup); + groupLayout->setAlignment(Qt::AlignCenter); + mTypeGroup->setLayout(groupLayout); + + QVBoxLayout *mainLayout = new QVBoxLayout(this); + mainLayout->setSizeConstraint(QLayout::SetNoConstraint); + mainLayout->addWidget(mTypeGroup); + mainLayout->addLayout(mButtonLayout); +} + +CSVWorld::ExtendedCommandConfigurator::~ExtendedCommandConfigurator() +{ + delete mButtonLayout; +} + +void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandConfigurator::Mode mode) +{ + mMode = mode; + if (mMode != Mode_None) + { + mTypeGroup->setTitle(getTypeGroupTitle(mMode)); + setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); + setupGroupLayout(); + } +} + +void CSVWorld::ExtendedCommandConfigurator::resizeEvent(QResizeEvent *event) +{ + QWidget::resizeEvent(event); + setupGroupLayout(); +} + +void CSVWorld::ExtendedCommandConfigurator::setupGroupLayout() +{ + if (mMode == Mode_None) + { + return; + } + + int groupWidth = mTypeGroup->geometry().width(); + QGridLayout *layout = qobject_cast(mTypeGroup->layout()); + + // One row of checkboxes with enough space - the setup is over + if (mNumUsedCheckBoxes > 0 && layout->rowCount() == 1 && groupWidth >= mTypeGroup->sizeHint().width()) + { + return; + } + + // Find the optimal number of rows to place the checkboxes within the available space + int divider = 1; + do + { + while (layout->itemAt(0) != NULL) + { + layout->removeItem(layout->itemAt(0)); + } + + int counter = 0; + int itemsPerRow = mNumUsedCheckBoxes / divider; + CheckBoxMap::const_iterator current = mTypeCheckBoxes.begin(); + CheckBoxMap::const_iterator end = mTypeCheckBoxes.end(); + for (; current != end; ++current) + { + if (current->first->isVisible()) + { + int row = counter / itemsPerRow; + int column = counter - (counter / itemsPerRow) * itemsPerRow; + layout->addWidget(current->first, row, column); + } + ++counter; + } + divider *= 2; + } + while (groupWidth < mTypeGroup->sizeHint().width()); +} + +void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vector &types) +{ + // Make sure that we have enough checkboxes + int numTypes = static_cast(types.size()); + int numCheckBoxes = static_cast(mTypeCheckBoxes.size()); + if (numTypes > numCheckBoxes) + { + for (int i = numTypes - numCheckBoxes; i > 0; --i) + { + mTypeCheckBoxes.insert(std::make_pair(new QCheckBox(this), CSMWorld::UniversalId::Type_None)); + } + } + + // Set up the checkboxes + int counter = 0; + CheckBoxMap::iterator current = mTypeCheckBoxes.begin(); + CheckBoxMap::iterator end = mTypeCheckBoxes.end(); + for (; current != end; ++current) + { + if (counter < numTypes) + { + CSMWorld::UniversalId type = types[counter]; + current->first->setText(QString::fromUtf8(type.getTypeName().c_str())); + current->first->setChecked(true); + current->second = type; + ++counter; + } + else + { + current->first->hide(); + } + } + mNumUsedCheckBoxes = counter - 1; +} + +void CSVWorld::ExtendedCommandConfigurator::performExtendedCommand() +{ + std::vector types; + + CheckBoxMap::const_iterator current = mTypeCheckBoxes.begin(); + CheckBoxMap::const_iterator end = mTypeCheckBoxes.end(); + for (; current != end; ++current) + { + if (current->first->isChecked()) + { + types.push_back(current->second); + } + } + + mCommandDispatcher->setExtendedTypes(types); + if (mMode == Mode_Delete) + { + mCommandDispatcher->executeExtendedDelete(); + } + else + { + mCommandDispatcher->executeExtendedRevert(); + } + emit done(); +} diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp new file mode 100644 index 000000000..2feec14a7 --- /dev/null +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -0,0 +1,68 @@ +#ifndef CSVWORLD_EXTENDEDCOMMANDCONFIGURATOR_HPP +#define CSVWORLD_EXTENDEDCOMMANDCONFIGURATOR_HPP + +#include + +#include + +class QPushButton; +class QGroupBox; +class QCheckBox; +class QHBoxLayout; + +namespace CSMDoc +{ + class Document; +} + +namespace CSMWorld +{ + class CommandDispatcher; + class UniversalId; +} + +namespace CSVWorld +{ + class ExtendedCommandConfigurator : public QWidget + { + Q_OBJECT + + public: + enum Mode { Mode_None, Mode_Delete, Mode_Revert }; + + private: + typedef std::map CheckBoxMap; + + QPushButton *mPerformButton; + QPushButton *mCancelButton; + QHBoxLayout *mButtonLayout; + QGroupBox *mTypeGroup; + CheckBoxMap mTypeCheckBoxes; + int mNumUsedCheckBoxes; + + Mode mMode; + CSMWorld::CommandDispatcher *mCommandDispatcher; + + void setupGroupLayout(); + void setupCheckBoxes(const std::vector &types); + + public: + ExtendedCommandConfigurator(CSMDoc::Document &document, + const CSMWorld::UniversalId &id, + QWidget *parent = 0); + virtual ~ExtendedCommandConfigurator(); + + void configure(Mode mode); + + protected: + virtual void resizeEvent(QResizeEvent *event); + + private slots: + void performExtendedCommand(); + + signals: + void done(); + }; +} + +#endif From ba762ec1c1739bf0c86f727e8875efd7a2f3c4bf Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 2 Jul 2015 17:21:47 +0300 Subject: [PATCH 008/419] Add the configuration widget to the bottom box --- apps/opencs/view/world/tablebottombox.cpp | 37 ++++++++++++++++++----- apps/opencs/view/world/tablebottombox.hpp | 17 +++++++++-- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index dc3a6cc76..eab6b07b3 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -39,11 +39,19 @@ void CSVWorld::TableBottomBox::updateStatus() } } +void CSVWorld::TableBottomBox::extendedConfigRequest(CSVWorld::ExtendedCommandConfigurator::Mode mode) +{ + mExtendedConfigurator->configure (mode); + mLayout->setCurrentWidget (mExtendedConfigurator); + mEditMode = EditMode_ExtendedConfig; + setVisible (true); +} + CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, CSMDoc::Document& document, const CSMWorld::UniversalId& id, QWidget *parent) -: QWidget (parent), mShowStatusBar (false), mCreating (false) +: QWidget (parent), mShowStatusBar (false), mEditMode(EditMode_None) { for (int i=0; i<4; ++i) mStatusCount[i] = 0; @@ -69,11 +77,15 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto { mLayout->addWidget (mCreator); - connect (mCreator, SIGNAL (done()), this, SLOT (createRequestDone())); + connect (mCreator, SIGNAL (done()), this, SLOT (requestDone())); connect (mCreator, SIGNAL (requestFocus (const std::string&)), this, SIGNAL (requestFocus (const std::string&))); } + + mExtendedConfigurator = new ExtendedCommandConfigurator (document, id, this); + mLayout->addWidget (mExtendedConfigurator); + connect (mExtendedConfigurator, SIGNAL (done()), this, SLOT (requestDone())); } void CSVWorld::TableBottomBox::setEditLock (bool locked) @@ -91,7 +103,7 @@ void CSVWorld::TableBottomBox::setStatusBar (bool show) { if (show!=mShowStatusBar) { - setVisible (show || mCreating); + setVisible (show || (mEditMode != EditMode_None)); mShowStatusBar = show; @@ -105,7 +117,7 @@ bool CSVWorld::TableBottomBox::canCreateAndDelete() const return mCreator; } -void CSVWorld::TableBottomBox::createRequestDone() +void CSVWorld::TableBottomBox::requestDone() { if (!mShowStatusBar) setVisible (false); @@ -113,8 +125,7 @@ void CSVWorld::TableBottomBox::createRequestDone() updateStatus(); mLayout->setCurrentWidget (mStatusBar); - - mCreating = false; + mEditMode = EditMode_None; } void CSVWorld::TableBottomBox::selectionSizeChanged (int size) @@ -158,7 +169,7 @@ void CSVWorld::TableBottomBox::createRequest() mCreator->toggleWidgets(true); mLayout->setCurrentWidget (mCreator); setVisible (true); - mCreating = true; + mEditMode = EditMode_Creation; mCreator->focus(); } @@ -170,6 +181,16 @@ void CSVWorld::TableBottomBox::cloneRequest(const std::string& id, mLayout->setCurrentWidget(mCreator); mCreator->toggleWidgets(false); setVisible (true); - mCreating = true; + mEditMode = EditMode_Creation; mCreator->focus(); } + +void CSVWorld::TableBottomBox::extendedDeleteConfigRequest() +{ + extendedConfigRequest(ExtendedCommandConfigurator::Mode_Delete); +} + +void CSVWorld::TableBottomBox::extendedRevertConfigRequest() +{ + extendedConfigRequest(ExtendedCommandConfigurator::Mode_Revert); +} diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index a7d009c42..d2fb865e7 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -4,10 +4,11 @@ #include #include +#include "extendedcommandconfigurator.hpp" + class QLabel; class QStackedLayout; class QStatusBar; -class QUndoStack; namespace CSMDoc { @@ -23,12 +24,17 @@ namespace CSVWorld { Q_OBJECT + enum EditMode { EditMode_None, EditMode_Creation, EditMode_ExtendedConfig }; + bool mShowStatusBar; QLabel *mStatus; QStatusBar *mStatusBar; int mStatusCount[4]; + + EditMode mEditMode; Creator *mCreator; - bool mCreating; + ExtendedCommandConfigurator *mExtendedConfigurator; + QStackedLayout *mLayout; private: @@ -39,6 +45,8 @@ namespace CSVWorld void updateStatus(); + void extendedConfigRequest(ExtendedCommandConfigurator::Mode mode); + public: TableBottomBox (const CreatorFactoryBase& creatorFactory, @@ -65,7 +73,7 @@ namespace CSVWorld private slots: - void createRequestDone(); + void requestDone(); ///< \note This slot being called does not imply success. public slots: @@ -80,6 +88,9 @@ namespace CSVWorld void createRequest(); void cloneRequest(const std::string& id, const CSMWorld::UniversalId::Type type); + + void extendedDeleteConfigRequest(); + void extendedRevertConfigRequest(); }; } From fcf69555f4bf382aa808179a5fafb89df7feaaa1 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 2 Jul 2015 20:41:32 +0300 Subject: [PATCH 009/419] Add the user setting for enabling the configuration of extended commands --- apps/opencs/model/settings/usersettings.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 1bfc6e85b..cb001fea9 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -215,6 +215,12 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() "Jump to the added or cloned record."); jumpToAdded->setDefaultValue (defaultValue); jumpToAdded->setDeclaredValues (jumpValues); + + Setting *extendedConfig = createSetting (Type_CheckBox, "extended-config", + "Enable configuration of the extended delete/revert"); + extendedConfig->setDefaultValue("false"); + extendedConfig->setToolTip("Enables the ability to specify tables that will be affected by " + "the extended delete/revert command"); } declareSection ("report-input", "Report Input"); From b8772c6902ec22f80a3f1d4850db626417c1898b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 2 Jul 2015 20:44:59 +0300 Subject: [PATCH 010/419] Add the ability to configure extended commands for tables --- .../world/extendedcommandconfigurator.cpp | 6 +- .../world/extendedcommandconfigurator.hpp | 2 +- apps/opencs/view/world/table.cpp | 70 +++++++++++++------ apps/opencs/view/world/table.hpp | 10 +++ apps/opencs/view/world/tablebottombox.cpp | 13 ++-- apps/opencs/view/world/tablebottombox.hpp | 7 +- apps/opencs/view/world/tablesubview.cpp | 5 ++ 7 files changed, 79 insertions(+), 34 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index dfdb5f573..6ba26634b 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -37,7 +37,7 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mCancelButton = new QPushButton("Cancel", this); mCancelButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - connect(mCancelButton, SIGNAL(clicked(bool)), this, SLOT(done())); + connect(mCancelButton, SIGNAL(clicked(bool)), this, SIGNAL(done())); mButtonLayout = new QHBoxLayout(); mButtonLayout->setAlignment(Qt::AlignCenter); @@ -61,12 +61,14 @@ CSVWorld::ExtendedCommandConfigurator::~ExtendedCommandConfigurator() delete mButtonLayout; } -void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandConfigurator::Mode mode) +void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandConfigurator::Mode mode, + const std::vector &selectedIds) { mMode = mode; if (mMode != Mode_None) { mTypeGroup->setTitle(getTypeGroupTitle(mMode)); + mCommandDispatcher->setSelection(selectedIds); setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); setupGroupLayout(); } diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 2feec14a7..dd2477444 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -52,7 +52,7 @@ namespace CSVWorld QWidget *parent = 0); virtual ~ExtendedCommandConfigurator(); - void configure(Mode mode); + void configure(Mode mode, const std::vector &selectedIds); protected: virtual void resizeEvent(QResizeEvent *event); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index ba691131b..353bd50d2 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -32,28 +32,14 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) { // configure dispatcher - QModelIndexList selectedRows = selectionModel()->selectedRows(); - - std::vector records; - - int columnIndex = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id); - - for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); - ++iter) - { - int row = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0)).row(); - - records.push_back (mModel->data ( - mModel->index (row, columnIndex)).toString().toUtf8().constData()); - } - - mDispatcher->setSelection (records); + mDispatcher->setSelection (getSelectedIds()); std::vector extendedTypes = mDispatcher->getExtendedTypes(); mDispatcher->setExtendedTypes (extendedTypes); // create context menu + QModelIndexList selectedRows = selectionModel()->selectedRows(); QMenu menu (this); /// \todo add menu items for select all and clear selection @@ -375,16 +361,12 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, connect (mPreviewAction, SIGNAL (triggered()), this, SLOT (previewRecord())); addAction (mPreviewAction); - /// \todo add a user option, that redirects the extended action to an input panel (in - /// the bottom bar) that lets the user select which record collections should be - /// modified. - mExtendedDeleteAction = new QAction (tr ("Extended Delete Record"), this); - connect (mExtendedDeleteAction, SIGNAL (triggered()), mDispatcher, SLOT (executeExtendedDelete())); + connect (mExtendedDeleteAction, SIGNAL (triggered()), this, SLOT (executeExtendedDelete())); addAction (mExtendedDeleteAction); mExtendedRevertAction = new QAction (tr ("Extended Revert Record"), this); - connect (mExtendedRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeExtendedRevert())); + connect (mExtendedRevertAction, SIGNAL (triggered()), this, SLOT (executeExtendedRevert())); addAction (mExtendedRevertAction); connect (mProxyModel, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), @@ -430,6 +412,22 @@ CSMWorld::UniversalId CSVWorld::Table::getUniversalId (int row) const mModel->data (mModel->index (row, idColumn)).toString().toUtf8().constData()); } +std::vector CSVWorld::Table::getSelectedIds() const +{ + std::vector ids; + QModelIndexList selectedRows = selectionModel()->selectedRows(); + int columnIndex = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id); + + for (QModelIndexList::const_iterator iter (selectedRows.begin()); + iter != selectedRows.end(); + ++iter) + { + int row = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0)).row(); + ids.push_back (mModel->data (mModel->index (row, columnIndex)).toString().toUtf8().constData()); + } + return ids; +} + void CSVWorld::Table::editRecord() { if (!mEditLock || (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant)) @@ -562,6 +560,34 @@ void CSVWorld::Table::previewRecord() } } +void CSVWorld::Table::executeExtendedDelete() +{ + CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); + QString configSetting = settings.settingValue ("table-input/extended-config"); + if (configSetting == "true") + { + emit extendedDeleteConfigRequest(getSelectedIds()); + } + else + { + QMetaObject::invokeMethod(mDispatcher, "executeExtendedDelete", Qt::QueuedConnection); + } +} + +void CSVWorld::Table::executeExtendedRevert() +{ + CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); + QString configSetting = settings.settingValue ("table-input/extended-config"); + if (configSetting == "true") + { + emit extendedRevertConfigRequest(getSelectedIds()); + } + else + { + QMetaObject::invokeMethod(mDispatcher, "executeExtendedRevert", Qt::QueuedConnection); + } +} + void CSVWorld::Table::updateUserSetting (const QString &name, const QStringList &list) { if (name=="table-input/jump-to-added") diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 38fcd83bd..7efc3ad34 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -93,6 +93,8 @@ namespace CSVWorld std::vector getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const; + std::vector getSelectedIds() const; + virtual std::vector getDraggedRecords() const; signals: @@ -112,6 +114,10 @@ namespace CSVWorld void closeRequest(); + void extendedDeleteConfigRequest(const std::vector &selectedIds); + + void extendedRevertConfigRequest(const std::vector &selectedIds); + private slots: void editCell(); @@ -128,6 +134,10 @@ namespace CSVWorld void previewRecord(); + void executeExtendedDelete(); + + void executeExtendedRevert(); + public slots: void tableSizeUpdate(); diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index eab6b07b3..bfd56b326 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -39,9 +39,10 @@ void CSVWorld::TableBottomBox::updateStatus() } } -void CSVWorld::TableBottomBox::extendedConfigRequest(CSVWorld::ExtendedCommandConfigurator::Mode mode) +void CSVWorld::TableBottomBox::extendedConfigRequest(CSVWorld::ExtendedCommandConfigurator::Mode mode, + const std::vector &selectedIds) { - mExtendedConfigurator->configure (mode); + mExtendedConfigurator->configure (mode, selectedIds); mLayout->setCurrentWidget (mExtendedConfigurator); mEditMode = EditMode_ExtendedConfig; setVisible (true); @@ -185,12 +186,12 @@ void CSVWorld::TableBottomBox::cloneRequest(const std::string& id, mCreator->focus(); } -void CSVWorld::TableBottomBox::extendedDeleteConfigRequest() +void CSVWorld::TableBottomBox::extendedDeleteConfigRequest(const std::vector &selectedIds) { - extendedConfigRequest(ExtendedCommandConfigurator::Mode_Delete); + extendedConfigRequest(ExtendedCommandConfigurator::Mode_Delete, selectedIds); } -void CSVWorld::TableBottomBox::extendedRevertConfigRequest() +void CSVWorld::TableBottomBox::extendedRevertConfigRequest(const std::vector &selectedIds) { - extendedConfigRequest(ExtendedCommandConfigurator::Mode_Revert); + extendedConfigRequest(ExtendedCommandConfigurator::Mode_Revert, selectedIds); } diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index d2fb865e7..fded912fe 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -45,7 +45,8 @@ namespace CSVWorld void updateStatus(); - void extendedConfigRequest(ExtendedCommandConfigurator::Mode mode); + void extendedConfigRequest(ExtendedCommandConfigurator::Mode mode, + const std::vector &selectedIds); public: @@ -89,8 +90,8 @@ namespace CSVWorld void cloneRequest(const std::string& id, const CSMWorld::UniversalId::Type type); - void extendedDeleteConfigRequest(); - void extendedRevertConfigRequest(); + void extendedDeleteConfigRequest(const std::vector &selectedIds); + void extendedRevertConfigRequest(const std::vector &selectedIds); }; } diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 75671a50c..abae6115a 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -71,6 +71,11 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D connect (this, SIGNAL(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type)), mBottom, SLOT(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type))); + + connect (mTable, SIGNAL(extendedDeleteConfigRequest(const std::vector &)), + mBottom, SLOT(extendedDeleteConfigRequest(const std::vector &))); + connect (mTable, SIGNAL(extendedRevertConfigRequest(const std::vector &)), + mBottom, SLOT(extendedRevertConfigRequest(const std::vector &))); } connect (mBottom, SIGNAL (requestFocus (const std::string&)), mTable, SLOT (requestFocus (const std::string&))); From 12bf3694bdd5320dcc843a82b75d244e0e9ed975 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 2 Jul 2015 22:05:45 +0300 Subject: [PATCH 011/419] Rework widget layout of ExtendedCommandConfigurator --- .../world/extendedcommandconfigurator.cpp | 36 ++++++++----------- .../world/extendedcommandconfigurator.hpp | 4 +-- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index 6ba26634b..9f067545c 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "../../model/world/commanddispatcher.hpp" @@ -39,10 +40,8 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mCancelButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(mCancelButton, SIGNAL(clicked(bool)), this, SIGNAL(done())); - mButtonLayout = new QHBoxLayout(); - mButtonLayout->setAlignment(Qt::AlignCenter); - mButtonLayout->addWidget(mPerformButton); - mButtonLayout->addWidget(mCancelButton); + mCommandTitle = new QLabel(this); + mCommandTitle->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); mTypeGroup = new QGroupBox(this); @@ -50,15 +49,12 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum groupLayout->setAlignment(Qt::AlignCenter); mTypeGroup->setLayout(groupLayout); - QVBoxLayout *mainLayout = new QVBoxLayout(this); + QHBoxLayout *mainLayout = new QHBoxLayout(this); mainLayout->setSizeConstraint(QLayout::SetNoConstraint); + mainLayout->addWidget(mCommandTitle); mainLayout->addWidget(mTypeGroup); - mainLayout->addLayout(mButtonLayout); -} - -CSVWorld::ExtendedCommandConfigurator::~ExtendedCommandConfigurator() -{ - delete mButtonLayout; + mainLayout->addWidget(mPerformButton); + mainLayout->addWidget(mCancelButton); } void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandConfigurator::Mode mode, @@ -67,7 +63,9 @@ void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandC mMode = mode; if (mMode != Mode_None) { - mTypeGroup->setTitle(getTypeGroupTitle(mMode)); + QString title = (mMode == Mode_Delete) ? "Extended Delete" : "Extended Revert"; + title.append(" from:"); + mCommandTitle->setText(title); mCommandDispatcher->setSelection(selectedIds); setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); setupGroupLayout(); @@ -90,12 +88,6 @@ void CSVWorld::ExtendedCommandConfigurator::setupGroupLayout() int groupWidth = mTypeGroup->geometry().width(); QGridLayout *layout = qobject_cast(mTypeGroup->layout()); - // One row of checkboxes with enough space - the setup is over - if (mNumUsedCheckBoxes > 0 && layout->rowCount() == 1 && groupWidth >= mTypeGroup->sizeHint().width()) - { - return; - } - // Find the optimal number of rows to place the checkboxes within the available space int divider = 1; do @@ -111,7 +103,7 @@ void CSVWorld::ExtendedCommandConfigurator::setupGroupLayout() CheckBoxMap::const_iterator end = mTypeCheckBoxes.end(); for (; current != end; ++current) { - if (current->first->isVisible()) + if (counter < mNumUsedCheckBoxes) { int row = counter / itemsPerRow; int column = counter - (counter / itemsPerRow) * itemsPerRow; @@ -121,7 +113,7 @@ void CSVWorld::ExtendedCommandConfigurator::setupGroupLayout() } divider *= 2; } - while (groupWidth < mTypeGroup->sizeHint().width()); + while (groupWidth < mTypeGroup->sizeHint().width() && divider <= mNumUsedCheckBoxes); } void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vector &types) @@ -133,7 +125,7 @@ void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vector 0; --i) { - mTypeCheckBoxes.insert(std::make_pair(new QCheckBox(this), CSMWorld::UniversalId::Type_None)); + mTypeCheckBoxes.insert(std::make_pair(new QCheckBox(mTypeGroup), CSMWorld::UniversalId::Type_None)); } } @@ -156,7 +148,7 @@ void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vectorfirst->hide(); } } - mNumUsedCheckBoxes = counter - 1; + mNumUsedCheckBoxes = numTypes; } void CSVWorld::ExtendedCommandConfigurator::performExtendedCommand() diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index dd2477444..8efe36fa7 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -8,6 +8,7 @@ class QPushButton; class QGroupBox; class QCheckBox; +class QLabel; class QHBoxLayout; namespace CSMDoc @@ -35,7 +36,7 @@ namespace CSVWorld QPushButton *mPerformButton; QPushButton *mCancelButton; - QHBoxLayout *mButtonLayout; + QLabel *mCommandTitle; QGroupBox *mTypeGroup; CheckBoxMap mTypeCheckBoxes; int mNumUsedCheckBoxes; @@ -50,7 +51,6 @@ namespace CSVWorld ExtendedCommandConfigurator(CSMDoc::Document &document, const CSMWorld::UniversalId &id, QWidget *parent = 0); - virtual ~ExtendedCommandConfigurator(); void configure(Mode mode, const std::vector &selectedIds); From 260f6f22aecfa6722e103620ed657c33549de597 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 22:07:37 +0300 Subject: [PATCH 012/419] TableBottomBox adjusts its size according to the current widget size --- apps/opencs/view/world/tablebottombox.cpp | 22 ++++++++++++++++++++++ apps/opencs/view/world/tablebottombox.hpp | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index bfd56b326..eee25b1bf 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -9,6 +9,20 @@ #include "creator.hpp" +void CSVWorld::TableBottomBox::updateSize() +{ + // Make sure that the size of the bottom box is determined by the currently visible widget + for (int i = 0; i < mLayout->count(); ++i) + { + QSizePolicy::Policy verPolicy = QSizePolicy::Ignored; + if (mLayout->widget(i) == mLayout->currentWidget()) + { + verPolicy = QSizePolicy::Expanding; + } + mLayout->widget(i)->setSizePolicy(QSizePolicy::Expanding, verPolicy); + } +} + void CSVWorld::TableBottomBox::updateStatus() { if (mShowStatusBar) @@ -61,6 +75,7 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto mLayout = new QStackedLayout; mLayout->setContentsMargins (0, 0, 0, 0); + connect (mLayout, SIGNAL (currentChanged (int)), this, SLOT (currentWidgetChanged (int))); mStatus = new QLabel; @@ -87,6 +102,8 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto mExtendedConfigurator = new ExtendedCommandConfigurator (document, id, this); mLayout->addWidget (mExtendedConfigurator); connect (mExtendedConfigurator, SIGNAL (done()), this, SLOT (requestDone())); + + updateSize(); } void CSVWorld::TableBottomBox::setEditLock (bool locked) @@ -129,6 +146,11 @@ void CSVWorld::TableBottomBox::requestDone() mEditMode = EditMode_None; } +void CSVWorld::TableBottomBox::currentWidgetChanged(int /*index*/) +{ + updateSize(); +} + void CSVWorld::TableBottomBox::selectionSizeChanged (int size) { if (mStatusCount[3]!=size) diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index fded912fe..15ae2924c 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -43,6 +43,8 @@ namespace CSVWorld TableBottomBox (const TableBottomBox&); TableBottomBox& operator= (const TableBottomBox&); + void updateSize(); + void updateStatus(); void extendedConfigRequest(ExtendedCommandConfigurator::Mode mode, @@ -77,6 +79,8 @@ namespace CSVWorld void requestDone(); ///< \note This slot being called does not imply success. + void currentWidgetChanged(int index); + public slots: void selectionSizeChanged (int size); From 95d16b24c05142943b22c31162bebc1b7b46a82f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 22:25:56 +0300 Subject: [PATCH 013/419] ExtendedCommandConfigurator: disable the perform button when all tables are unchecked --- .../world/extendedcommandconfigurator.cpp | 24 +++++++++++++++++-- .../world/extendedcommandconfigurator.hpp | 2 ++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index 9f067545c..257e9c4f0 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -28,6 +28,7 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum QWidget *parent) : QWidget(parent), mNumUsedCheckBoxes(0), + mNumChecked(0), mMode(Mode_None) { mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); @@ -125,7 +126,9 @@ void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vector 0; --i) { - mTypeCheckBoxes.insert(std::make_pair(new QCheckBox(mTypeGroup), CSMWorld::UniversalId::Type_None)); + QCheckBox *checkBox = new QCheckBox(mTypeGroup); + connect(checkBox, SIGNAL(stateChanged(int)), this, SLOT(checkBoxStateChanged(int))); + mTypeCheckBoxes.insert(std::make_pair(checkBox, CSMWorld::UniversalId::Type_None)); } } @@ -148,7 +151,7 @@ void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vectorfirst->hide(); } } - mNumUsedCheckBoxes = numTypes; + mNumChecked = mNumUsedCheckBoxes = numTypes; } void CSVWorld::ExtendedCommandConfigurator::performExtendedCommand() @@ -176,3 +179,20 @@ void CSVWorld::ExtendedCommandConfigurator::performExtendedCommand() } emit done(); } + +void CSVWorld::ExtendedCommandConfigurator::checkBoxStateChanged(int state) +{ + switch (state) + { + case Qt::Unchecked: + --mNumChecked; + break; + case Qt::Checked: + ++mNumChecked; + break; + case Qt::PartiallyChecked: // Not used + break; + } + + mPerformButton->setEnabled(mNumChecked > 0); +} diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 8efe36fa7..6a5e1e2e7 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -40,6 +40,7 @@ namespace CSVWorld QGroupBox *mTypeGroup; CheckBoxMap mTypeCheckBoxes; int mNumUsedCheckBoxes; + int mNumChecked; Mode mMode; CSMWorld::CommandDispatcher *mCommandDispatcher; @@ -59,6 +60,7 @@ namespace CSVWorld private slots: void performExtendedCommand(); + void checkBoxStateChanged(int state); signals: void done(); From 05cc130212162195f2f09143000f1fb49d38442f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 22:31:38 +0300 Subject: [PATCH 014/419] The configuration panel gets a focus when opening --- apps/opencs/view/world/tablebottombox.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index eee25b1bf..3a7fa8e8a 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -60,6 +60,7 @@ void CSVWorld::TableBottomBox::extendedConfigRequest(CSVWorld::ExtendedCommandCo mLayout->setCurrentWidget (mExtendedConfigurator); mEditMode = EditMode_ExtendedConfig; setVisible (true); + mExtendedConfigurator->setFocus(); } CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, From e664ef75785929d5657986bd2cacace7779c627b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 23:15:26 +0300 Subject: [PATCH 015/419] ExtendedCommandConfigurator: the perform button takes the name of the command that is executed --- .../world/extendedcommandconfigurator.cpp | 24 ++----------------- .../world/extendedcommandconfigurator.hpp | 1 - 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index 257e9c4f0..36bff7d59 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -9,20 +9,6 @@ #include "../../model/world/commanddispatcher.hpp" #include "../../model/world/universalid.hpp" -namespace -{ - QString getTypeGroupTitle(CSVWorld::ExtendedCommandConfigurator::Mode mode) - { - static const QString title = "Tables affected by "; - QString titleSuffix = "Extended Delete"; - if (mode == CSVWorld::ExtendedCommandConfigurator::Mode_Revert) - { - titleSuffix = "Extended Revert"; - } - return title + titleSuffix; - } -} - CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Document &document, const CSMWorld::UniversalId &id, QWidget *parent) @@ -33,7 +19,7 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum { mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); - mPerformButton = new QPushButton("Perform", this); + mPerformButton = new QPushButton(this); mPerformButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(mPerformButton, SIGNAL(clicked(bool)), this, SLOT(performExtendedCommand())); @@ -41,9 +27,6 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mCancelButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(mCancelButton, SIGNAL(clicked(bool)), this, SIGNAL(done())); - mCommandTitle = new QLabel(this); - mCommandTitle->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - mTypeGroup = new QGroupBox(this); QGridLayout *groupLayout = new QGridLayout(mTypeGroup); @@ -52,7 +35,6 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum QHBoxLayout *mainLayout = new QHBoxLayout(this); mainLayout->setSizeConstraint(QLayout::SetNoConstraint); - mainLayout->addWidget(mCommandTitle); mainLayout->addWidget(mTypeGroup); mainLayout->addWidget(mPerformButton); mainLayout->addWidget(mCancelButton); @@ -64,9 +46,7 @@ void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandC mMode = mode; if (mMode != Mode_None) { - QString title = (mMode == Mode_Delete) ? "Extended Delete" : "Extended Revert"; - title.append(" from:"); - mCommandTitle->setText(title); + mPerformButton->setText((mMode == Mode_Delete) ? "Extended Delete" : "Extended Revert"); mCommandDispatcher->setSelection(selectedIds); setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); setupGroupLayout(); diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 6a5e1e2e7..9ed16aa1e 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -36,7 +36,6 @@ namespace CSVWorld QPushButton *mPerformButton; QPushButton *mCancelButton; - QLabel *mCommandTitle; QGroupBox *mTypeGroup; CheckBoxMap mTypeCheckBoxes; int mNumUsedCheckBoxes; From ff3c9a6fb28bcddfdc73da2b0a3eaa23e8ffd0b0 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 3 Jul 2015 23:35:00 +0300 Subject: [PATCH 016/419] ExtendedCommandConfigurator: the perform button is now the default for the widget --- apps/opencs/view/world/extendedcommandconfigurator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index 36bff7d59..85c5a2bda 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -20,6 +20,7 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); mPerformButton = new QPushButton(this); + mPerformButton->setDefault(true); mPerformButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(mPerformButton, SIGNAL(clicked(bool)), this, SLOT(performExtendedCommand())); From 1f826476ff6fc3627c9968cc78912d3dde087b1b Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 02:02:22 +0300 Subject: [PATCH 017/419] Fix build error --- apps/opencs/view/world/extendedcommandconfigurator.cpp | 1 - apps/opencs/view/world/extendedcommandconfigurator.hpp | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index 85c5a2bda..d3b97b127 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -7,7 +7,6 @@ #include #include "../../model/world/commanddispatcher.hpp" -#include "../../model/world/universalid.hpp" CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Document &document, const CSMWorld::UniversalId &id, diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 9ed16aa1e..590cabab1 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -5,6 +5,8 @@ #include +#include "../../model/world/universalid.hpp" + class QPushButton; class QGroupBox; class QCheckBox; @@ -19,7 +21,6 @@ namespace CSMDoc namespace CSMWorld { class CommandDispatcher; - class UniversalId; } namespace CSVWorld From 880bc31ddf0bb287aff8252e9b04eb17d26236b4 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 20:30:02 +0300 Subject: [PATCH 018/419] TableBottomBox: Creator/Configurator can be closed via Escape --- apps/opencs/view/world/tablebottombox.cpp | 18 ++++++++++++++++++ apps/opencs/view/world/tablebottombox.hpp | 2 ++ 2 files changed, 20 insertions(+) diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index 3a7fa8e8a..d02b76fdc 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "creator.hpp" @@ -92,6 +94,7 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto if (mCreator) { + mCreator->installEventFilter(this); mLayout->addWidget (mCreator); connect (mCreator, SIGNAL (done()), this, SLOT (requestDone())); @@ -101,6 +104,7 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto } mExtendedConfigurator = new ExtendedCommandConfigurator (document, id, this); + mExtendedConfigurator->installEventFilter(this); mLayout->addWidget (mExtendedConfigurator); connect (mExtendedConfigurator, SIGNAL (done()), this, SLOT (requestDone())); @@ -118,6 +122,20 @@ CSVWorld::TableBottomBox::~TableBottomBox() delete mCreator; } +bool CSVWorld::TableBottomBox::eventFilter(QObject *object, QEvent *event) +{ + if (event->type() == QEvent::KeyPress) + { + QKeyEvent *keyEvent = static_cast(event); + if (keyEvent->key() == Qt::Key_Escape) + { + requestDone(); + return true; + } + } + return QWidget::eventFilter(object, event); +} + void CSVWorld::TableBottomBox::setStatusBar (bool show) { if (show!=mShowStatusBar) diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index 15ae2924c..a24844890 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -59,6 +59,8 @@ namespace CSVWorld virtual ~TableBottomBox(); + virtual bool eventFilter(QObject *object, QEvent *event); + void setEditLock (bool locked); void setStatusBar (bool show); From 4fbd24206b49e4dd981caaae47d3f39b62edeb97 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 4 Jul 2015 20:47:10 +0300 Subject: [PATCH 019/419] ExtendedCommandConfigurator: layout changes --- apps/opencs/view/world/extendedcommandconfigurator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index d3b97b127..b9b2fa10c 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -30,11 +30,12 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mTypeGroup = new QGroupBox(this); QGridLayout *groupLayout = new QGridLayout(mTypeGroup); - groupLayout->setAlignment(Qt::AlignCenter); + groupLayout->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); mTypeGroup->setLayout(groupLayout); QHBoxLayout *mainLayout = new QHBoxLayout(this); mainLayout->setSizeConstraint(QLayout::SetNoConstraint); + mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->addWidget(mTypeGroup); mainLayout->addWidget(mPerformButton); mainLayout->addWidget(mCancelButton); From 9a02a85a244fc5738dd12de0307256ff81285c47 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:07:14 +1200 Subject: [PATCH 020/419] Pulled duplicate code into function. --- apps/openmw/mwmechanics/aiwander.cpp | 24 +++++++++++------------- apps/openmw/mwmechanics/aiwander.hpp | 3 +++ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index f32636b23..3c69a2f5e 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -498,14 +498,8 @@ namespace MWMechanics { assert(mAllowedNodes.size()); unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); - // NOTE: initially constructed with local (i.e. cell) co-ordinates - // convert dest to use world co-ordinates ESM::Pathgrid::Point dest(mAllowedNodes[randNode]); - if (currentCell->getCell()->isExterior()) - { - dest.mX += currentCell->getCell()->mData.mX * ESM::Land::REAL_SIZE; - dest.mY += currentCell->getCell()->mData.mY * ESM::Land::REAL_SIZE; - } + ToWorldCoordinates(dest, currentCell->getCell()); // actor position is already in world co-ordinates ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); @@ -537,6 +531,15 @@ namespace MWMechanics return false; // AiWander package not yet completed } + void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell) + { + if (cell->isExterior()) + { + point.mX += cell->mData.mX * ESM::Land::REAL_SIZE; + point.mY += cell->mData.mY * ESM::Land::REAL_SIZE; + } + } + void AiWander::trimAllowedNodes(std::vector& nodes, const PathFinder& pathfinder) { @@ -643,12 +646,7 @@ namespace MWMechanics // apply a slight offset to prevent overcrowding dest.mX += static_cast(Misc::Rng::rollProbability() * 128 - 64); dest.mY += static_cast(Misc::Rng::rollProbability() * 128 - 64); - - if (actor.getCell()->isExterior()) - { - dest.mX += actor.getCell()->getCell()->mData.mX * ESM::Land::REAL_SIZE; - dest.mY += actor.getCell()->getCell()->mData.mY * ESM::Land::REAL_SIZE; - } + ToWorldCoordinates(dest, actor.getCell()->getCell()); MWBase::Environment::get().getWorld()->moveObject(actor, static_cast(dest.mX), static_cast(dest.mY), static_cast(dest.mZ)); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 75b223094..d69a72585 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -118,6 +118,9 @@ namespace MWMechanics GroupIndex_MaxIdle = 9 }; + /// convert point from local (i.e. cell) to world co-ordinates + void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell); + /// lookup table for converting idleSelect value to groupName static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; }; From f942db2b2761483b9e262fbdfd50302f9c2903b5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:08:09 +1200 Subject: [PATCH 021/419] Simplified code. --- apps/openmw/mwmechanics/aiwander.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 3c69a2f5e..1567f48f6 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -682,19 +682,14 @@ namespace MWMechanics // ... pathgrids don't usually include water, so swimmers ignore them if (mDistance && !actor.getClass().isPureWaterCreature(actor)) { - float cellXOffset = 0; - float cellYOffset = 0; + // get NPC's position in local (i.e. cell) co-ordinates + osg::Vec3f npcPos(mInitialActorPosition); if(cell->isExterior()) { - cellXOffset = static_cast(cell->mData.mX * ESM::Land::REAL_SIZE); - cellYOffset = static_cast(cell->mData.mY * ESM::Land::REAL_SIZE); + npcPos[0] = npcPos[0] - static_cast(cell->mData.mX * ESM::Land::REAL_SIZE); + npcPos[1] = npcPos[1] - static_cast(cell->mData.mY * ESM::Land::REAL_SIZE); } - // convert npcPos to local (i.e. cell) co-ordinates - osg::Vec3f npcPos(mInitialActorPosition); - npcPos[0] = npcPos[0] - cellXOffset; - npcPos[1] = npcPos[1] - cellYOffset; - // mAllowedNodes for this actor with pathgrid point indexes based on mDistance // NOTE: mPoints and mAllowedNodes are in local co-ordinates for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) From 0095737c407e9513cea0b294338ce84807be8704 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:09:14 +1200 Subject: [PATCH 022/419] Use correct type of variable. Remove unnecessary casts. --- apps/openmw/mwmechanics/pathgrid.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 4e9bc8904..66af864ea 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -313,27 +313,27 @@ namespace MWMechanics return path; // for some reason couldn't build a path // reconstruct path to return, using world co-ordinates - float xCell = 0; - float yCell = 0; + int xCell = 0; + int yCell = 0; if (mIsExterior) { - xCell = static_cast(mPathgrid->mData.mX * ESM::Land::REAL_SIZE); - yCell = static_cast(mPathgrid->mData.mY * ESM::Land::REAL_SIZE); + xCell = mPathgrid->mData.mX * ESM::Land::REAL_SIZE; + yCell = mPathgrid->mData.mY * ESM::Land::REAL_SIZE; } while(graphParent[current] != -1) { ESM::Pathgrid::Point pt = mPathgrid->mPoints[current]; - pt.mX += static_cast(xCell); - pt.mY += static_cast(yCell); + pt.mX += xCell; + pt.mY += yCell; path.push_front(pt); current = graphParent[current]; } // add first node to path explicitly ESM::Pathgrid::Point pt = mPathgrid->mPoints[start]; - pt.mX += static_cast(xCell); - pt.mY += static_cast(yCell); + pt.mX += xCell; + pt.mY += yCell; path.push_front(pt); return path; } From 76f20b8b2024ca59ba0349f9c9988c4abafa81fb Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:10:02 +1200 Subject: [PATCH 023/419] fix 'WIN32_LEAN_AND_MEAN' macro redefinition warning. --- apps/openmw/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index dc58daed9..85a0dbe55 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -14,7 +14,9 @@ #if defined(_WIN32) // For OutputDebugString +#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN +#endif #include // makes __argc and __argv available on windows #include From eb2aa965b9fece4dbae0b414e0a737a8ca6e43f5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:17:18 +1200 Subject: [PATCH 024/419] Extracted function SetCurrentNodeToClosestAllowedNode() --- apps/openmw/mwmechanics/aiwander.cpp | 33 ++++++++++++++++++---------- apps/openmw/mwmechanics/aiwander.hpp | 2 ++ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 1567f48f6..6f2c6969c 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -1,5 +1,7 @@ #include "aiwander.hpp" +#include + #include #include @@ -700,23 +702,30 @@ namespace MWMechanics } if(!mAllowedNodes.empty()) { - osg::Vec3f firstNodePos(PathFinder::MakeOsgVec3(mAllowedNodes[0])); - float closestNode = (npcPos - firstNodePos).length2(); - unsigned int index = 0; - for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++) - { - osg::Vec3f nodePos(PathFinder::MakeOsgVec3(mAllowedNodes[counterThree])); - float tempDist = (npcPos - nodePos).length2(); - if(tempDist < closestNode) - index = counterThree; - } - mCurrentNode = mAllowedNodes[index]; - mAllowedNodes.erase(mAllowedNodes.begin() + index); + SetCurrentNodeToClosestAllowedNode(npcPos); } mStoredAvailableNodes = true; // set only if successful in finding allowed nodes } } + void AiWander::SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos) + { + float distanceToClosestNode = FLT_MAX; + unsigned int index = 0; + for (unsigned int counterThree = 0; counterThree < mAllowedNodes.size(); counterThree++) + { + osg::Vec3f nodePos(PathFinder::MakeOsgVec3(mAllowedNodes[counterThree])); + float tempDist = (npcPos - nodePos).length2(); + if (tempDist < distanceToClosestNode) + { + index = counterThree; + distanceToClosestNode = tempDist; + } + } + mCurrentNode = mAllowedNodes[index]; + mAllowedNodes.erase(mAllowedNodes.begin() + index); + } + void AiWander::writeState(ESM::AiSequence::AiSequence &sequence) const { std::auto_ptr wander(new ESM::AiSequence::AiWander()); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index d69a72585..94758afc8 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -121,6 +121,8 @@ namespace MWMechanics /// convert point from local (i.e. cell) to world co-ordinates void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell); + void SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos); + /// lookup table for converting idleSelect value to groupName static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; }; From 1239667cb415835d2d4cb6f3aba941c92e4fecaa Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 5 Jul 2015 18:21:35 +1200 Subject: [PATCH 025/419] AiWander uses points between PathGrid points (Fixes #1317) When there is only on PathGrid point within a NPC's wander distance, expand possible wander destinations by using positions between PathGrid points. --- apps/openmw/mwmechanics/aiwander.cpp | 44 ++++++++++++++++++++++++- apps/openmw/mwmechanics/aiwander.hpp | 4 +++ apps/openmw/mwmechanics/pathfinding.hpp | 4 ++- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 6f2c6969c..25ed4694b 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -216,7 +216,7 @@ namespace MWMechanics // Are we there yet? bool& chooseAction = storage.mChooseAction; if(walking && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], 64.f)) + storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1])) { stopWalking(actor, storage); moveNow = false; @@ -694,11 +694,19 @@ namespace MWMechanics // mAllowedNodes for this actor with pathgrid point indexes based on mDistance // NOTE: mPoints and mAllowedNodes are in local co-ordinates + int pointIndex = 0; for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) { osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter])); if((npcPos - nodePos).length2() <= mDistance * mDistance) + { mAllowedNodes.push_back(pathgrid->mPoints[counter]); + pointIndex = counter; + } + } + if (mAllowedNodes.size() == 1) + { + AddNonPathGridAllowedPoints(npcPos, pathgrid, pointIndex); } if(!mAllowedNodes.empty()) { @@ -708,6 +716,40 @@ namespace MWMechanics } } + // When only one path grid point in wander distance, + // additional points for NPC to wander to are: + // 1. NPC's initial location + // 2. Partway along the path between the point and its connected points. + void AiWander::AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex) + { + mAllowedNodes.push_back(PathFinder::MakePathgridPoint(npcPos)); + for (std::vector::const_iterator it = pathGrid->mEdges.begin(); it != pathGrid->mEdges.end(); ++it) + { + if (it->mV0 == pointIndex) + { + AddPointBetweenPathGridPoints(pathGrid->mPoints[it->mV0], pathGrid->mPoints[it->mV1]); + } + } + } + + void AiWander::AddPointBetweenPathGridPoints(const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end) + { + osg::Vec3f vectorStart = PathFinder::MakeOsgVec3(start); + osg::Vec3f delta = PathFinder::MakeOsgVec3(end) - vectorStart; + float length = delta.length(); + delta.normalize(); + + // destination must be far enough away that NPC will need to move to get there. + const int threshold = PathFinder::PathTolerance * 2; + int distance = std::max(mDistance / 2, threshold); + + // must not travel more than 1/2 way between waypoints, + // otherwise, NPC goes to far endpoint then comes back. Looks weird. + distance = std::min(distance, static_cast(length / 2)); + delta *= distance; + mAllowedNodes.push_back(PathFinder::MakePathgridPoint(vectorStart + delta)); + } + void AiWander::SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos) { float distanceToClosestNode = FLT_MAX; diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 94758afc8..18f98cfd5 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -123,6 +123,10 @@ namespace MWMechanics void SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos); + void AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex); + + void AddPointBetweenPathGridPoints(const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end); + /// lookup table for converting idleSelect value to groupName static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; }; diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 45d9dd973..a4886a840 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -19,6 +19,8 @@ namespace MWMechanics public: PathFinder(); + static const int PathTolerance = 32; + static float sgn(float val) { if(val > 0) @@ -35,7 +37,7 @@ namespace MWMechanics void clearPath(); - bool checkPathCompleted(float x, float y, float tolerance=32.f); + bool checkPathCompleted(float x, float y, float tolerance = PathTolerance); ///< \Returns true if we are within \a tolerance units of the last path point. /// In degrees From ceb3dea55cc70d3518d1253b00ff45ecc21ffc5f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 5 Jul 2015 20:11:21 +0300 Subject: [PATCH 026/419] Rewording of the user setting for extended configuration --- apps/opencs/model/settings/usersettings.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index cb001fea9..05b06d562 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -217,10 +217,13 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() jumpToAdded->setDeclaredValues (jumpValues); Setting *extendedConfig = createSetting (Type_CheckBox, "extended-config", - "Enable configuration of the extended delete/revert"); + "Manually specify affected record types for an extended delete/revert"); extendedConfig->setDefaultValue("false"); - extendedConfig->setToolTip("Enables the ability to specify tables that will be affected by " - "the extended delete/revert command"); + extendedConfig->setToolTip("Delete and revert commands have an extended form that also affects " + "associated records.\n\n" + "If this option is enabled, types of affected records are selected " + "manually before a command execution.\nOtherwise, all associated " + "records are deleted/reverted immediately."); } declareSection ("report-input", "Report Input"); From 3c6bc7406219e1fec46fe79fa9fde76a7dc999c5 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 5 Jul 2015 22:10:37 +0300 Subject: [PATCH 027/419] Close the extended configurator when all respective records were removed outside --- .../world/extendedcommandconfigurator.cpp | 40 ++++++++++++++++++- .../world/extendedcommandconfigurator.hpp | 4 ++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index b9b2fa10c..d243ff256 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -1,12 +1,17 @@ #include "extendedcommandconfigurator.hpp" +#include + #include #include #include #include #include +#include "../../model/doc/document.hpp" + #include "../../model/world/commanddispatcher.hpp" +#include "../../model/world/data.hpp" CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Document &document, const CSMWorld::UniversalId &id, @@ -14,10 +19,13 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum : QWidget(parent), mNumUsedCheckBoxes(0), mNumChecked(0), - mMode(Mode_None) + mMode(Mode_None), + mData(document.getData()) { mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); + connect(&mData, SIGNAL(idListChanged()), this, SLOT(dataIdListChanged())); + mPerformButton = new QPushButton(this); mPerformButton->setDefault(true); mPerformButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); @@ -48,7 +56,8 @@ void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandC if (mMode != Mode_None) { mPerformButton->setText((mMode == Mode_Delete) ? "Extended Delete" : "Extended Revert"); - mCommandDispatcher->setSelection(selectedIds); + mSelectedIds = selectedIds; + mCommandDispatcher->setSelection(mSelectedIds); setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); setupGroupLayout(); } @@ -177,3 +186,30 @@ void CSVWorld::ExtendedCommandConfigurator::checkBoxStateChanged(int state) mPerformButton->setEnabled(mNumChecked > 0); } + +void CSVWorld::ExtendedCommandConfigurator::dataIdListChanged() +{ + bool idsRemoved = false; + for (int i = 0; i < static_cast(mSelectedIds.size()); ++i) + { + if (!mData.hasId(mSelectedIds[i])) + { + std::swap(mSelectedIds[i], mSelectedIds.back()); + mSelectedIds.pop_back(); + idsRemoved = true; + --i; + } + } + + // If all selected IDs were removed, cancel the configurator + if (mSelectedIds.empty()) + { + emit done(); + return; + } + + if (idsRemoved) + { + mCommandDispatcher->setSelection(mSelectedIds); + } +} diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 590cabab1..2e06e9c9c 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -21,6 +21,7 @@ namespace CSMDoc namespace CSMWorld { class CommandDispatcher; + class Data; } namespace CSVWorld @@ -44,6 +45,8 @@ namespace CSVWorld Mode mMode; CSMWorld::CommandDispatcher *mCommandDispatcher; + CSMWorld::Data &mData; + std::vector mSelectedIds; void setupGroupLayout(); void setupCheckBoxes(const std::vector &types); @@ -61,6 +64,7 @@ namespace CSVWorld private slots: void performExtendedCommand(); void checkBoxStateChanged(int state); + void dataIdListChanged(); signals: void done(); From 47d21ff4b34c1192746ba7533d6c0815e7afc194 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 5 Jul 2015 22:49:48 +0300 Subject: [PATCH 028/419] Add edit locking to ExtendedCommandConfigurator --- .../world/extendedcommandconfigurator.cpp | 26 ++++++++++++++++++- .../world/extendedcommandconfigurator.hpp | 4 +++ apps/opencs/view/world/tablebottombox.cpp | 1 + 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/extendedcommandconfigurator.cpp b/apps/opencs/view/world/extendedcommandconfigurator.cpp index d243ff256..2cf6222a6 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.cpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.cpp @@ -20,7 +20,8 @@ CSVWorld::ExtendedCommandConfigurator::ExtendedCommandConfigurator(CSMDoc::Docum mNumUsedCheckBoxes(0), mNumChecked(0), mMode(Mode_None), - mData(document.getData()) + mData(document.getData()), + mEditLock(false) { mCommandDispatcher = new CSMWorld::CommandDispatcher(document, id, this); @@ -58,8 +59,19 @@ void CSVWorld::ExtendedCommandConfigurator::configure(CSVWorld::ExtendedCommandC mPerformButton->setText((mMode == Mode_Delete) ? "Extended Delete" : "Extended Revert"); mSelectedIds = selectedIds; mCommandDispatcher->setSelection(mSelectedIds); + setupCheckBoxes(mCommandDispatcher->getExtendedTypes()); setupGroupLayout(); + lockWidgets(mEditLock); + } +} + +void CSVWorld::ExtendedCommandConfigurator::setEditLock(bool locked) +{ + if (mEditLock != locked) + { + mEditLock = locked; + lockWidgets(mEditLock); } } @@ -144,6 +156,18 @@ void CSVWorld::ExtendedCommandConfigurator::setupCheckBoxes(const std::vectorsetEnabled(!mEditLock && mNumChecked > 0); + + CheckBoxMap::const_iterator current = mTypeCheckBoxes.begin(); + CheckBoxMap::const_iterator end = mTypeCheckBoxes.end(); + for (int i = 0; current != end && i < mNumUsedCheckBoxes; ++current, ++i) + { + current->first->setEnabled(!mEditLock); + } +} + void CSVWorld::ExtendedCommandConfigurator::performExtendedCommand() { std::vector types; diff --git a/apps/opencs/view/world/extendedcommandconfigurator.hpp b/apps/opencs/view/world/extendedcommandconfigurator.hpp index 2e06e9c9c..641b4a524 100644 --- a/apps/opencs/view/world/extendedcommandconfigurator.hpp +++ b/apps/opencs/view/world/extendedcommandconfigurator.hpp @@ -48,8 +48,11 @@ namespace CSVWorld CSMWorld::Data &mData; std::vector mSelectedIds; + bool mEditLock; + void setupGroupLayout(); void setupCheckBoxes(const std::vector &types); + void lockWidgets(bool locked); public: ExtendedCommandConfigurator(CSMDoc::Document &document, @@ -57,6 +60,7 @@ namespace CSVWorld QWidget *parent = 0); void configure(Mode mode, const std::vector &selectedIds); + void setEditLock(bool locked); protected: virtual void resizeEvent(QResizeEvent *event); diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index d02b76fdc..225ff32a4 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -115,6 +115,7 @@ void CSVWorld::TableBottomBox::setEditLock (bool locked) { if (mCreator) mCreator->setEditLock (locked); + mExtendedConfigurator->setEditLock (locked); } CSVWorld::TableBottomBox::~TableBottomBox() From 52cf8541f5d02677a893bfda0542267df1249568 Mon Sep 17 00:00:00 2001 From: dteviot Date: Wed, 8 Jul 2015 18:41:03 +1200 Subject: [PATCH 029/419] End point tolerance restored to 64 units. Corrected problem pointed out by Scrawl. Destination needs tolerance of 64 to avoid overcrowding. --- apps/openmw/mwmechanics/aiwander.cpp | 21 +++++++++++---------- apps/openmw/mwmechanics/aiwander.hpp | 8 ++++++++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 25ed4694b..31687edf2 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -216,7 +216,7 @@ namespace MWMechanics // Are we there yet? bool& chooseAction = storage.mChooseAction; if(walking && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1])) + storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DestinationTolerance)) { stopWalking(actor, storage); moveNow = false; @@ -645,9 +645,8 @@ namespace MWMechanics int index = Misc::Rng::rollDice(mAllowedNodes.size()); ESM::Pathgrid::Point dest = mAllowedNodes[index]; - // apply a slight offset to prevent overcrowding - dest.mX += static_cast(Misc::Rng::rollProbability() * 128 - 64); - dest.mY += static_cast(Misc::Rng::rollProbability() * 128 - 64); + dest.mX += OffsetToPreventOvercrowding(); + dest.mY += OffsetToPreventOvercrowding(); ToWorldCoordinates(dest, actor.getCell()->getCell()); MWBase::Environment::get().getWorld()->moveObject(actor, static_cast(dest.mX), @@ -658,6 +657,11 @@ namespace MWMechanics mStoredAvailableNodes = false; } + int AiWander::OffsetToPreventOvercrowding() + { + return static_cast(DestinationTolerance * (Misc::Rng::rollProbability() * 2.0f - 1.0f)); + } + void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell) { if (!mStoredInitialActorPosition) @@ -739,13 +743,10 @@ namespace MWMechanics float length = delta.length(); delta.normalize(); - // destination must be far enough away that NPC will need to move to get there. - const int threshold = PathFinder::PathTolerance * 2; - int distance = std::max(mDistance / 2, threshold); + int distance = std::max(mDistance / 2, MinimumWanderDistance); - // must not travel more than 1/2 way between waypoints, - // otherwise, NPC goes to far endpoint then comes back. Looks weird. - distance = std::min(distance, static_cast(length / 2)); + // must not travel longer than distance between waypoints or NPC goes past waypoint + distance = std::min(distance, static_cast(length)); delta *= distance; mAllowedNodes.push_back(PathFinder::MakePathgridPoint(vectorStart + delta)); } diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 18f98cfd5..c15ec7c3c 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -118,6 +118,12 @@ namespace MWMechanics GroupIndex_MaxIdle = 9 }; + // to prevent overcrowding + static const int DestinationTolerance = 64; + + // distance must be long enough that NPC will need to move to get there. + static const int MinimumWanderDistance = DestinationTolerance * 2; + /// convert point from local (i.e. cell) to world co-ordinates void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell); @@ -129,6 +135,8 @@ namespace MWMechanics /// lookup table for converting idleSelect value to groupName static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; + + static int OffsetToPreventOvercrowding(); }; From f1774ee7c37b89ad03508fa040b482d0662aee6b Mon Sep 17 00:00:00 2001 From: dteviot Date: Wed, 8 Jul 2015 19:34:33 +1200 Subject: [PATCH 030/419] Fixed compile failing on OSX and Linux. --- apps/openmw/mwmechanics/aiwander.cpp | 12 +++++++++--- apps/openmw/mwmechanics/aiwander.hpp | 6 ------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 31687edf2..4aef8f8ba 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -30,6 +30,12 @@ namespace MWMechanics static const int GREETING_SHOULD_START = 4; //how many reaction intervals should pass before NPC can greet player static const int GREETING_SHOULD_END = 10; + // to prevent overcrowding + static const int DESTINATION_TOLERANCE = 64; + + // distance must be long enough that NPC will need to move to get there. + static const int MINIMUM_WANDER_DISTANCE = DESTINATION_TOLERANCE * 2; + const std::string AiWander::sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1] = { std::string("idle2"), @@ -216,7 +222,7 @@ namespace MWMechanics // Are we there yet? bool& chooseAction = storage.mChooseAction; if(walking && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DestinationTolerance)) + storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) { stopWalking(actor, storage); moveNow = false; @@ -659,7 +665,7 @@ namespace MWMechanics int AiWander::OffsetToPreventOvercrowding() { - return static_cast(DestinationTolerance * (Misc::Rng::rollProbability() * 2.0f - 1.0f)); + return static_cast(DESTINATION_TOLERANCE * (Misc::Rng::rollProbability() * 2.0f - 1.0f)); } void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell) @@ -743,7 +749,7 @@ namespace MWMechanics float length = delta.length(); delta.normalize(); - int distance = std::max(mDistance / 2, MinimumWanderDistance); + int distance = std::max(mDistance / 2, MINIMUM_WANDER_DISTANCE); // must not travel longer than distance between waypoints or NPC goes past waypoint distance = std::min(distance, static_cast(length)); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index c15ec7c3c..926017b46 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -118,12 +118,6 @@ namespace MWMechanics GroupIndex_MaxIdle = 9 }; - // to prevent overcrowding - static const int DestinationTolerance = 64; - - // distance must be long enough that NPC will need to move to get there. - static const int MinimumWanderDistance = DestinationTolerance * 2; - /// convert point from local (i.e. cell) to world co-ordinates void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell); From 3a0293480e73b29a2548b76ea3da5ecf8e2cbab9 Mon Sep 17 00:00:00 2001 From: Scott Howard Date: Thu, 9 Jul 2015 15:32:15 -0400 Subject: [PATCH 031/419] Update boost in travis-ci to fix build failure --- CI/before_install.linux.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 2408a5822..2efb6e2bb 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -10,9 +10,10 @@ fi echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" echo "yes" | sudo apt-add-repository ppa:openmw/openmw +echo "yes" | sudo apt-add-repository ppa:boost-latest/ppa sudo apt-get update -qq sudo apt-get install -qq libgtest-dev google-mock -sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev +sudo apt-get install -qq libboost-filesystem1.55-dev libboost-program-options1.55-dev libboost-system1.55-dev libboost-thread1.55-dev sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04 From f12619b86a149f17aaa136456d6fd97061fec0f1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 10 Jul 2015 02:34:00 +0200 Subject: [PATCH 032/419] Implement fStromWindSpeed (Fixes #2764) --- apps/openmw/mwworld/weather.cpp | 9 ++++++--- apps/openmw/mwworld/weather.hpp | 4 +++- apps/openmw/mwworld/worldimp.cpp | 6 +++--- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 70d6f1b36..2d2b3e20d 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -66,6 +66,10 @@ void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name weather.mGlareView = mFallback->getFallbackFloat("Weather_"+upper+"_Glare_View"); weather.mCloudTexture = mFallback->getFallbackString("Weather_"+upper+"_Cloud_Texture"); + static const float fStromWindSpeed = mStore->get().find("fStromWindSpeed")->getFloat(); + + weather.mIsStorm = weather.mWindSpeed > fStromWindSpeed; + bool usesPrecip = mFallback->getFallbackBool("Weather_"+upper+"_Using_Precip"); if (usesPrecip) weather.mRainEffect = "meshes\\raindrop.nif"; @@ -79,7 +83,6 @@ Rain Height Max=700 ? Rain Threshold=0.6 ? Max Raindrops=650 ? */ - weather.mIsStorm = (name == "ashstorm" || name == "blight"); mWeatherSettings[name] = weather; } @@ -112,8 +115,8 @@ float WeatherManager::calculateAngleFade (const std::string& moonName, float ang return 1.f; } -WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fallback* fallback) : - mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mFallback(fallback), +WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::Fallback* fallback, MWWorld::ESMStore* store) : + mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mFallback(fallback), mStore(store), mRendering(rendering), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true), mRemainingTransitionTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index d7dfee99b..efe69f17c 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -156,7 +156,8 @@ namespace MWWorld class WeatherManager { public: - WeatherManager(MWRender::RenderingManager*,MWWorld::Fallback* fallback); + // Have to pass fallback and Store, can't use singleton since World isn't fully constructed yet at the time + WeatherManager(MWRender::RenderingManager*, MWWorld::Fallback* fallback, MWWorld::ESMStore* store); ~WeatherManager(); /** @@ -210,6 +211,7 @@ namespace MWWorld std::string mPlayingSoundID; MWWorld::Fallback* mFallback; + MWWorld::ESMStore* mStore; void setFallbackWeather(Weather& weather,const std::string& name); MWRender::RenderingManager* mRendering; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4b14ea602..a2c7c3a79 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -163,8 +163,6 @@ namespace MWWorld mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mPhysics)); mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback); - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); - mEsm.resize(contentFiles.size()); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); listener->loadingOn(); @@ -193,6 +191,8 @@ namespace MWWorld mGlobalVariables.fill (mStore); + mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback,&mStore); + mWorldScene = new Scene(*mRendering, mPhysics); } @@ -265,7 +265,7 @@ namespace MWWorld // we don't want old weather to persist on a new game delete mWeatherManager; mWeatherManager = 0; - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); + mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback,&mStore); if (!mStartupScript.empty()) MWBase::Environment::get().getWindowManager()->executeInConsole(mStartupScript); From 72686c32ae18a1e5afb89478849b15bd4cfcc881 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 10 Jul 2015 03:03:17 +0200 Subject: [PATCH 033/419] Fix runtime exceptions on MyGUI debug builds --- components/myguiplatform/myguirendermanager.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 4979d6451..89d55f5c1 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -523,12 +523,8 @@ void RenderManager::destroyAllResources() bool RenderManager::checkTexture(MyGUI::ITexture* _texture) { - for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item) - { - if (item->second == _texture) - return true; - } - return false; + // We support external textures that aren't registered via this manager, so can't implement this method sensibly. + return true; } } From 12f413ba9b8c6fbbf81af8dd1a6fd4eca193eaaf Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Fri, 10 Jul 2015 20:21:55 +0200 Subject: [PATCH 034/419] Don't instantiate specialized templates This fixes the VS2012 build issue --- apps/openmw/mwworld/store.cpp | 12 ++++++------ apps/openmw/mwworld/store.hpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 96c711896..d873ab468 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1064,11 +1064,11 @@ namespace MWWorld template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; @@ -1082,21 +1082,21 @@ template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; -template class MWWorld::Store; +//template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; template class MWWorld::Store; diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 02fb983cd..3cbd8d3ac 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -319,7 +319,7 @@ namespace MWWorld public: - Store(); + Store(); void setCells(Store& cells); void load(ESM::ESMReader &esm, const std::string &id); From 4b002863c899d22c2a060773e39034a69a7b3e13 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Jul 2015 00:45:11 +0200 Subject: [PATCH 035/419] Re-enabled a few build targets --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cbfc5d489..a0a6f0746 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ addons: name: "OpenMW/openmw" description: "" notification_email: scrawl@baseoftrash.de - build_command_prepend: "cmake . -DBUILD_OPENCS=FALSE -DBUILD_UNITTESTS=FALSE -DBUILD_WIZARD=FALSE -DBUILD_BSATOOL=FALSE -DBUILD_ESMTOOL=FALSE -DBUILD_LAUNCHER=FALSE -DBUILD_MWINIIMPORTER=FALSE" + build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_WIZARD=FALSE -DBUILD_LAUNCHER=FALSE -DBUILD_MWINIIMPORTER=FALSE" build_command: "make" branch_pattern: coverity_scan matrix: From 3d3b37324d95e3e774e00db58d1e5e68e22035cb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Jul 2015 01:38:20 +0200 Subject: [PATCH 036/419] Change build targets again --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a0a6f0746..80277f8ba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ addons: name: "OpenMW/openmw" description: "" notification_email: scrawl@baseoftrash.de - build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_WIZARD=FALSE -DBUILD_LAUNCHER=FALSE -DBUILD_MWINIIMPORTER=FALSE" + build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_OPENCS=FALSE" build_command: "make" branch_pattern: coverity_scan matrix: From ebdd5dc9939b40aa3503b37dc9785b8206f810b1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Jul 2015 03:06:53 +0200 Subject: [PATCH 037/419] Fix code that I forgot to uncomment (thanks coverity) --- apps/openmw/mwrender/npcanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 6252d392b..fc1a19391 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -459,7 +459,7 @@ void NpcAnimation::updateParts() }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); - bool wasArrowAttached = 0;//(mAmmunition.get() != NULL); + bool wasArrowAttached = (mAmmunition.get() != NULL); MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) From 667c80fb2acc4809493fc912e82a72e66797b461 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Jul 2015 03:09:50 +0200 Subject: [PATCH 038/419] Add brackets around a correct expression to fix coverity warning --- apps/openmw/mwrender/npcanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index fc1a19391..6417bc812 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -622,7 +622,7 @@ void NpcAnimation::updateParts() continue; } - if (!mNpc->isMale() != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) + if ((!mNpc->isMale()) != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) { // Allow opposite gender's parts as fallback if parts for our gender are missing BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart)); From 24ae1d5acea04696ee3eec79c15ec0de90a49345 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Jul 2015 03:33:31 +0200 Subject: [PATCH 039/419] Fix some issues found by coverity --- apps/essimporter/importer.cpp | 15 +++++++++++++++ apps/essimporter/importercontext.hpp | 4 ++++ apps/openmw/mwdialogue/filter.cpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 3 +++ apps/openmw/mwrender/ripplesimulation.hpp | 1 - components/myguiplatform/myguirendermanager.cpp | 2 +- components/nifosg/controller.cpp | 3 ++- 7 files changed, 27 insertions(+), 3 deletions(-) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 32ad1816c..27b70a06e 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -166,7 +166,9 @@ namespace ESSImport if (i >= file2.mRecords.size()) { + std::ios::fmtflags f(std::cout.flags()); std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset << std::endl; + std::cout.flags(f); return; } @@ -174,7 +176,9 @@ namespace ESSImport if (rec.mName != rec2.mName) { + std::ios::fmtflags f(std::cout.flags()); std::cout << "Different record name at (2) 0x" << std::hex << rec2.mFileOffset << std::endl; + std::cout.flags(f); return; // TODO: try to recover } @@ -185,7 +189,9 @@ namespace ESSImport if (j >= rec2.mSubrecords.size()) { + std::ios::fmtflags f(std::cout.flags()); std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset << std::endl; + std::cout.flags(f); return; } @@ -193,8 +199,10 @@ namespace ESSImport if (sub.mName != sub2.mName) { + std::ios::fmtflags f(std::cout.flags()); std::cout << "Different subrecord name (" << rec.mName << "." << sub.mName << " vs. " << sub2.mName << ") at (1) 0x" << std::hex << sub.mFileOffset << " (2) 0x" << sub2.mFileOffset << std::endl; + std::cout.flags(f); break; // TODO: try to recover } @@ -203,6 +211,8 @@ namespace ESSImport if (blacklist.find(std::make_pair(rec.mName, sub.mName)) != blacklist.end()) continue; + std::ios::fmtflags f(std::cout.flags()); + std::cout << "Different subrecord data for " << rec.mName << "." << sub.mName << " at (1) 0x" << std::hex << sub.mFileOffset << " (2) 0x" << sub2.mFileOffset << std::endl; @@ -235,6 +245,7 @@ namespace ESSImport std::cout << "\033[0m"; } std::cout << std::endl; + std::cout.flags(f); } } } @@ -319,7 +330,11 @@ namespace ESSImport else { if (unknownRecords.insert(n.val).second) + { + std::ios::fmtflags f(std::cout.flags()); std::cerr << "unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl; + std::cout.flags(f); + } esm.skipRecord(); } diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 3b010cb8f..c93dff269 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -49,6 +49,10 @@ namespace ESSImport std::map mNpcs; Context() + : mDay(0) + , mMonth(0) + , mYear(0) + , mHour(0.f) { mPlayer.mAutoMove = 0; ESM::CellId playerCellId; diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index adb7d3892..29fac1c67 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -203,6 +203,8 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c return false; // script does not have a variable of this name. int index = localDefs.getIndex (name); + if (index < 0) + return false; // shouldn't happen, we checked that variable has a type above, so must exist const MWScript::Locals& locals = mActor.getRefData().getLocals(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9cf957522..582519b19 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -896,6 +896,9 @@ namespace MWGui void WindowManager::updateMap() { + if (!mLocalMapRender) + return; + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); osg::Vec3f playerPosition = player.getRefData().getPosition().asVec3(); diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 8e591a5db..1717cca57 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -59,7 +59,6 @@ namespace MWRender private: osg::ref_ptr mParent; - Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mParticleSystem; osg::ref_ptr mParticleNode; diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 89d55f5c1..160d659bd 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -119,7 +119,7 @@ class Drawable : public osg::Drawable { // VBOs disabled due to crash in OSG: http://forum.openscenegraph.org/viewtopic.php?t=14909 osg::GLBufferObject* bufferobject = 0;//state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0; - if (bufferobject) + if (0)//bufferobject) { state->bindVertexBufferObject(bufferobject); diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 5e7e55004..83ecc0fa9 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -407,7 +407,8 @@ FlipController::FlipController(int texSlot, float delta, std::vector Date: Sat, 11 Jul 2015 04:27:35 +0200 Subject: [PATCH 040/419] Fix cout/cerr mixup --- apps/essimporter/importer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 27b70a06e..624241039 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -331,9 +331,9 @@ namespace ESSImport { if (unknownRecords.insert(n.val).second) { - std::ios::fmtflags f(std::cout.flags()); + std::ios::fmtflags f(std::cerr.flags()); std::cerr << "unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl; - std::cout.flags(f); + std::cerr.flags(f); } esm.skipRecord(); From b97a4cee44676ec44934dac69b1e16d2370492c1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 11 Jul 2015 16:09:13 +0200 Subject: [PATCH 041/419] added button bar to script subview --- apps/opencs/view/world/scriptsubview.cpp | 61 ++++++++++++++++++------ apps/opencs/view/world/scriptsubview.hpp | 7 +++ 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 411eb3660..dc079c3a9 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -15,26 +15,20 @@ #include "../../model/settings/usersettings.hpp" #include "scriptedit.hpp" +#include "recordbuttonbar.hpp" CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mStatus(0) +: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mStatus(0), + mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) { + std::vector selection (1, id.getId()); + mCommandDispatcher.setSelection (selection); + QVBoxLayout *layout = new QVBoxLayout; - layout->setContentsMargins (QMargins (0, 0, 0, 0)); - mBottom = new QWidget(this); - QStackedLayout *bottmLayout = new QStackedLayout(mBottom); - bottmLayout->setContentsMargins (0, 0, 0, 0); - QStatusBar *statusBar = new QStatusBar(mBottom); - mStatus = new QLabel(mBottom); - statusBar->addWidget (mStatus); - bottmLayout->addWidget (statusBar); - mBottom->setLayout (bottmLayout); + layout->addWidget (mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this), 2); - layout->addWidget (mBottom, 0); - layout->insertWidget (0, mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this), 2); - - QWidget *widget = new QWidget; + QWidget *widget = new QWidget (this);; widget->setLayout (layout); setWidget (widget); @@ -54,6 +48,25 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString()); + // buttons + mButtons = new RecordButtonBar (id, *mModel, 0, &mCommandDispatcher, this); + + layout->addWidget (mButtons); + + // status bar + QStatusBar *statusBar = new QStatusBar(mBottom); + mStatus = new QLabel(mBottom); + statusBar->addWidget (mStatus); + + mBottom = new QWidget(this); + QStackedLayout *bottmLayout = new QStackedLayout(mBottom); + bottmLayout->setContentsMargins (0, 0, 0, 0); + bottmLayout->addWidget (statusBar); + mBottom->setLayout (bottmLayout); + + layout->addWidget (mBottom, 0); + + // signals connect (mEditor, SIGNAL (textChanged()), this, SLOT (textChanged())); connect (mModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), @@ -62,6 +75,11 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int))); + connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int))); + + connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), + mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); + updateStatusBar(); connect(mEditor, SIGNAL(cursorPositionChanged()), this, SLOT(updateStatusBar())); } @@ -78,6 +96,8 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr { mEditor->setMonoFont(value.at(0).toStdString() == "true"); } + + mButtons->updateUserSetting (name, value); } void CSVWorld::ScriptSubView::updateStatusBar () @@ -93,6 +113,8 @@ void CSVWorld::ScriptSubView::updateStatusBar () void CSVWorld::ScriptSubView::setEditLock (bool locked) { mEditor->setReadOnly (locked); + mButtons->setEditLock (locked); + mCommandDispatcher.setEditLock (locked); } void CSVWorld::ScriptSubView::useHint (const std::string& hint) @@ -159,3 +181,14 @@ void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, i emit closeRequest(); } +void CSVWorld::ScriptSubView::switchToRow (int row) +{ + int idColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id); + std::string id = mModel->data (mModel->index (row, idColumn)).toString().toUtf8().constData(); + setUniversalId (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Script, id)); + + mEditor->setPlainText (mModel->data (mModel->index (row, mColumn)).toString()); + + std::vector selection (1, id); + mCommandDispatcher.setSelection (selection); +} diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 1c6474e54..0479e6ad8 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -1,6 +1,8 @@ #ifndef CSV_WORLD_SCRIPTSUBVIEW_H #define CSV_WORLD_SCRIPTSUBVIEW_H +#include "../../model/world/commanddispatcher.hpp" + #include "../doc/subview.hpp" class QModelIndex; @@ -19,6 +21,7 @@ namespace CSMWorld namespace CSVWorld { class ScriptEdit; + class RecordButtonBar; class ScriptSubView : public CSVDoc::SubView { @@ -30,6 +33,8 @@ namespace CSVWorld int mColumn; QWidget *mBottom; QLabel *mStatus; + RecordButtonBar *mButtons; + CSMWorld::CommandDispatcher mCommandDispatcher; public: @@ -52,6 +57,8 @@ namespace CSVWorld private slots: void updateStatusBar(); + + void switchToRow (int row); }; } From b508846a644f58264f84fb1a041f56d133260f65 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 16:32:48 +1200 Subject: [PATCH 042/419] Renamed mStoredAvailableNodes to mPopulateAvailableNodes. Don't call getAllowedNodes() needlessly. --- apps/openmw/mwmechanics/aiwander.cpp | 13 +++++++------ apps/openmw/mwmechanics/aiwander.hpp | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 4aef8f8ba..3da02306b 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -117,7 +117,7 @@ namespace MWMechanics mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - mStoredAvailableNodes = false; + mPopulateAvailableNodes = true; } @@ -191,7 +191,7 @@ namespace MWMechanics if(!currentCell || cellChange) { currentCell = actor.getCell(); - mStoredAvailableNodes = false; // prob. not needed since mDistance = 0 + mPopulateAvailableNodes = true; } cStats.setDrawState(DrawState_Nothing); @@ -390,7 +390,7 @@ namespace MWMechanics } // Initialization to discover & store allowed node points for this actor. - if(!mStoredAvailableNodes) + if (mPopulateAvailableNodes) { getAllowedNodes(actor, currentCell->getCell()); } @@ -640,7 +640,7 @@ namespace MWMechanics if (mDistance == 0) return; - if (!mStoredAvailableNodes) + if (mPopulateAvailableNodes) getAllowedNodes(actor, actor.getCell()->getCell()); if (mAllowedNodes.empty()) @@ -660,7 +660,7 @@ namespace MWMechanics actor.getClass().adjustPosition(actor, false); // may have changed cell - mStoredAvailableNodes = false; + mPopulateAvailableNodes = true; } int AiWander::OffsetToPreventOvercrowding() @@ -722,8 +722,9 @@ namespace MWMechanics { SetCurrentNodeToClosestAllowedNode(npcPos); } - mStoredAvailableNodes = true; // set only if successful in finding allowed nodes } + + mPopulateAvailableNodes = false; } // When only one path grid point in wander distance, diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 926017b46..fb1ed0b7e 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -88,8 +88,8 @@ namespace MWMechanics - // if false triggers calculating allowed nodes based on mDistance - bool mStoredAvailableNodes; + // do we need to calculate allowed nodes based on mDistance + bool mPopulateAvailableNodes; From df421fce9265cee142eee278610f927a466b40fb Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 16:35:15 +1200 Subject: [PATCH 043/419] extracted function setPathToAnAllowedNode() --- apps/openmw/mwmechanics/aiwander.cpp | 61 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 3da02306b..17d125209 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -504,41 +504,48 @@ namespace MWMechanics // Construct a new path if there isn't one if(!storage.mPathFinder.isPathConstructed()) { - assert(mAllowedNodes.size()); - unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); - ESM::Pathgrid::Point dest(mAllowedNodes[randNode]); - ToWorldCoordinates(dest, currentCell->getCell()); - - // actor position is already in world co-ordinates - ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); - - // don't take shortcuts for wandering - storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); - - if(storage.mPathFinder.isPathConstructed()) + if (mAllowedNodes.size()) { - // 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); - // check if mCurrentNode was taken out of mAllowedNodes - if(mTrimCurrentNode && mAllowedNodes.size() > 1) - mTrimCurrentNode = false; - else - mAllowedNodes.push_back(mCurrentNode); - mCurrentNode = temp; - - moveNow = false; - walking = true; + setPathToAnAllowedNode(actor, storage, pos); } - // Choose a different node and delete this one from possible nodes because it is uncreachable: - else - mAllowedNodes.erase(mAllowedNodes.begin() + randNode); } } return false; // AiWander package not yet completed } + void AiWander::setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos) + { + unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); + ESM::Pathgrid::Point dest(mAllowedNodes[randNode]); + ToWorldCoordinates(dest, storage.mCell->getCell()); + + // actor position is already in world co-ordinates + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actorPos)); + + // don't take shortcuts for wandering + storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); + + if (storage.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); + // check if mCurrentNode was taken out of mAllowedNodes + if (mTrimCurrentNode && mAllowedNodes.size() > 1) + mTrimCurrentNode = false; + else + mAllowedNodes.push_back(mCurrentNode); + mCurrentNode = temp; + + storage.mMoveNow = false; + storage.mWalking = true; + } + // Choose a different node and delete this one from possible nodes because it is uncreachable: + else + mAllowedNodes.erase(mAllowedNodes.begin() + randNode); + } + void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell) { if (cell->isExterior()) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index fb1ed0b7e..9f68ee171 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -71,6 +71,7 @@ namespace MWMechanics void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); void getRandomIdle(unsigned short& playedIdle); + void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 1ef78b1e568f21638a9c87d11e8813332841a556 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 16:37:31 +1200 Subject: [PATCH 044/419] extracted playGreetingIfPlayerGetsTooClose() --- apps/openmw/mwmechanics/aiwander.cpp | 136 ++++++++++++++------------- apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 72 insertions(+), 65 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 17d125209..753e6ef68 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -432,71 +432,7 @@ namespace MWMechanics // Allow interrupting a walking actor to trigger a greeting if(idleNow || walking) { - // Play a random voice greeting if the player gets too close - int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); - float helloDistance = static_cast(hello); - static int iGreetDistanceMultiplier =MWBase::Environment::get().getWorld()->getStore() - .get().find("iGreetDistanceMultiplier")->getInt(); - - helloDistance *= iGreetDistanceMultiplier; - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - osg::Vec3f playerPos(player.getRefData().getPosition().asVec3()); - osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); - float playerDistSqr = (playerPos - actorPos).length2(); - - int& greetingTimer = storage.mGreetingTimer; - if (greetingState == Greet_None) - { - if ((playerDistSqr <= helloDistance*helloDistance) && - !player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor) - && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor)) - greetingTimer++; - - if (greetingTimer >= GREETING_SHOULD_START) - { - greetingState = Greet_InProgress; - MWBase::Environment::get().getDialogueManager()->say(actor, "hello"); - greetingTimer = 0; - } - } - - if(greetingState == Greet_InProgress) - { - greetingTimer++; - - if(walking) - { - stopWalking(actor, storage); - moveNow = false; - walking = false; - mObstacleCheck.clear(); - idleNow = true; - getRandomIdle(playedIdle); - } - - if(!rotate) - { - osg::Vec3f dir = playerPos - actorPos; - - float faceAngleRadians = std::atan2(dir.x(), dir.y()); - targetAngleRadians = faceAngleRadians; - rotate = true; - } - - if (greetingTimer >= GREETING_SHOULD_END) - { - greetingState = Greet_Done; - greetingTimer = 0; - } - } - - if (greetingState == MWMechanics::AiWander::Greet_Done) - { - float resetDist = 2*helloDistance; - if (playerDistSqr >= resetDist*resetDist) - greetingState = Greet_None; - } + playGreetingIfPlayerGetsTooClose(actor, storage); } if(moveNow && mDistance) @@ -514,6 +450,76 @@ namespace MWMechanics return false; // AiWander package not yet completed } + void AiWander::playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage) + { + // Play a random voice greeting if the player gets too close + int hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified(); + float helloDistance = static_cast(hello); + static int iGreetDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore() + .get().find("iGreetDistanceMultiplier")->getInt(); + + helloDistance *= iGreetDistanceMultiplier; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + osg::Vec3f playerPos(player.getRefData().getPosition().asVec3()); + osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); + float playerDistSqr = (playerPos - actorPos).length2(); + + int& greetingTimer = storage.mGreetingTimer; + GreetingState& greetingState = storage.mSaidGreeting; + if (greetingState == Greet_None) + { + if ((playerDistSqr <= helloDistance*helloDistance) && + !player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor) + && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor)) + greetingTimer++; + + if (greetingTimer >= GREETING_SHOULD_START) + { + greetingState = Greet_InProgress; + MWBase::Environment::get().getDialogueManager()->say(actor, "hello"); + greetingTimer = 0; + } + } + + if (greetingState == Greet_InProgress) + { + greetingTimer++; + + if (storage.mWalking) + { + stopWalking(actor, storage); + storage.mMoveNow = false; + storage.mWalking = false; + mObstacleCheck.clear(); + storage.mIdleNow = true; + getRandomIdle(storage.mPlayedIdle); + } + + if (!storage.mRotate) + { + osg::Vec3f dir = playerPos - actorPos; + + float faceAngleRadians = std::atan2(dir.x(), dir.y()); + storage.mTargetAngleRadians = faceAngleRadians; + storage.mRotate = true; + } + + if (greetingTimer >= GREETING_SHOULD_END) + { + greetingState = Greet_Done; + greetingTimer = 0; + } + } + + if (greetingState == MWMechanics::AiWander::Greet_Done) + { + float resetDist = 2 * helloDistance; + if (playerDistSqr >= resetDist*resetDist) + greetingState = Greet_None; + } + } + void AiWander::setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos) { unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 9f68ee171..0451ec700 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -72,6 +72,7 @@ namespace MWMechanics bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); void getRandomIdle(unsigned short& playedIdle); void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); + void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 0b089a55640f1c1184c68cbea15a63f9303f6e69 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 16:38:36 +1200 Subject: [PATCH 045/419] extracted function evadeObstacles() --- apps/openmw/mwmechanics/aiwander.cpp | 83 +++++++++++++++------------- apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 45 insertions(+), 39 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 753e6ef68..a2388320c 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -239,45 +239,7 @@ namespace MWMechanics zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); actor.getClass().getMovementSettings(actor).mPosition[1] = 1; - // Returns true if evasive action needs to be taken - if(mObstacleCheck.check(actor, duration)) - { - // first check if we're walking into a door - if(proximityToDoor(actor)) // NOTE: checks interior cells only - { - // remove allowed points then select another random destination - mTrimCurrentNode = true; - trimAllowedNodes(mAllowedNodes, storage.mPathFinder); - mObstacleCheck.clear(); - storage.mPathFinder.clearPath(); - walking = false; - moveNow = true; - } - else // probably walking into another NPC - { - // TODO: diagonal should have same animation as walk forward - // but doesn't seem to do that? - actor.getClass().getMovementSettings(actor).mPosition[0] = 1; - actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; - // change the angle a bit, too - zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); - } - mStuckCount++; // TODO: maybe no longer needed - } -//#if 0 - // TODO: maybe no longer needed - if(mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset - { - //std::cout << "Reset \""<< cls.getName(actor) << "\"" << std::endl; - mObstacleCheck.clear(); - - stopWalking(actor, storage); - moveNow = false; - walking = false; - chooseAction = true; - mStuckCount = 0; - } -//#endif + evadeObstacles(actor, storage, duration); } @@ -450,6 +412,49 @@ namespace MWMechanics return false; // AiWander package not yet completed } + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) + { + if (mObstacleCheck.check(actor, duration)) + { + // first check if we're walking into a door + if (proximityToDoor(actor)) // NOTE: checks interior cells only + { + // remove allowed points then select another random destination + mTrimCurrentNode = true; + trimAllowedNodes(mAllowedNodes, storage.mPathFinder); + mObstacleCheck.clear(); + storage.mPathFinder.clearPath(); + storage.mWalking = false; + storage.mMoveNow = true; + } + else // probably walking into another NPC + { + // TODO: diagonal should have same animation as walk forward + // but doesn't seem to do that? + actor.getClass().getMovementSettings(actor).mPosition[0] = 1; + actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; + // change the angle a bit, too + const ESM::Position& pos = actor.getRefData().getPosition(); + zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); + } + mStuckCount++; // TODO: maybe no longer needed + } +//#if 0 + // TODO: maybe no longer needed + if (mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset + { + //std::cout << "Reset \""<< cls.getName(actor) << "\"" << std::endl; + mObstacleCheck.clear(); + + stopWalking(actor, storage); + storage.mMoveNow = false; + storage.mWalking = false; + storage.mChooseAction = true; + mStuckCount = 0; + } +//#endif + } + void AiWander::playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage) { // Play a random voice greeting if the player gets too close diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 0451ec700..5196bca00 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -73,6 +73,7 @@ namespace MWMechanics void getRandomIdle(unsigned short& playedIdle); void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); + void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 22059d68f6e70df4cb3764a0742e172888ab4b53 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 17:14:48 +1200 Subject: [PATCH 046/419] Remove duplicated code. --- apps/openmw/mwmechanics/aiwander.cpp | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index a2388320c..a17f7a1f6 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -225,8 +225,6 @@ namespace MWMechanics storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) { stopWalking(actor, storage); - moveNow = false; - walking = false; chooseAction = true; mHasReturnPosition = false; } @@ -329,17 +327,8 @@ namespace MWMechanics { // End package if duration is complete or mid-night hits: MWWorld::TimeStamp currentTime = world->getTimeStamp(); - if(currentTime.getHour() >= mStartTime.getHour() + mDuration) - { - if(!mRepeat) - { - stopWalking(actor, storage); - return true; - } - else - mStartTime = currentTime; - } - else if(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay()) + if((currentTime.getHour() >= mStartTime.getHour() + mDuration) || + (int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())) { if(!mRepeat) { @@ -447,8 +436,6 @@ namespace MWMechanics mObstacleCheck.clear(); stopWalking(actor, storage); - storage.mMoveNow = false; - storage.mWalking = false; storage.mChooseAction = true; mStuckCount = 0; } @@ -494,8 +481,6 @@ namespace MWMechanics if (storage.mWalking) { stopWalking(actor, storage); - storage.mMoveNow = false; - storage.mWalking = false; mObstacleCheck.clear(); storage.mIdleNow = true; getRandomIdle(storage.mPlayedIdle); @@ -601,6 +586,8 @@ namespace MWMechanics { storage.mPathFinder.clearPath(); actor.getClass().getMovementSettings(actor).mPosition[1] = 0; + storage.mMoveNow = false; + storage.mWalking = false; } void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) From e294cd95cd2cb155c5fede771592fc3c4a7eab11 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 17:15:14 +1200 Subject: [PATCH 047/419] extracted function playIdleDialogueRandomly() --- apps/openmw/mwmechanics/aiwander.cpp | 57 +++++++++++++++------------- apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index a17f7a1f6..1375b5807 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -285,32 +285,7 @@ namespace MWMechanics } } - // Play idle voiced dialogue entries randomly - int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); - if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor) - && MWBase::Environment::get().getSoundManager()->sayDone(actor)) - { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - - static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() - .get().find("fVoiceIdleOdds")->getFloat(); - - float roll = Misc::Rng::rollProbability() * 10000.0f; - - // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds - // due to the roll being an integer. - // Our implementation does not have these issues, so needs to be recalibrated. We chose to - // use the chance MW would have when run at 60 FPS with the default value of the GMST for calibration. - float x = fVoiceIdleOdds * 0.6f * (MWBase::Environment::get().getFrameDuration() / 0.1f); - - // Only say Idle voices when player is in LOS - // A bit counterintuitive, likely vanilla did this to reduce the appearance of - // voices going through walls? - if (roll < x && (player.getRefData().getPosition().asVec3() - pos.asVec3()).length2() - < 3000*3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead - && MWBase::Environment::get().getWorld()->getLOS(player, actor)) - MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); - } + playIdleDialogueRandomly(actor); float& lastReaction = storage.mReaction; lastReaction += duration; @@ -442,6 +417,36 @@ namespace MWMechanics //#endif } + void AiWander::playIdleDialogueRandomly(const MWWorld::Ptr& actor) + { + int hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified(); + if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor) + && MWBase::Environment::get().getSoundManager()->sayDone(actor)) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() + .get().find("fVoiceIdleOdds")->getFloat(); + + float roll = Misc::Rng::rollProbability() * 10000.0f; + + // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds + // due to the roll being an integer. + // Our implementation does not have these issues, so needs to be recalibrated. We chose to + // use the chance MW would have when run at 60 FPS with the default value of the GMST for calibration. + float x = fVoiceIdleOdds * 0.6f * (MWBase::Environment::get().getFrameDuration() / 0.1f); + + // Only say Idle voices when player is in LOS + // A bit counterintuitive, likely vanilla did this to reduce the appearance of + // voices going through walls? + const ESM::Position& pos = actor.getRefData().getPosition(); + if (roll < x && (player.getRefData().getPosition().asVec3() - pos.asVec3()).length2() + < 3000 * 3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead + && MWBase::Environment::get().getWorld()->getLOS(player, actor)) + MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); + } + } + void AiWander::playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage) { // Play a random voice greeting if the player gets too close diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 5196bca00..82baeedf3 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -74,6 +74,7 @@ namespace MWMechanics void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); + void playIdleDialogueRandomly(const MWWorld::Ptr& actor); int mDistance; // how far the actor can wander from the spawn point int mDuration; From ddeabcdfbe006c2f23eb682bf8c611505a3e84f8 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 12 Jul 2015 17:15:41 +1200 Subject: [PATCH 048/419] Removed unused field that was giving compiler warning. --- apps/openmw/mwrender/ripplesimulation.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 8e591a5db..1717cca57 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -59,7 +59,6 @@ namespace MWRender private: osg::ref_ptr mParent; - Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mParticleSystem; osg::ref_ptr mParticleNode; From 749eff5259269a3fced49098ca39517c06f6a582 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 13 Jul 2015 09:42:16 +0200 Subject: [PATCH 049/419] renaming a few user settings categories --- apps/opencs/model/settings/usersettings.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 1bfc6e85b..11fc8bfeb 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -162,7 +162,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() ritd->setDeclaredValues (values); } - declareSection ("table-input", "Table Input"); + declareSection ("table-input", "ID Tables"); { QString inPlaceEdit ("Edit in Place"); QString editRecord ("Edit Record"); @@ -217,7 +217,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() jumpToAdded->setDeclaredValues (jumpValues); } - declareSection ("report-input", "Report Input"); + declareSection ("report-input", "Reports"); { QString none ("None"); QString edit ("Edit"); @@ -257,7 +257,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() shiftCtrlDoubleClick->setDefaultValue (none); shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in report table:

" + toolTip); } - + declareSection ("search", "Search & Replace"); { Setting *before = createSetting (Type_SpinBox, "char-before", @@ -299,7 +299,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() QStringList modes; modes << "Ignore" << modeNormal << "Strict"; - + Setting *warnings = createSetting (Type_ComboBox, "warnings", "Warning Mode"); warnings->setDeclaredValues (modes); @@ -309,7 +309,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() "

  • Normal: Report warning as a warning
  • " "
  • Strict: Promote warning to an error
  • " ""); - + Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int"); formatInt->setDefaultValues (QStringList() << "Dark magenta"); formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); @@ -346,7 +346,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() cycle->setToolTip ("When using next/previous functions at the last/first item of a " "list go to the first/last item"); } - + { /****************************************************************** * There are three types of values: From fc6c14614b9277e833ac5a6dc18640c2b1b22655 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 13 Jul 2015 12:52:18 +0200 Subject: [PATCH 050/419] added user settings option to toggle toolbars in single-record subviews --- apps/opencs/model/settings/usersettings.cpp | 9 +++ apps/opencs/view/world/dialoguesubview.cpp | 86 ++++++++++++++------- apps/opencs/view/world/dialoguesubview.hpp | 16 ++-- apps/opencs/view/world/scriptsubview.cpp | 63 ++++++++++----- apps/opencs/view/world/scriptsubview.hpp | 8 ++ 5 files changed, 131 insertions(+), 51 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 11fc8bfeb..673db4057 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -217,6 +217,12 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() jumpToAdded->setDeclaredValues (jumpValues); } + declareSection ("dialogues", "ID Dialogues"); + { + Setting *toolbar = createSetting (Type_CheckBox, "toolbar", "Show toolbar"); + toolbar->setDefaultValue ("true"); + } + declareSection ("report-input", "Reports"); { QString none ("None"); @@ -310,6 +316,9 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() "
  • Strict: Promote warning to an error
  • " ""); + Setting *toolbar = createSetting (Type_CheckBox, "toolbar", "Show toolbar"); + toolbar->setDefaultValue ("true"); + Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int"); formatInt->setDefaultValues (QStringList() << "Dark magenta"); formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index ed50b81cd..edd9cc1e2 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -31,6 +31,7 @@ #include "../../model/world/idtree.hpp" #include "../../model/world/commands.hpp" #include "../../model/doc/document.hpp" +#include "../../model/settings/usersettings.hpp" #include "../widget/coloreditor.hpp" #include "../widget/droplineedit.hpp" @@ -66,7 +67,7 @@ void CSVWorld::NotEditableSubDelegate::setEditorData (QWidget* editor, const QMo CSMWorld::Columns::ColumnId columnId = static_cast ( mTable->getColumnId (index.column())); - + if (QVariant::String == v.type()) { label->setText(v.toString()); @@ -75,7 +76,7 @@ void CSVWorld::NotEditableSubDelegate::setEditorData (QWidget* editor, const QMo { int data = v.toInt(); std::vector enumNames (CSMWorld::Columns::getEnums (columnId)); - + label->setText(QString::fromUtf8(enumNames.at(data).c_str())); } else @@ -324,11 +325,11 @@ CSVWorld::IdContextMenu::IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Di Q_ASSERT(mWidget != NULL); Q_ASSERT(CSMWorld::ColumnBase::isId(display)); Q_ASSERT(mIdType != CSMWorld::UniversalId::Type_None); - + mWidget->setContextMenuPolicy(Qt::CustomContextMenu); - connect(mWidget, - SIGNAL(customContextMenuRequested(const QPoint &)), - this, + connect(mWidget, + SIGNAL(customContextMenuRequested(const QPoint &)), + this, SLOT(showContextMenu(const QPoint &))); mEditIdAction = new QAction(this); @@ -352,7 +353,7 @@ void CSVWorld::IdContextMenu::excludeId(const std::string &id) QString CSVWorld::IdContextMenu::getWidgetValue() const { - QLineEdit *lineEdit = qobject_cast(mWidget); + QLineEdit *lineEdit = qobject_cast(mWidget); QLabel *label = qobject_cast(mWidget); QString value = ""; @@ -411,7 +412,7 @@ void CSVWorld::IdContextMenu::showContextMenu(const QPoint &pos) { removeEditIdActionFromMenu(); } - + if (!mContextMenu->actions().isEmpty()) { mContextMenu->exec(mWidget->mapToGlobal(pos)); @@ -588,9 +589,9 @@ void CSVWorld::EditWidget::remake(int row) tablesLayout->addWidget(label); tablesLayout->addWidget(table); - connect(table, - SIGNAL(editRequest(const CSMWorld::UniversalId &, const std::string &)), - this, + connect(table, + SIGNAL(editRequest(const CSMWorld::UniversalId &, const std::string &)), + this, SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &))); } else if (!(flags & CSMWorld::ColumnBase::Flag_Dialogue_List)) @@ -830,9 +831,28 @@ void CSVWorld::SimpleDialogueSubView::updateCurrentId() } +void CSVWorld::DialogueSubView::addButtonBar() +{ + if (mButtons) + return; + + mButtons = new RecordButtonBar (getUniversalId(), getTable(), mBottom, + &getCommandDispatcher(), this); + + getMainLayout().insertWidget (1, mButtons); + + // connections + connect (mButtons, SIGNAL (showPreview()), this, SLOT (showPreview())); + connect (mButtons, SIGNAL (viewRecord()), this, SLOT (viewRecord())); + connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int))); + + connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), + mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); +} + CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, const CreatorFactoryBase& creatorFactory, bool sorting) -: SimpleDialogueSubView (id, document) +: SimpleDialogueSubView (id, document), mButtons (0) { // bottom box mBottom = new TableBottomBox (creatorFactory, document, id, this); @@ -843,32 +863,44 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, this, SLOT (requestFocus (const std::string&))); // button bar - mButtons = new RecordButtonBar (id, getTable(), mBottom, - &getCommandDispatcher(), this); + if (CSMSettings::UserSettings::instance().setting ("dialogues/toolbar", QString("true")) == "true") + addButtonBar(); // layout - getMainLayout().addWidget (mButtons); getMainLayout().addWidget (mBottom); - - // connections - connect (mButtons, SIGNAL (showPreview()), this, SLOT (showPreview())); - connect (mButtons, SIGNAL (viewRecord()), this, SLOT (viewRecord())); - connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int))); - - connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), - mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); } void CSVWorld::DialogueSubView::setEditLock (bool locked) { SimpleDialogueSubView::setEditLock (locked); - mButtons->setEditLock (locked); + + if (mButtons) + mButtons->setEditLock (locked); } void CSVWorld::DialogueSubView::updateUserSetting (const QString& name, const QStringList& value) { SimpleDialogueSubView::updateUserSetting (name, value); - mButtons->updateUserSetting (name, value); + + if (name=="dialogues/toolbar") + { + if (value.at(0)==QString ("true")) + { + addButtonBar(); + } + else + { + if (mButtons) + { + getMainLayout().removeWidget (mButtons); + delete mButtons; + mButtons = 0; + } + } + } + + if (mButtons) + mButtons->updateUserSetting (name, value); } void CSVWorld::DialogueSubView::showPreview () @@ -908,7 +940,7 @@ void CSVWorld::DialogueSubView::switchToRow (int row) setUniversalId (CSMWorld::UniversalId (type, id)); updateCurrentId(); - + getEditWidget().remake (row); int stateColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Modification); @@ -923,5 +955,5 @@ void CSVWorld::DialogueSubView::requestFocus (const std::string& id) QModelIndex index = getTable().getModelIndex (id, 0); if (index.isValid()) - switchToRow (index.row()); + switchToRow (index.row()); } diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index d82936e45..2ae0f9720 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -195,8 +195,8 @@ namespace CSVWorld CSMDoc::Document& mDocument; std::vector mNestedModels; //Plain, raw C pointers, deleted in the dtor - void createEditorContextMenu(QWidget *editor, - CSMWorld::ColumnBase::Display display, + void createEditorContextMenu(QWidget *editor, + CSMWorld::ColumnBase::Display display, int currentRow) const; public: @@ -236,7 +236,7 @@ namespace CSVWorld void updateCurrentId(); bool isLocked() const; - + public: SimpleDialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); @@ -256,10 +256,14 @@ namespace CSVWorld class DialogueSubView : public SimpleDialogueSubView { Q_OBJECT - + TableBottomBox* mBottom; RecordButtonBar *mButtons; + private: + + void addButtonBar(); + public: DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, @@ -268,14 +272,14 @@ namespace CSVWorld virtual void setEditLock (bool locked); virtual void updateUserSetting (const QString& name, const QStringList& value); - + private slots: void showPreview(); void viewRecord(); - void switchToRow (int row); + void switchToRow (int row); void requestFocus (const std::string& id); }; diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index dc079c3a9..0f5d5014a 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -17,19 +17,32 @@ #include "scriptedit.hpp" #include "recordbuttonbar.hpp" +void CSVWorld::ScriptSubView::addButtonBar() +{ + if (mButtons) + return; + + mButtons = new RecordButtonBar (getUniversalId(), *mModel, 0, &mCommandDispatcher, this); + + mLayout.insertWidget (1, mButtons); + + connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int))); + + connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), + mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); +} + CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mStatus(0), +: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mStatus(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) { std::vector selection (1, id.getId()); mCommandDispatcher.setSelection (selection); - QVBoxLayout *layout = new QVBoxLayout; - - layout->addWidget (mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this), 2); + mLayout.addWidget (mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this), 2); QWidget *widget = new QWidget (this);; - widget->setLayout (layout); + widget->setLayout (&mLayout); setWidget (widget); mModel = &dynamic_cast ( @@ -49,9 +62,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString()); // buttons - mButtons = new RecordButtonBar (id, *mModel, 0, &mCommandDispatcher, this); - - layout->addWidget (mButtons); + if (CSMSettings::UserSettings::instance().setting ("script-editor/toolbar", QString("true")) == "true") + addButtonBar(); // status bar QStatusBar *statusBar = new QStatusBar(mBottom); @@ -64,7 +76,7 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: bottmLayout->addWidget (statusBar); mBottom->setLayout (bottmLayout); - layout->addWidget (mBottom, 0); + mLayout.addWidget (mBottom, 0); // signals connect (mEditor, SIGNAL (textChanged()), this, SLOT (textChanged())); @@ -75,11 +87,6 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int))); - connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int))); - - connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)), - mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); - updateStatusBar(); connect(mEditor, SIGNAL(cursorPositionChanged()), this, SLOT(updateStatusBar())); } @@ -88,16 +95,33 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr { if (name == "script-editor/show-linenum") { - std::string showLinenum = value.at(0).toStdString(); + std::string showLinenum = value.at(0).toUtf8().constData(); mEditor->showLineNum(showLinenum == "true"); mBottom->setVisible(showLinenum == "true"); } else if (name == "script-editor/mono-font") { - mEditor->setMonoFont(value.at(0).toStdString() == "true"); + mEditor->setMonoFont (value.at(0)==QString ("true")); + } + else if (name=="script-editor/toolbar") + { + if (value.at(0)==QString ("true")) + { + addButtonBar(); + } + else + { + if (mButtons) + { + mLayout.removeWidget (mButtons); + delete mButtons; + mButtons = 0; + } + } } - mButtons->updateUserSetting (name, value); + if (mButtons) + mButtons->updateUserSetting (name, value); } void CSVWorld::ScriptSubView::updateStatusBar () @@ -113,7 +137,10 @@ void CSVWorld::ScriptSubView::updateStatusBar () void CSVWorld::ScriptSubView::setEditLock (bool locked) { mEditor->setReadOnly (locked); - mButtons->setEditLock (locked); + + if (mButtons) + mButtons->setEditLock (locked); + mCommandDispatcher.setEditLock (locked); } diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 0479e6ad8..370754ebe 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -1,12 +1,15 @@ #ifndef CSV_WORLD_SCRIPTSUBVIEW_H #define CSV_WORLD_SCRIPTSUBVIEW_H +#include + #include "../../model/world/commanddispatcher.hpp" #include "../doc/subview.hpp" class QModelIndex; class QLabel; +class QVBoxLayout; namespace CSMDoc { @@ -35,6 +38,11 @@ namespace CSVWorld QLabel *mStatus; RecordButtonBar *mButtons; CSMWorld::CommandDispatcher mCommandDispatcher; + QVBoxLayout mLayout; + + private: + + void addButtonBar(); public: From 5a0af772dda52209ffe92b26bbfbb6aa4e1ea68a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Jul 2015 17:40:03 +0200 Subject: [PATCH 051/419] Update README.md - Remove "an attempt at". I think we are far enough into the project to say that the "attempt" has been successful, at least to a degree. ;) - Added Current Status section. - Added line about OpenMW-CS. --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f62800e1f..5b986e007 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,9 @@ OpenMW [![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) -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. +OpenMW is a recreation of 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. + +OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set. * Version: 0.36.0 * License: GPL (see docs/license/GPL3.txt for more information) @@ -14,6 +15,13 @@ Morrowind by Bethesda Softworks. You need to own and install the original game f Font Licenses: * DejaVuLGCSansMono.ttf: custom (see docs/license/DejaVu Font License.txt for more information) +Current Status +-------------- + +The main quests in Morrowind, Tribunal and Bloodmoon are all completable. Some issues with side quests are to be expected (but rare). Check the [bug tracker](https://bugs.openmw.org/versions/21) for a list of issues we need to resolve before the "1.0" release. Even before the "1.0" release however, OpenMW boasts some new [features](https://wiki.openmw.org/index.php?title=Features), such as improved graphics and user interfaces. + +Pre-existing modifications created for the original Morrowind engine can be hit-and-miss. The OpenMW script compiler performs more thorough error-checking than Morrowind does, meaning that a mod created for Morrowind may not necessarily run in OpenMW. Some mods also rely on quirky behaviour or engine bugs in order to work. We are considering such compatibility issues on a case-by-case basis - in some cases adding a workaround to OpenMW may be feasible, in other cases fixing the mod will be the only option. If you know of any mods that work or don't work, feel free to add them to the [Mod status](https://wiki.openmw.org/index.php?title=Mod_status) wiki page. + Getting Started --------------- From f1b52c964a2da506aefdc7b404bd00fee766b273 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Jul 2015 18:00:41 +0200 Subject: [PATCH 052/419] Select the current resolution in resolution list on game start (Fixes #2768) --- apps/openmw/mwgui/settingswindow.cpp | 21 +++++++++++++++++++++ apps/openmw/mwgui/settingswindow.hpp | 1 + 2 files changed, 22 insertions(+) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index df5aa1a40..3ab2a6ce3 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -233,6 +233,7 @@ namespace MWGui if (mResolutionList->findItemIndexWith(str) == MyGUI::ITEM_NONE) mResolutionList->addItem(str); } + highlightCurrentResolution(); std::string tf = Settings::Manager::getString("texture filtering", "General"); mTextureFilteringButton->setCaption(textureFilteringToStr(tf)); @@ -299,8 +300,28 @@ namespace MWGui } void SettingsWindow::onResolutionCancel() + { + highlightCurrentResolution(); + } + + void SettingsWindow::highlightCurrentResolution() { mResolutionList->setIndexSelected(MyGUI::ITEM_NONE); + + int currentX = Settings::Manager::getInt("resolution x", "Video"); + int currentY = Settings::Manager::getInt("resolution y", "Video"); + + for (size_t i=0; igetItemCount(); ++i) + { + int resX, resY; + parseResolution (resX, resY, mResolutionList->getItemNameAt(i)); + + if (resX == currentX && resY == currentY) + { + mResolutionList->setIndexSelected(i); + break; + } + } } void SettingsWindow::onShadowTextureSizeChanged(MyGUI::ComboBox *_sender, size_t pos) diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 45d489284..79487c54b 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -59,6 +59,7 @@ namespace MWGui void onResolutionSelected(MyGUI::ListBox* _sender, size_t index); void onResolutionAccept(); void onResolutionCancel(); + void highlightCurrentResolution(); void onShadowTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos); From dca4704b4b665f0853917150f7902e0c29607e58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Jul 2015 18:40:05 +0200 Subject: [PATCH 053/419] Print exceptions in CharacterCreation::spawnDialog --- apps/openmw/mwgui/charactercreation.cpp | 241 ++++++++++++------------ 1 file changed, 124 insertions(+), 117 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 73b950a6a..d0a050526 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -132,134 +132,141 @@ namespace MWGui void CharacterCreation::spawnDialog(const char id) { - switch (id) + try { - case GM_Name: - MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); - mNameDialog = 0; - mNameDialog = new TextInputDialog(); - mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name")); - mNameDialog->setTextInput(mPlayerName); - mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen); - mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone); - mNameDialog->setVisible(true); - break; + switch (id) + { + case GM_Name: + MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); + mNameDialog = 0; + mNameDialog = new TextInputDialog(); + mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name")); + mNameDialog->setTextInput(mPlayerName); + mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen); + mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone); + mNameDialog->setVisible(true); + break; - case GM_Race: - MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); - mRaceDialog = 0; - mRaceDialog = new RaceDialog(mViewer, mResourceSystem); - mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); - mRaceDialog->setRaceId(mPlayerRaceId); - mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); - mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack); - mRaceDialog->setVisible(true); - if (mCreationStage < CSE_NameChosen) - mCreationStage = CSE_NameChosen; - break; + case GM_Race: + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); + mRaceDialog = 0; + mRaceDialog = new RaceDialog(mViewer, mResourceSystem); + mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); + mRaceDialog->setRaceId(mPlayerRaceId); + mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); + mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack); + mRaceDialog->setVisible(true); + if (mCreationStage < CSE_NameChosen) + mCreationStage = CSE_NameChosen; + break; - case GM_Class: - MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); - mClassChoiceDialog = 0; - mClassChoiceDialog = new ClassChoiceDialog(); - mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); - mClassChoiceDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; + case GM_Class: + MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); + mClassChoiceDialog = 0; + mClassChoiceDialog = new ClassChoiceDialog(); + mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); + mClassChoiceDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; - case GM_ClassPick: - MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); - mPickClassDialog = 0; - mPickClassDialog = new PickClassDialog(); - mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); - mPickClassDialog->setClassId(mPlayerClass.mName); - mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); - mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack); - mPickClassDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; + case GM_ClassPick: + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); + mPickClassDialog = 0; + mPickClassDialog = new PickClassDialog(); + mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); + mPickClassDialog->setClassId(mPlayerClass.mName); + mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); + mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack); + mPickClassDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; - case GM_Birth: - MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); - mBirthSignDialog = 0; - mBirthSignDialog = new BirthDialog(); - mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); - mBirthSignDialog->setBirthId(mPlayerBirthSignId); - mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); - mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); - mBirthSignDialog->setVisible(true); - if (mCreationStage < CSE_ClassChosen) - mCreationStage = CSE_ClassChosen; - break; + case GM_Birth: + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); + mBirthSignDialog = 0; + mBirthSignDialog = new BirthDialog(); + mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); + mBirthSignDialog->setBirthId(mPlayerBirthSignId); + mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); + mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); + mBirthSignDialog->setVisible(true); + if (mCreationStage < CSE_ClassChosen) + mCreationStage = CSE_ClassChosen; + break; - case GM_ClassCreate: - if (!mCreateClassDialog) - { - mCreateClassDialog = new CreateClassDialog(); - mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); - mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); - } - mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); - mCreateClassDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; - case GM_ClassGenerate: - mGenerateClassStep = 0; - mGenerateClass = ""; - mGenerateClassSpecializations[0] = 0; - mGenerateClassSpecializations[1] = 0; - mGenerateClassSpecializations[2] = 0; - showClassQuestionDialog(); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; - case GM_Review: - MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); - mReviewDialog = 0; - mReviewDialog = new ReviewDialog(); - mReviewDialog->setPlayerName(mPlayerName); - mReviewDialog->setRace(mPlayerRaceId); - mReviewDialog->setClass(mPlayerClass); - mReviewDialog->setBirthSign(mPlayerBirthSignId); - - { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); - - mReviewDialog->setHealth ( stats.getHealth() ); - mReviewDialog->setMagicka( stats.getMagicka() ); - mReviewDialog->setFatigue( stats.getFatigue() ); - } - - { - std::map attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); - for (std::map::iterator it = attributes.begin(); - it != attributes.end(); ++it) + case GM_ClassCreate: + if (!mCreateClassDialog) { - mReviewDialog->setAttribute(static_cast (it->first), it->second); + mCreateClassDialog = new CreateClassDialog(); + mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); + mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); } - } + mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); + mCreateClassDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + case GM_ClassGenerate: + mGenerateClassStep = 0; + mGenerateClass = ""; + mGenerateClassSpecializations[0] = 0; + mGenerateClassSpecializations[1] = 0; + mGenerateClassSpecializations[2] = 0; + showClassQuestionDialog(); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + case GM_Review: + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); + mReviewDialog = 0; + mReviewDialog = new ReviewDialog(); + mReviewDialog->setPlayerName(mPlayerName); + mReviewDialog->setRace(mPlayerRaceId); + mReviewDialog->setClass(mPlayerClass); + mReviewDialog->setBirthSign(mPlayerBirthSignId); - { - std::map skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); - for (std::map::iterator it = skills.begin(); - it != skills.end(); ++it) { - mReviewDialog->setSkillValue(static_cast (it->first), it->second); - } - mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); - } + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); - mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); - mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack); - mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog); - mReviewDialog->setVisible(true); - if (mCreationStage < CSE_BirthSignChosen) - mCreationStage = CSE_BirthSignChosen; - break; + mReviewDialog->setHealth ( stats.getHealth() ); + mReviewDialog->setMagicka( stats.getMagicka() ); + mReviewDialog->setFatigue( stats.getFatigue() ); + } + + { + std::map attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); + for (std::map::iterator it = attributes.begin(); + it != attributes.end(); ++it) + { + mReviewDialog->setAttribute(static_cast (it->first), it->second); + } + } + + { + std::map skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); + for (std::map::iterator it = skills.begin(); + it != skills.end(); ++it) + { + mReviewDialog->setSkillValue(static_cast (it->first), it->second); + } + mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); + } + + mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); + mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack); + mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog); + mReviewDialog->setVisible(true); + if (mCreationStage < CSE_BirthSignChosen) + mCreationStage = CSE_BirthSignChosen; + break; + } + } + catch (std::exception& e) + { + std::cerr << "Failed to create chargen window: " << e.what() << std::endl; } } From c4866bdfc63e28ceff2573dabb643fafc4283360 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Jul 2015 19:13:26 +0200 Subject: [PATCH 054/419] Disable mipmaps for GUI textures For some reason, the mipmap generator seems to be broken on Linux Intel graphics (works on Nvidia). This was breaking the scrollbar arrows, which are minified enough to show using a mipmap. --- components/myguiplatform/myguitexture.cpp | 2 ++ components/resource/texturemanager.cpp | 25 ++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index 0a846b227..50ac5c1f3 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -87,6 +87,8 @@ namespace osgMyGUI throw std::runtime_error("No texturemanager set"); mTexture = mTextureManager->getTexture2D(fname, osg::Texture2D::CLAMP_TO_EDGE, osg::Texture2D::CLAMP_TO_EDGE); + // disable mip-maps + mTexture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR); // FIXME mFormat = MyGUI::PixelFormat::R8G8B8; diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 62cbd6bb3..ae8d16102 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -64,7 +64,30 @@ namespace Resource for (std::map >::iterator it = mTextures.begin(); it != mTextures.end(); ++it) { osg::ref_ptr tex = it->second; - tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter); + + // Keep mip-mapping disabled if the texture creator explicitely requested it. + osg::Texture::FilterMode oldMin = tex->getFilter(osg::Texture::MIN_FILTER); + if (oldMin == osg::Texture::LINEAR || oldMin == osg::Texture::NEAREST) + { + osg::Texture::FilterMode newMin = osg::Texture::LINEAR; + switch (mMinFilter) + { + case osg::Texture::LINEAR: + case osg::Texture::LINEAR_MIPMAP_LINEAR: + case osg::Texture::LINEAR_MIPMAP_NEAREST: + newMin = osg::Texture::LINEAR; + break; + case osg::Texture::NEAREST: + case osg::Texture::NEAREST_MIPMAP_LINEAR: + case osg::Texture::NEAREST_MIPMAP_NEAREST: + newMin = osg::Texture::NEAREST; + break; + } + tex->setFilter(osg::Texture::MIN_FILTER, newMin); + } + else + tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter); + tex->setFilter(osg::Texture::MAG_FILTER, mMagFilter); tex->setMaxAnisotropy(static_cast(mMaxAnisotropy)); } From de6dc21552d0a5c190f2930df6090fdaeb66dbe6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 13 Jul 2015 23:36:25 +0200 Subject: [PATCH 055/419] Create hardware cursors in advance (Fixes #2660) --- apps/openmw/mwgui/windowmanagerimp.cpp | 56 +++++++++++++------------ apps/openmw/mwgui/windowmanagerimp.hpp | 1 + components/sdlutil/sdlcursormanager.cpp | 13 ++---- components/sdlutil/sdlcursormanager.hpp | 6 +-- 4 files changed, 36 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 582519b19..a2a826161 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -235,8 +235,9 @@ namespace MWGui MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); + // Create all cursors in advance + createCursors(); onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); - mCursorManager->setEnabled(true); // hide mygui's pointer @@ -1181,31 +1182,7 @@ namespace MWGui void WindowManager::onCursorChange(const std::string &name) { - if(!mCursorManager->cursorChanged(name)) - return; //the cursor manager doesn't want any more info about this cursor - //See if we can get the information we need out of the cursor resource - ResourceImageSetPointerFix* imgSetPtr = dynamic_cast(MyGUI::PointerManager::getInstance().getByName(name)); - if(imgSetPtr != NULL) - { - MyGUI::ResourceImageSet* imgSet = imgSetPtr->getImageSet(); - - std::string tex_name = imgSet->getIndexInfo(0,0).texture; - - osg::ref_ptr tex = mResourceSystem->getTextureManager()->getTexture2D(tex_name, osg::Texture::CLAMP, osg::Texture::CLAMP); - tex->setUnRefImageDataAfterApply(false); // FIXME? - - //everything looks good, send it to the cursor manager - if(tex.valid()) - { - Uint8 size_x = imgSetPtr->getSize().width; - Uint8 size_y = imgSetPtr->getSize().height; - Uint8 hotspot_x = imgSetPtr->getHotSpot().left; - Uint8 hotspot_y = imgSetPtr->getHotSpot().top; - int rotation = imgSetPtr->getRotation(); - - mCursorManager->receiveCursorInfo(name, rotation, tex->getImage(), size_x, size_y, hotspot_x, hotspot_y); - } - } + mCursorManager->cursorChanged(name); } void WindowManager::popGuiMode() @@ -1963,6 +1940,33 @@ namespace MWGui return Misc::ResourceHelpers::correctTexturePath(path, mResourceSystem->getVFS()); } + void WindowManager::createCursors() + { + MyGUI::ResourceManager::EnumeratorPtr enumerator = MyGUI::ResourceManager::getInstance().getEnumerator(); + while (enumerator.next()) + { + MyGUI::IResource* resource = enumerator.current().second; + ResourceImageSetPointerFix* imgSetPointer = dynamic_cast(resource); + if (!imgSetPointer) + continue; + std::string tex_name = imgSetPointer->getImageSet()->getIndexInfo(0,0).texture; + + osg::ref_ptr tex = mResourceSystem->getTextureManager()->getTexture2D(tex_name, osg::Texture::CLAMP, osg::Texture::CLAMP); + + if(tex.valid()) + { + //everything looks good, send it to the cursor manager + Uint8 size_x = imgSetPointer->getSize().width; + Uint8 size_y = imgSetPointer->getSize().height; + Uint8 hotspot_x = imgSetPointer->getHotSpot().left; + Uint8 hotspot_y = imgSetPointer->getHotSpot().top; + int rotation = imgSetPointer->getRotation(); + + mCursorManager->createCursor(imgSetPointer->getResourceName(), rotation, tex->getImage(), size_x, size_y, hotspot_x, hotspot_y); + } + } + } + void WindowManager::createTextures() { { diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index c275a9f62..e6c8d0a81 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -511,6 +511,7 @@ namespace MWGui void onClipboardRequested(const std::string& _type, std::string& _data); void createTextures(); + void createCursors(); void setMenuTransparency(float value); }; } diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index a8a48f4f8..d8d4b0b50 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -175,23 +175,16 @@ namespace SDLUtil } } - bool SDLCursorManager::cursorChanged(const std::string& name) + void SDLCursorManager::cursorChanged(const std::string& name) { mCurrentCursor = name; CursorMap::const_iterator curs_iter = mCursorMap.find(name); - //we have this cursor if(curs_iter != mCursorMap.end()) { + //we have this cursor _setGUICursor(name); - - return false; - } - else - { - //they should get back to us with more info - return true; } } @@ -200,7 +193,7 @@ namespace SDLUtil SDL_SetCursor(mCursorMap.find(name)->second); } - void SDLCursorManager::receiveCursorInfo(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + void SDLCursorManager::createCursor(const std::string& name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) { _createCursorFromResource(name, rotDegrees, image, size_x, size_y, hotspot_x, hotspot_y); } diff --git a/components/sdlutil/sdlcursormanager.hpp b/components/sdlutil/sdlcursormanager.hpp index 646f548e3..0db578039 100644 --- a/components/sdlutil/sdlcursormanager.hpp +++ b/components/sdlutil/sdlcursormanager.hpp @@ -27,11 +27,9 @@ namespace SDLUtil /// \brief Tell the manager that the cursor has changed, giving the /// name of the cursor we changed to ("arrow", "ibeam", etc) - /// \return Whether the manager is interested in more information about the cursor - virtual bool cursorChanged(const std::string &name); + virtual void cursorChanged(const std::string &name); - /// \brief Follow up a cursorChanged() call with enough info to create an cursor. - virtual void receiveCursorInfo(const std::string &name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + virtual void createCursor(const std::string &name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); private: void _createCursorFromResource(const std::string &name, int rotDegrees, osg::Image* image, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); From 2202973c2462b9299480c9106904383a113fb89d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 14 Jul 2015 10:05:45 +0200 Subject: [PATCH 056/419] replaced the script subview status bar with a bottom box (including a status bar) --- apps/opencs/view/world/dialoguesubview.cpp | 2 -- apps/opencs/view/world/scriptsubview.cpp | 33 +++++++++----------- apps/opencs/view/world/scriptsubview.hpp | 6 ++-- apps/opencs/view/world/tablebottombox.cpp | 36 ++++++++++++++++++---- apps/opencs/view/world/tablebottombox.hpp | 13 ++++++-- 5 files changed, 59 insertions(+), 31 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index edd9cc1e2..5a44708c1 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -857,8 +857,6 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, // bottom box mBottom = new TableBottomBox (creatorFactory, document, id, this); - mBottom->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Fixed); - connect (mBottom, SIGNAL (requestFocus (const std::string&)), this, SLOT (requestFocus (const std::string&))); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 0f5d5014a..f65f77285 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -4,7 +4,6 @@ #include #include -#include #include "../../model/doc/document.hpp" #include "../../model/world/universalid.hpp" @@ -16,6 +15,8 @@ #include "scriptedit.hpp" #include "recordbuttonbar.hpp" +#include "tablebottombox.hpp" +#include "genericcreator.hpp" void CSVWorld::ScriptSubView::addButtonBar() { @@ -33,7 +34,7 @@ void CSVWorld::ScriptSubView::addButtonBar() } CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mStatus(0), mButtons (0), +: SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) { std::vector selection (1, id.getId()); @@ -65,18 +66,13 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: if (CSMSettings::UserSettings::instance().setting ("script-editor/toolbar", QString("true")) == "true") addButtonBar(); - // status bar - QStatusBar *statusBar = new QStatusBar(mBottom); - mStatus = new QLabel(mBottom); - statusBar->addWidget (mStatus); + // bottom box + mBottom = new TableBottomBox (CreatorFactory(), document, id, this); - mBottom = new QWidget(this); - QStackedLayout *bottmLayout = new QStackedLayout(mBottom); - bottmLayout->setContentsMargins (0, 0, 0, 0); - bottmLayout->addWidget (statusBar); - mBottom->setLayout (bottmLayout); + connect (mBottom, SIGNAL (requestFocus (const std::string&)), + this, SLOT (requestFocus (const std::string&))); - mLayout.addWidget (mBottom, 0); + mLayout.addWidget (mBottom); // signals connect (mEditor, SIGNAL (textChanged()), this, SLOT (textChanged())); @@ -124,14 +120,15 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr mButtons->updateUserSetting (name, value); } +void CSVWorld::ScriptSubView::setStatusBar (bool show) +{ + mBottom->setStatusBar (show); +} + void CSVWorld::ScriptSubView::updateStatusBar () { - std::ostringstream stream; - - stream << "(" << mEditor->textCursor().blockNumber() + 1 << ", " - << mEditor->textCursor().columnNumber() + 1 << ")"; - - mStatus->setText (QString::fromUtf8 (stream.str().c_str())); + mBottom->positionChanged (mEditor->textCursor().blockNumber() + 1, + mEditor->textCursor().columnNumber() + 1); } void CSVWorld::ScriptSubView::setEditLock (bool locked) diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 370754ebe..09f7907ee 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -25,6 +25,7 @@ namespace CSVWorld { class ScriptEdit; class RecordButtonBar; + class TableBottomBox; class ScriptSubView : public CSVDoc::SubView { @@ -34,8 +35,7 @@ namespace CSVWorld CSMDoc::Document& mDocument; CSMWorld::IdTable *mModel; int mColumn; - QWidget *mBottom; - QLabel *mStatus; + TableBottomBox *mBottom; RecordButtonBar *mButtons; CSMWorld::CommandDispatcher mCommandDispatcher; QVBoxLayout mLayout; @@ -54,6 +54,8 @@ namespace CSVWorld virtual void updateUserSetting (const QString& name, const QStringList& value); + virtual void setStatusBar (bool show); + public slots: void textChanged(); diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index dc3a6cc76..12226450b 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -35,15 +35,23 @@ void CSVWorld::TableBottomBox::updateStatus() } } + if (mHasPosition) + { + if (!first) + stream << " -- "; + + stream << "(" << mRow << ", " << mColumn << ")"; + } + mStatus->setText (QString::fromUtf8 (stream.str().c_str())); } } -CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, - CSMDoc::Document& document, - const CSMWorld::UniversalId& id, +CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, + CSMDoc::Document& document, + const CSMWorld::UniversalId& id, QWidget *parent) -: QWidget (parent), mShowStatusBar (false), mCreating (false) +: QWidget (parent), mShowStatusBar (false), mCreating (false), mHasPosition (false) { for (int i=0; i<4; ++i) mStatusCount[i] = 0; @@ -74,6 +82,8 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto connect (mCreator, SIGNAL (requestFocus (const std::string&)), this, SIGNAL (requestFocus (const std::string&))); } + + setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Fixed); } void CSVWorld::TableBottomBox::setEditLock (bool locked) @@ -152,6 +162,20 @@ void CSVWorld::TableBottomBox::tableSizeChanged (int size, int deleted, int modi updateStatus(); } +void CSVWorld::TableBottomBox::positionChanged (int row, int column) +{ + mRow = row; + mColumn = column; + mHasPosition = true; + updateStatus(); +} + +void CSVWorld::TableBottomBox::noMorePosition() +{ + mHasPosition = false; + updateStatus(); +} + void CSVWorld::TableBottomBox::createRequest() { mCreator->reset(); @@ -162,8 +186,8 @@ void CSVWorld::TableBottomBox::createRequest() mCreator->focus(); } -void CSVWorld::TableBottomBox::cloneRequest(const std::string& id, - const CSMWorld::UniversalId::Type type) +void CSVWorld::TableBottomBox::cloneRequest(const std::string& id, + const CSMWorld::UniversalId::Type type) { mCreator->reset(); mCreator->cloneMode(id, type); diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index a7d009c42..6e68553bc 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -30,6 +30,9 @@ namespace CSVWorld Creator *mCreator; bool mCreating; QStackedLayout *mLayout; + bool mHasPosition; + int mRow; + int mColumn; private: @@ -41,9 +44,9 @@ namespace CSVWorld public: - TableBottomBox (const CreatorFactoryBase& creatorFactory, - CSMDoc::Document& document, - const CSMWorld::UniversalId& id, + TableBottomBox (const CreatorFactoryBase& creatorFactory, + CSMDoc::Document& document, + const CSMWorld::UniversalId& id, QWidget *parent = 0); virtual ~TableBottomBox(); @@ -77,6 +80,10 @@ namespace CSVWorld /// \param deleted Number of deleted records /// \param modified Number of added and modified records + void positionChanged (int row, int column); + + void noMorePosition(); + void createRequest(); void cloneRequest(const std::string& id, const CSMWorld::UniversalId::Type type); From 0860c27b039465e4505f5211a9bcbb9ddedf773e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 14 Jul 2015 11:49:41 +0200 Subject: [PATCH 057/419] improving consistency of subview layouts --- apps/opencs/view/tools/searchsubview.cpp | 20 +++++++++----------- apps/opencs/view/world/previewsubview.cpp | 2 -- apps/opencs/view/world/scenesubview.cpp | 2 -- apps/opencs/view/world/tablesubview.cpp | 3 --- 4 files changed, 9 insertions(+), 18 deletions(-) diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index dc670af40..8b35db6ae 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -16,7 +16,7 @@ void CSVTools::SearchSubView::replace (bool selection) { if (mLocked) return; - + std::vector indices = mTable->getReplaceIndices (selection); std::string replace = mSearchBox.getReplaceText(); @@ -29,7 +29,7 @@ void CSVTools::SearchSubView::replace (bool selection) CSMTools::Search search (mSearch); CSMWorld::IdTableBase *currentTable = 0; - + // We are running through the indices in reverse order to avoid messing up multiple results // in a single string. for (std::vector::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter) @@ -46,7 +46,7 @@ void CSVTools::SearchSubView::replace (bool selection) search.configure (table); currentTable = table; } - + std::string hint = model.getHint (*iter); if (search.verify (mDocument, table, id, hint)) @@ -63,7 +63,7 @@ void CSVTools::SearchSubView::replace (bool selection) void CSVTools::SearchSubView::showEvent (QShowEvent *event) { CSVDoc::SubView::showEvent (event); - mSearchBox.focus(); + mSearchBox.focus(); } CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) @@ -71,25 +71,23 @@ CSVTools::SearchSubView::SearchSubView (const CSMWorld::UniversalId& id, CSMDoc: { QVBoxLayout *layout = new QVBoxLayout; - layout->setContentsMargins (QMargins (0, 0, 0, 0)); - layout->addWidget (&mSearchBox); - + layout->addWidget (mTable = new ReportTable (document, id, true), 2); QWidget *widget = new QWidget; - + widget->setLayout (layout); setWidget (widget); stateChanged (document.getState(), &document); - + connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); connect (mTable, SIGNAL (replaceRequest()), this, SLOT (replaceRequest())); - + connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (stateChanged (int, CSMDoc::Document *))); @@ -124,7 +122,7 @@ void CSVTools::SearchSubView::startSearch (const CSMTools::Search& search) mSearch = search; mSearch.setPadding (paddingBefore, paddingAfter); - + mTable->clear(); mDocument.runSearch (getUniversalId(), mSearch); } diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index 1c2d6b95c..756e79fe6 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -13,8 +13,6 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo { QHBoxLayout *layout = new QHBoxLayout; - layout->setContentsMargins (QMargins (0, 0, 0, 0)); - if (document.getData().getReferenceables().searchId (id.getId())==-1) { std::string referenceableId = diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 397d24929..b7a795e23 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -31,8 +31,6 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D { QVBoxLayout *layout = new QVBoxLayout; - layout->setContentsMargins (QMargins (0, 0, 0, 0)); - layout->addWidget (mBottom = new TableBottomBox (NullCreatorFactory(), document, id, this), 0); mLayout->setContentsMargins (QMargins (0, 0, 0, 0)); diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 75671a50c..e2c9e2fb1 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -23,8 +23,6 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D { QVBoxLayout *layout = new QVBoxLayout; - layout->setContentsMargins (QMargins (0, 0, 0, 0)); - layout->addWidget (mBottom = new TableBottomBox (creatorFactory, document, id, this), 0); @@ -166,4 +164,3 @@ bool CSVWorld::TableSubView::eventFilter (QObject* object, QEvent* event) } return false; } - From cf1fb76bb4cdb3e08f8b4a71e682681a811fe64b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 14 Jul 2015 13:34:13 +0200 Subject: [PATCH 058/419] fixed deleted button sensitivity state --- apps/opencs/view/world/recordbuttonbar.cpp | 29 +++++++++++----------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 63c0dd0a1..9cae0d0c9 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -17,18 +17,17 @@ void CSVWorld::RecordButtonBar::updateModificationButtons() mCloneButton->setDisabled (createAndDeleteDisabled); mAddButton->setDisabled (createAndDeleteDisabled); - mDeleteButton->setDisabled (createAndDeleteDisabled); bool commandDisabled = !mCommandDispatcher || mLocked; - + mRevertButton->setDisabled (commandDisabled); - mDeleteButton->setDisabled (commandDisabled); + mDeleteButton->setDisabled (commandDisabled || createAndDeleteDisabled); } void CSVWorld::RecordButtonBar::updatePrevNextButtons() { int rows = mTable.rowCount(); - + if (rows<=1) { mPrevButton->setDisabled (true); @@ -62,12 +61,12 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, mPrevButton->setIcon(QIcon(":/go-previous.png")); mPrevButton->setToolTip ("Switch to previous record"); buttonsLayout->addWidget (mPrevButton, 0); - + mNextButton = new QToolButton (this); mNextButton->setIcon(QIcon(":/go-next.png")); mNextButton->setToolTip ("Switch to next record"); buttonsLayout->addWidget (mNextButton, 1); - + buttonsLayout->addStretch(2); // optional buttons of the right section @@ -94,22 +93,22 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, mCloneButton->setIcon(QIcon(":/edit-clone.png")); mCloneButton->setToolTip ("Clone record"); buttonsLayout->addWidget(mCloneButton); - + mAddButton = new QToolButton (this); mAddButton->setIcon(QIcon(":/add.png")); mAddButton->setToolTip ("Add new record"); buttonsLayout->addWidget(mAddButton); - + mDeleteButton = new QToolButton (this); mDeleteButton->setIcon(QIcon(":/edit-delete.png")); mDeleteButton->setToolTip ("Delete record"); buttonsLayout->addWidget(mDeleteButton); - + mRevertButton = new QToolButton (this); mRevertButton->setIcon(QIcon(":/edit-undo.png")); mRevertButton->setToolTip ("Revert record"); buttonsLayout->addWidget(mRevertButton); - + setLayout (buttonsLayout); // connections @@ -132,7 +131,7 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, this, SLOT (rowNumberChanged (const QModelIndex&, int, int))); connect (&mTable, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), this, SLOT (rowNumberChanged (const QModelIndex&, int, int))); - + updateModificationButtons(); updatePrevNextButtons(); } @@ -170,7 +169,7 @@ void CSVWorld::RecordButtonBar::cloneRequest() } void CSVWorld::RecordButtonBar::nextId() -{ +{ int newRow = mTable.getModelIndex (mId.getId(), 0).row() + 1; if (newRow >= mTable.rowCount()) @@ -180,8 +179,8 @@ void CSVWorld::RecordButtonBar::nextId() newRow = 0; else return; - } - + } + emit switchToRow (newRow); } @@ -197,7 +196,7 @@ void CSVWorld::RecordButtonBar::prevId() else return; } - + emit switchToRow (newRow); } From df027b3498f1730cfda5daed06052c04a64456d9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 14 Jul 2015 13:52:48 +0200 Subject: [PATCH 059/419] hooked up script subview buttons to bottom box (enables add and clone) --- apps/opencs/view/world/scriptsubview.cpp | 15 +++++++++------ apps/opencs/view/world/scriptsubview.hpp | 2 ++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index f65f77285..181400c88 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -23,7 +23,7 @@ void CSVWorld::ScriptSubView::addButtonBar() if (mButtons) return; - mButtons = new RecordButtonBar (getUniversalId(), *mModel, 0, &mCommandDispatcher, this); + mButtons = new RecordButtonBar (getUniversalId(), *mModel, mBottom, &mCommandDispatcher, this); mLayout.insertWidget (1, mButtons); @@ -61,16 +61,14 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: throw std::logic_error ("Can't find script column"); mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString()); + // bottom box and buttons + mBottom = new TableBottomBox (CreatorFactory(), document, id, this); - // buttons if (CSMSettings::UserSettings::instance().setting ("script-editor/toolbar", QString("true")) == "true") addButtonBar(); - // bottom box - mBottom = new TableBottomBox (CreatorFactory(), document, id, this); - connect (mBottom, SIGNAL (requestFocus (const std::string&)), - this, SLOT (requestFocus (const std::string&))); + this, SLOT (switchToId (const std::string&))); mLayout.addWidget (mBottom); @@ -216,3 +214,8 @@ void CSVWorld::ScriptSubView::switchToRow (int row) std::vector selection (1, id); mCommandDispatcher.setSelection (selection); } + +void CSVWorld::ScriptSubView::switchToId (const std::string& id) +{ + switchToRow (mModel->getModelIndex (id, 0).row()); +} diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 09f7907ee..6e5276c68 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -69,6 +69,8 @@ namespace CSVWorld void updateStatusBar(); void switchToRow (int row); + + void switchToId (const std::string& id); }; } From 73731d27e9e32f26e154b16fd1eb4543f84ea917 Mon Sep 17 00:00:00 2001 From: Koncord Date: Tue, 14 Jul 2015 23:54:47 +0900 Subject: [PATCH 060/419] Add ${MYGUI_LIBRARIES} to components/CMakeLists.txt --- components/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 3224d0989..d91bb5c30 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -180,6 +180,7 @@ target_link_libraries(components ${SDL2_LIBRARY} # For MyGUI platform ${OPENGL_gl_LIBRARY} + ${MYGUI_LIBRARIES} ) if (WIN32) From 335ef97cf561e4655363e16041aaf119cde375db Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 9 Jul 2015 18:47:11 +0200 Subject: [PATCH 061/419] Rename Animation::Group to Animation::BlendMask The old naming is problematic, because the term group was being used for another feature (text key groups) already. --- apps/openmw/mwmechanics/character.cpp | 70 +++++++++++------------ apps/openmw/mwrender/animation.cpp | 42 +++++++------- apps/openmw/mwrender/animation.hpp | 30 +++++----- apps/openmw/mwrender/characterpreview.cpp | 6 +- 4 files changed, 74 insertions(+), 74 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4b2ce9f4c..bd15b6a73 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -251,26 +251,26 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat { mHitState = CharState_KnockOut; mCurrentHit = "knockout"; - mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, false, 1, "start", "stop", 0.0f, ~0ul); + mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, false, 1, "start", "stop", 0.0f, ~0ul); mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(true); } else if(knockdown) { mHitState = CharState_KnockDown; mCurrentHit = "knockdown"; - mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0); + mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); } else if (recovery) { mHitState = CharState_Hit; mCurrentHit = chooseRandomGroup("hit"); - mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0); + mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); } else if (block) { mHitState = CharState_Block; mCurrentHit = "shield"; - mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "block start", "block stop", 0.0f, 0); + mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "block start", "block stop", 0.0f, 0); } // Cancel upper body animations @@ -303,7 +303,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat { mHitState = CharState_KnockDown; mAnimation->disable(mCurrentHit); - mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, true, 1, "loop stop", "stop", 0.0f, 0); + mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "loop stop", "stop", 0.0f, 0); } } @@ -314,7 +314,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if(force && mJumpState != JumpState_None) { std::string jump; - MWRender::Animation::Group jumpgroup = MWRender::Animation::Group_All; + MWRender::Animation::BlendMask jumpmask = MWRender::Animation::BlendMask_All; if(mJumpState != JumpState_None) { jump = "jump"; @@ -323,7 +323,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat jump += weap->shortgroup; if(!mAnimation->hasAnimation(jump)) { - jumpgroup = MWRender::Animation::Group_LowerBody; + jumpmask = MWRender::Animation::BlendMask_LowerBody; jump = "jump"; } } @@ -336,7 +336,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mAnimation->disable(mCurrentJump); mCurrentJump = jump; if (mAnimation->hasAnimation("jump")) - mAnimation->play(mCurrentJump, Priority_Jump, jumpgroup, false, + mAnimation->play(mCurrentJump, Priority_Jump, jumpmask, false, 1.0f, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); } else @@ -344,7 +344,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mAnimation->disable(mCurrentJump); mCurrentJump.clear(); if (mAnimation->hasAnimation("jump")) - mAnimation->play(jump, Priority_Jump, jumpgroup, true, + mAnimation->play(jump, Priority_Jump, jumpmask, true, 1.0f, "loop stop", "stop", 0.0f, 0); } } @@ -354,7 +354,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mMovementState = movement; std::string movement; - MWRender::Animation::Group movegroup = MWRender::Animation::Group_All; + MWRender::Animation::BlendMask movemask = MWRender::Animation::BlendMask_All; const StateInfo *movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(mMovementState)); if(movestate != sMovementListEnd) { @@ -364,7 +364,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat movement += weap->shortgroup; if(!mAnimation->hasAnimation(movement)) { - movegroup = MWRender::Animation::Group_LowerBody; + movemask = MWRender::Animation::BlendMask_LowerBody; movement = movestate->groupname; } } @@ -386,7 +386,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } else { - movegroup = MWRender::Animation::Group_LowerBody; + movemask = MWRender::Animation::BlendMask_LowerBody; movement.erase(swimpos, 4); if(!mAnimation->hasAnimation(movement)) movement.clear(); @@ -447,7 +447,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } } - mAnimation->play(mCurrentMovement, Priority_Movement, movegroup, false, + mAnimation->play(mCurrentMovement, Priority_Movement, movemask, false, speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); } } @@ -486,7 +486,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mAnimation->disable(mCurrentIdle); mCurrentIdle = idle; if(!mCurrentIdle.empty()) - mAnimation->play(mCurrentIdle, Priority_Default, MWRender::Animation::Group_All, false, + mAnimation->play(mCurrentIdle, Priority_Default, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, ~0ul, true); } @@ -602,7 +602,7 @@ void CharacterController::playDeath(float startpoint, CharacterState death) mCurrentJump = ""; mMovementAnimationControlled = true; - mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All, + mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", startpoint, 0); } @@ -868,10 +868,10 @@ void CharacterController::updateIdleStormState() mAnimation->getInfo("idlestorm", &complete); if (complete == 0) - mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, false, + mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::BlendMask_RightArm, false, 1.0f, "start", "loop start", 0.0f, 0); else if (complete == 1) - mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, false, + mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::BlendMask_RightArm, false, 1.0f, "loop start", "loop stop", 0.0f, ~0ul); } else @@ -882,7 +882,7 @@ void CharacterController::updateIdleStormState() { if (mAnimation->getCurrentTime("idlestorm") < mAnimation->getTextKeyTime("idlestorm: loop stop")) { - mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::Group_RightArm, true, + mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::BlendMask_RightArm, true, 1.0f, "loop stop", "stop", 0.0f, 0); } } @@ -989,7 +989,7 @@ bool CharacterController::updateCreatureState() if (!mCurrentWeapon.empty()) { mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_All, true, + MWRender::Animation::BlendMask_All, true, 1, startKey, stopKey, 0.0f, 0); mUpperBodyState = UpperCharState_StartToMinAttack; @@ -1064,7 +1064,7 @@ bool CharacterController::updateWeaponState() { getWeaponGroup(mWeaponType, weapgroup); mAnimation->play(weapgroup, Priority_Weapon, - MWRender::Animation::Group_UpperBody, true, + MWRender::Animation::BlendMask_UpperBody, true, 1.0f, "unequip start", "unequip stop", 0.0f, 0); mUpperBodyState = UpperCharState_UnEquipingWeap; } @@ -1075,7 +1075,7 @@ bool CharacterController::updateWeaponState() mAnimation->setWeaponGroup(weapgroup); mAnimation->play(weapgroup, Priority_Weapon, - MWRender::Animation::Group_UpperBody, true, + MWRender::Animation::BlendMask_UpperBody, true, 1.0f, "equip start", "equip stop", 0.0f, 0); mUpperBodyState = UpperCharState_EquipingWeap; @@ -1192,7 +1192,7 @@ bool CharacterController::updateWeaponState() } mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, true, + MWRender::Animation::BlendMask_UpperBody, true, weapSpeed, mAttackType+" start", mAttackType+" stop", 0.0f, 0); mUpperBodyState = UpperCharState_CastingSpell; @@ -1224,7 +1224,7 @@ bool CharacterController::updateWeaponState() Security(mPtr).probeTrap(target, item, resultMessage, resultSound); } mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, true, + MWRender::Animation::BlendMask_UpperBody, true, 1.0f, "start", "stop", 0.0, 0); mUpperBodyState = UpperCharState_FollowStartToFollowStop; @@ -1251,7 +1251,7 @@ bool CharacterController::updateWeaponState() } mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, false, + MWRender::Animation::BlendMask_UpperBody, false, weapSpeed, mAttackType+" start", mAttackType+" min attack", 0.0f, 0); mUpperBodyState = UpperCharState_StartToMinAttack; @@ -1302,7 +1302,7 @@ bool CharacterController::updateWeaponState() mAnimation->disable(mCurrentWeapon); mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, false, + MWRender::Animation::BlendMask_UpperBody, false, weapSpeed, mAttackType+" max attack", mAttackType+" min hit", 1.0f-complete, 0); @@ -1374,7 +1374,7 @@ bool CharacterController::updateWeaponState() //don't allow to continue playing hit animation on UpperBody after actor had attacked during it if(mHitState == CharState_Hit) { - mAnimation->changeGroups(mCurrentHit, MWRender::Animation::Group_LowerBody); + mAnimation->changeBlendMask(mCurrentHit, MWRender::Animation::BlendMask_LowerBody); //commenting out following 2 lines will give a bit different combat dynamics(slower) mHitState = CharState_None; mCurrentHit.clear(); @@ -1398,7 +1398,7 @@ bool CharacterController::updateWeaponState() //hack to avoid body pos desync when jumping/sneaking in 'max attack' state if(!mAnimation->isPlaying(mCurrentWeapon)) mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, false, + MWRender::Animation::BlendMask_UpperBody, false, 0, mAttackType+" min attack", mAttackType+" max attack", 0.999f, 0); break; case UpperCharState_MaxAttackToMinHit: @@ -1441,11 +1441,11 @@ bool CharacterController::updateWeaponState() mAnimation->disable(mCurrentWeapon); if (mUpperBodyState == UpperCharState_FollowStartToFollowStop) mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, true, + MWRender::Animation::BlendMask_UpperBody, true, weapSpeed, start, stop, 0.0f, 0); else mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, false, + MWRender::Animation::BlendMask_UpperBody, false, weapSpeed, start, stop, 0.0f, 0); } } @@ -1459,11 +1459,11 @@ bool CharacterController::updateWeaponState() MWBase::Environment::get().getWorld()->isSwimming(mPtr) || cls.getCreatureStats(mPtr).getMovementFlag(CreatureStats::Flag_Sneak)) { - mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_UpperBody); + mAnimation->changeBlendMask(mCurrentWeapon, MWRender::Animation::BlendMask_UpperBody); } else { - mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_All); + mAnimation->changeBlendMask(mCurrentWeapon, MWRender::Animation::BlendMask_All); } } @@ -1475,7 +1475,7 @@ bool CharacterController::updateWeaponState() && updateCarriedLeftVisible(mWeaponType)) { - mAnimation->play("torch", Priority_Torch, MWRender::Animation::Group_LeftArm, + mAnimation->play("torch", Priority_Torch, MWRender::Animation::BlendMask_LeftArm, false, 1.0f, "start", "stop", 0.0f, (~(size_t)0), true); } else if (mAnimation->isPlaying("torch")) @@ -1505,7 +1505,7 @@ void CharacterController::update(float duration) mAnimQueue.pop_front(); mAnimation->play(mAnimQueue.front().first, Priority_Default, - MWRender::Animation::Group_All, false, + MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, mAnimQueue.front().second); } } @@ -1786,7 +1786,7 @@ void CharacterController::update(float duration) mAnimQueue.pop_front(); mAnimation->play(mAnimQueue.front().first, Priority_Default, - MWRender::Animation::Group_All, false, + MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, mAnimQueue.front().second); } } @@ -1894,7 +1894,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mIdleState = CharState_SpecialIdle; mAnimation->play(groupname, Priority_Default, - MWRender::Animation::Group_All, false, 1.0f, + MWRender::Animation::BlendMask_All, false, 1.0f, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1); } else if(mode == 0) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 91f459ff2..097a4febf 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -219,7 +219,7 @@ namespace MWRender typedef std::map > ControllerMap; - ControllerMap mControllerMap[Animation::sNumGroups]; + ControllerMap mControllerMap[Animation::sNumBlendMasks]; const std::multimap& getTextKeys(); }; @@ -261,7 +261,7 @@ namespace MWRender , mHeadYawRadians(0.f) , mHeadPitchRadians(0.f) { - for(size_t i = 0;i < sNumGroups;i++) + for(size_t i = 0;i < sNumBlendMasks;i++) mAnimationTimePtr[i].reset(new AnimationTime); } @@ -299,9 +299,9 @@ namespace MWRender mResetAccumRootCallback->setAccumulate(mAccumulate); } - size_t Animation::detectAnimGroup(osg::Node* node) + size_t Animation::detectBlendMask(osg::Node* node) { - static const char sGroupRoots[sNumGroups][32] = { + static const char sBlendMaskRoots[sNumBlendMasks][32] = { "", /* Lower body / character root */ "Bip01 Spine1", /* Torso */ "Bip01 L Clavicle", /* Left arm */ @@ -311,9 +311,9 @@ namespace MWRender while(node != mObjectRoot) { const std::string &name = node->getName(); - for(size_t i = 1;i < sNumGroups;i++) + for(size_t i = 1;i < sNumBlendMasks;i++) { - if(name == sGroupRoots[i]) + if(name == sBlendMaskRoots[i]) return i; } @@ -361,13 +361,13 @@ namespace MWRender osg::Node* node = found->second; - size_t group = detectAnimGroup(node); + size_t blendMask = detectBlendMask(node); // clone the controller, because each Animation needs its own ControllerSource osg::ref_ptr cloned = osg::clone(it->second.get(), osg::CopyOp::DEEP_COPY_ALL); - cloned->setSource(mAnimationTimePtr[group]); + cloned->setSource(mAnimationTimePtr[blendMask]); - animsrc->mControllerMap[group].insert(std::make_pair(bonename, cloned)); + animsrc->mControllerMap[blendMask].insert(std::make_pair(bonename, cloned)); } mAnimSources.push_back(animsrc); @@ -390,7 +390,7 @@ namespace MWRender { mStates.clear(); - for(size_t i = 0;i < sNumGroups;i++) + for(size_t i = 0;i < sNumBlendMasks;i++) mAnimationTimePtr[i]->setTimePtr(boost::shared_ptr()); mAccumCtrl = NULL; @@ -461,7 +461,7 @@ namespace MWRender mTextKeyListener->handleTextKey(groupname, key, map); } - void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult, + void Animation::play(const std::string &groupname, int priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback) { if(!mObjectRoot || mAnimSources.empty()) @@ -505,7 +505,7 @@ namespace MWRender state.mLoopCount = loops; state.mPlaying = (state.getTime() < state.mStopTime); state.mPriority = priority; - state.mGroups = groups; + state.mBlendMask = blendMask; state.mAutoDisable = autodisable; mStates[groupname] = state; @@ -643,35 +643,35 @@ namespace MWRender mAccumCtrl = NULL; - for(size_t grp = 0;grp < sNumGroups;grp++) + for(size_t blendMask = 0;blendMask < sNumBlendMasks;blendMask++) { AnimStateMap::const_iterator active = mStates.end(); AnimStateMap::const_iterator state = mStates.begin(); for(;state != mStates.end();++state) { - if(!(state->second.mGroups&(1<second.mBlendMask&(1<second.mPriority < state->second.mPriority) active = state; } - mAnimationTimePtr[grp]->setTimePtr(active == mStates.end() ? boost::shared_ptr() : active->second.mTime); + mAnimationTimePtr[blendMask]->setTimePtr(active == mStates.end() ? boost::shared_ptr() : active->second.mTime); - // add external controllers for the AnimSource active in this group + // add external controllers for the AnimSource active in this blend mask if (active != mStates.end()) { boost::shared_ptr animsrc = active->second.mSource; - for (AnimSource::ControllerMap::iterator it = animsrc->mControllerMap[grp].begin(); it != animsrc->mControllerMap[grp].end(); ++it) + for (AnimSource::ControllerMap::iterator it = animsrc->mControllerMap[blendMask].begin(); it != animsrc->mControllerMap[blendMask].end(); ++it) { osg::ref_ptr node = mNodeMap.at(it->first); // this should not throw, we already checked for the node existing in addAnimSource node->addUpdateCallback(it->second); mActiveControllers.insert(std::make_pair(node, it->second)); - if (grp == 0 && node == mAccumRoot) + if (blendMask == 0 && node == mAccumRoot) { mAccumCtrl = it->second; @@ -690,14 +690,14 @@ namespace MWRender addControllers(); } - void Animation::changeGroups(const std::string &groupname, int groups) + void Animation::changeBlendMask(const std::string &groupname, int mask) { AnimStateMap::iterator stateiter = mStates.find(groupname); if(stateiter != mStates.end()) { - if(stateiter->second.mGroups != groups) + if(stateiter->second.mBlendMask != mask) { - stateiter->second.mGroups = groups; + stateiter->second.mBlendMask = mask; resetActiveGroups(); } return; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d23a62954..0a90489cf 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -67,16 +67,16 @@ typedef boost::shared_ptr PartHolderPtr; class Animation { public: - enum Group { - Group_LowerBody = 1<<0, + enum BlendMask { + BlendMask_LowerBody = 1<<0, - Group_Torso = 1<<1, - Group_LeftArm = 1<<2, - Group_RightArm = 1<<3, + BlendMask_Torso = 1<<1, + BlendMask_LeftArm = 1<<2, + BlendMask_RightArm = 1<<3, - Group_UpperBody = Group_Torso | Group_LeftArm | Group_RightArm, + BlendMask_UpperBody = BlendMask_Torso | BlendMask_LeftArm | BlendMask_RightArm, - Group_All = Group_LowerBody | Group_UpperBody + BlendMask_All = BlendMask_LowerBody | BlendMask_UpperBody }; class TextKeyListener @@ -90,7 +90,7 @@ public: protected: /* This is the number of *discrete* groups. */ - static const size_t sNumGroups = 4; + static const size_t sNumBlendMasks = 4; class AnimationTime : public SceneUtil::ControllerSource { @@ -133,12 +133,12 @@ protected: size_t mLoopCount; int mPriority; - int mGroups; + int mBlendMask; bool mAutoDisable; AnimState() : mStartTime(0.0f), mLoopStartTime(0.0f), mLoopStopTime(0.0f), mStopTime(0.0f), mTime(new float), mSpeedMult(1.0f), mPlaying(false), mLoopCount(0), - mPriority(0), mGroups(0), mAutoDisable(true) + mPriority(0), mBlendMask(0), mAutoDisable(true) { } ~AnimState(); @@ -176,7 +176,7 @@ protected: typedef std::multimap, osg::ref_ptr > ControllerMap; ControllerMap mActiveControllers; - boost::shared_ptr mAnimationTimePtr[sNumGroups]; + boost::shared_ptr mAnimationTimePtr[sNumBlendMasks]; // Stored in all lowercase for a case-insensitive lookup typedef std::map > NodeMap; @@ -213,7 +213,7 @@ protected: */ void resetActiveGroups(); - size_t detectAnimGroup(osg::Node* node); + size_t detectBlendMask(osg::Node* node); /* Updates the position of the accum root node for the given time, and * returns the wanted movement vector from the previous time. */ @@ -304,7 +304,7 @@ public: * \param priority Priority of the animation. The animation will play on * bone groups that don't have another animation set of a * higher priority. - * \param groups Bone groups to play the animation on. + * \param blendMask Bone groups to play the animation on. * \param autodisable Automatically disable the animation when it stops * playing. * \param speedmult Speed multiplier for the animation. @@ -319,7 +319,7 @@ public: * \param loopFallback Allow looping an animation that has no loop keys, i.e. fall back to use * the "start" and "stop" keys for looping? */ - void play(const std::string &groupname, int priority, int groups, bool autodisable, + void play(const std::string &groupname, int priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback=false); @@ -358,7 +358,7 @@ public: * \param groupname Animation group to disable. */ void disable(const std::string &groupname); - void changeGroups(const std::string &groupname, int group); + void changeBlendMask(const std::string &groupname, int mask); /** Retrieves the velocity (in units per second) that the animation will move. */ float getVelocity(const std::string &groupname) const; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 32e51c4d6..b4e1189f7 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -241,13 +241,13 @@ namespace MWRender mAnimation->showCarriedLeft(showCarriedLeft); mCurrentAnimGroup = groupname; - mAnimation->play(mCurrentAnimGroup, 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); + mAnimation->play(mCurrentAnimGroup, 1, Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, 0); MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name() && showCarriedLeft) { if(!mAnimation->getInfo("torch")) - mAnimation->play("torch", 2, MWRender::Animation::Group_LeftArm, false, + mAnimation->play("torch", 2, Animation::BlendMask_LeftArm, false, 1.0f, "start", "stop", 0.0f, ~0ul, true); } else if(mAnimation->getInfo("torch")) @@ -357,7 +357,7 @@ namespace MWRender void RaceSelectionPreview::onSetup () { - mAnimation->play("idle", 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); + mAnimation->play("idle", 1, Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, 0); mAnimation->runAnimation(0.f); // attach camera to follow the head node From e93a578f237b67f9e6d5da361220589895f08dde Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 14:18:31 +0200 Subject: [PATCH 062/419] Extend the animation priority system to one priority value per bone group / distinct blend mask --- apps/openmw/mwrender/animation.cpp | 14 ++++++------- apps/openmw/mwrender/animation.hpp | 33 ++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 097a4febf..2be2165ea 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -461,7 +461,7 @@ namespace MWRender mTextKeyListener->handleTextKey(groupname, key, map); } - void Animation::play(const std::string &groupname, int priority, int blendMask, bool autodisable, float speedmult, + void Animation::play(const std::string &groupname, AnimPriority priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback) { if(!mObjectRoot || mAnimSources.empty()) @@ -473,8 +473,6 @@ namespace MWRender return; } - priority = std::max(0, priority); - AnimStateMap::iterator stateiter = mStates.begin(); while(stateiter != mStates.end()) { @@ -653,7 +651,7 @@ namespace MWRender if(!(state->second.mBlendMask&(1<second.mPriority < state->second.mPriority) + if(active == mStates.end() || active->second.mPriority.mPriority[blendMask] < state->second.mPriority.mPriority[blendMask]) active = state; } @@ -690,6 +688,7 @@ namespace MWRender addControllers(); } + // TODO: remove void Animation::changeBlendMask(const std::string &groupname, int mask) { AnimStateMap::iterator stateiter = mStates.find(groupname); @@ -1208,9 +1207,10 @@ namespace MWRender { for (AnimStateMap::const_iterator stateiter = mStates.begin(); stateiter != mStates.end(); ++stateiter) { - if((stateiter->second.mPriority > MWMechanics::Priority_Movement - && stateiter->second.mPriority < MWMechanics::Priority_Torch) - || stateiter->second.mPriority == MWMechanics::Priority_Death) + if (stateiter->second.mPriority.contains(int(MWMechanics::Priority_Hit)) + || stateiter->second.mPriority.contains(int(MWMechanics::Priority_Weapon)) + || stateiter->second.mPriority.contains(int(MWMechanics::Priority_Knockdown)) + || stateiter->second.mPriority.contains(int(MWMechanics::Priority_Death))) return false; } return true; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 0a90489cf..90d2a68a3 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -118,6 +118,35 @@ protected: struct AnimSource; + /// Holds an animation priority value for each distinct bone blendmask. + struct AnimPriority + { + /// Convenience constructor, initialises all priorities to the same value. + AnimPriority(int priority) + { + for (unsigned int i=0; i mSource; float mStartTime; @@ -132,7 +161,7 @@ protected: bool mPlaying; size_t mLoopCount; - int mPriority; + AnimPriority mPriority; int mBlendMask; bool mAutoDisable; @@ -319,7 +348,7 @@ public: * \param loopFallback Allow looping an animation that has no loop keys, i.e. fall back to use * the "start" and "stop" keys for looping? */ - void play(const std::string &groupname, int priority, int blendMask, bool autodisable, + void play(const std::string &groupname, AnimPriority priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback=false); From 50db6ed3968df6b3e16cf9315b6f3a47d8ac8227 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 14:40:36 +0200 Subject: [PATCH 063/419] Use the extended animation priority for weapon animations --- apps/openmw/mwmechanics/character.cpp | 56 +++++++----------- apps/openmw/mwrender/animation.hpp | 85 ++++++++++++++------------- 2 files changed, 66 insertions(+), 75 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index bd15b6a73..8f813ceb1 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1051,6 +1051,9 @@ bool CharacterController::updateWeaponState() } } + MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon); + priorityWeapon.mPriority[MWRender::Animation::BoneGroup_LowerBody] = 0; + bool forcestateupdate = false; if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut && mHitState != CharState_Hit) @@ -1063,8 +1066,8 @@ bool CharacterController::updateWeaponState() if(weaptype == WeapType_None) { getWeaponGroup(mWeaponType, weapgroup); - mAnimation->play(weapgroup, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, true, + mAnimation->play(weapgroup, priorityWeapon, + MWRender::Animation::BlendMask_All, true, 1.0f, "unequip start", "unequip stop", 0.0f, 0); mUpperBodyState = UpperCharState_UnEquipingWeap; } @@ -1074,8 +1077,8 @@ bool CharacterController::updateWeaponState() mAnimation->showWeapons(false); mAnimation->setWeaponGroup(weapgroup); - mAnimation->play(weapgroup, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, true, + mAnimation->play(weapgroup, priorityWeapon, + MWRender::Animation::BlendMask_All, true, 1.0f, "equip start", "equip stop", 0.0f, 0); mUpperBodyState = UpperCharState_EquipingWeap; @@ -1191,8 +1194,8 @@ bool CharacterController::updateWeaponState() case 2: mAttackType = "target"; break; } - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, true, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, true, weapSpeed, mAttackType+" start", mAttackType+" stop", 0.0f, 0); mUpperBodyState = UpperCharState_CastingSpell; @@ -1223,8 +1226,8 @@ bool CharacterController::updateWeaponState() else if(item.getTypeName() == typeid(ESM::Probe).name()) Security(mPtr).probeTrap(target, item, resultMessage, resultSound); } - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, true, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, true, 1.0f, "start", "stop", 0.0, 0); mUpperBodyState = UpperCharState_FollowStartToFollowStop; @@ -1250,8 +1253,8 @@ bool CharacterController::updateWeaponState() determineAttackType(); } - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, false, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, false, weapSpeed, mAttackType+" start", mAttackType+" min attack", 0.0f, 0); mUpperBodyState = UpperCharState_StartToMinAttack; @@ -1301,8 +1304,8 @@ bool CharacterController::updateWeaponState() mAttackStrength = attackStrength; mAnimation->disable(mCurrentWeapon); - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, false, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, false, weapSpeed, mAttackType+" max attack", mAttackType+" min hit", 1.0f-complete, 0); @@ -1397,8 +1400,8 @@ bool CharacterController::updateWeaponState() case UpperCharState_MinAttackToMaxAttack: //hack to avoid body pos desync when jumping/sneaking in 'max attack' state if(!mAnimation->isPlaying(mCurrentWeapon)) - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, false, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, false, 0, mAttackType+" min attack", mAttackType+" max attack", 0.999f, 0); break; case UpperCharState_MaxAttackToMinHit: @@ -1440,33 +1443,16 @@ bool CharacterController::updateWeaponState() { mAnimation->disable(mCurrentWeapon); if (mUpperBodyState == UpperCharState_FollowStartToFollowStop) - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, true, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, true, weapSpeed, start, stop, 0.0f, 0); else - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::BlendMask_UpperBody, false, + mAnimation->play(mCurrentWeapon, priorityWeapon, + MWRender::Animation::BlendMask_All, false, weapSpeed, start, stop, 0.0f, 0); } } - //if playing combat animation and lowerbody is not busy switch to whole body animation - if((weaptype != WeapType_None || mUpperBodyState == UpperCharState_UnEquipingWeap) && animPlaying) - { - if( mMovementState != CharState_None || - mJumpState != JumpState_None || - mHitState != CharState_None || - MWBase::Environment::get().getWorld()->isSwimming(mPtr) || - cls.getCreatureStats(mPtr).getMovementFlag(CreatureStats::Flag_Sneak)) - { - mAnimation->changeBlendMask(mCurrentWeapon, MWRender::Animation::BlendMask_UpperBody); - } - else - { - mAnimation->changeBlendMask(mCurrentWeapon, MWRender::Animation::BlendMask_All); - } - } - if (mPtr.getClass().hasInventoryStore(mPtr)) { MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 90d2a68a3..35c0b5346 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -67,9 +67,15 @@ typedef boost::shared_ptr PartHolderPtr; class Animation { public: + enum BoneGroup { + BoneGroup_LowerBody = 0, + BoneGroup_Torso, + BoneGroup_LeftArm, + BoneGroup_RightArm + }; + enum BlendMask { BlendMask_LowerBody = 1<<0, - BlendMask_Torso = 1<<1, BlendMask_LeftArm = 1<<2, BlendMask_RightArm = 1<<3, @@ -78,47 +84,10 @@ public: BlendMask_All = BlendMask_LowerBody | BlendMask_UpperBody }; - - class TextKeyListener - { - public: - virtual void handleTextKey(const std::string &groupname, const std::multimap::const_iterator &key, - const std::multimap& map) = 0; - }; - - void setTextKeyListener(TextKeyListener* listener); - -protected: - /* This is the number of *discrete* groups. */ + /* This is the number of *discrete* blend masks. */ static const size_t sNumBlendMasks = 4; - class AnimationTime : public SceneUtil::ControllerSource - { - private: - boost::shared_ptr mTimePtr; - - public: - - void setTimePtr(boost::shared_ptr time) - { mTimePtr = time; } - boost::shared_ptr getTimePtr() const - { return mTimePtr; } - - virtual float getValue(osg::NodeVisitor* nv); - }; - - class NullAnimationTime : public SceneUtil::ControllerSource - { - public: - virtual float getValue(osg::NodeVisitor *nv) - { - return 0.f; - } - }; - - struct AnimSource; - - /// Holds an animation priority value for each distinct bone blendmask. + /// Holds an animation priority value for each BoneGroup. struct AnimPriority { /// Convenience constructor, initialises all priorities to the same value. @@ -147,6 +116,42 @@ protected: int mPriority[sNumBlendMasks]; }; + class TextKeyListener + { + public: + virtual void handleTextKey(const std::string &groupname, const std::multimap::const_iterator &key, + const std::multimap& map) = 0; + }; + + void setTextKeyListener(TextKeyListener* listener); + +protected: + class AnimationTime : public SceneUtil::ControllerSource + { + private: + boost::shared_ptr mTimePtr; + + public: + + void setTimePtr(boost::shared_ptr time) + { mTimePtr = time; } + boost::shared_ptr getTimePtr() const + { return mTimePtr; } + + virtual float getValue(osg::NodeVisitor* nv); + }; + + class NullAnimationTime : public SceneUtil::ControllerSource + { + public: + virtual float getValue(osg::NodeVisitor *nv) + { + return 0.f; + } + }; + + struct AnimSource; + struct AnimState { boost::shared_ptr mSource; float mStartTime; From cf14d1748c50dad6a64c8a7019c7fe454b09652a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 14:47:29 +0200 Subject: [PATCH 064/419] Use the extended animation priority for Hit animations --- apps/openmw/mwmechanics/character.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8f813ceb1..ea0d4f322 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1374,15 +1374,6 @@ bool CharacterController::updateWeaponState() mAnimation->attachArrow(); mUpperBodyState = UpperCharState_WeapEquiped; - //don't allow to continue playing hit animation on UpperBody after actor had attacked during it - if(mHitState == CharState_Hit) - { - mAnimation->changeBlendMask(mCurrentHit, MWRender::Animation::BlendMask_LowerBody); - //commenting out following 2 lines will give a bit different combat dynamics(slower) - mHitState = CharState_None; - mCurrentHit.clear(); - mPtr.getClass().getCreatureStats(mPtr).setHitRecovery(false); - } } else if(mUpperBodyState == UpperCharState_UnEquipingWeap) mUpperBodyState = UpperCharState_Nothing; From 83cceeee7283183db18e40b1890a20c55dae4ad3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 14:54:37 +0200 Subject: [PATCH 065/419] Use the extended animation priority for Block animations, allow starting attacks during a block animation (Fixes #2761) --- apps/openmw/mwmechanics/character.cpp | 11 +++++++---- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ea0d4f322..a71f8d160 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -270,7 +270,9 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat { mHitState = CharState_Block; mCurrentHit = "shield"; - mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "block start", "block stop", 0.0f, 0); + MWRender::Animation::AnimPriority priorityBlock (Priority_Hit); + priorityBlock.mPriority[MWRender::Animation::BoneGroup_LeftArm] = Priority_Block; + mAnimation->play(mCurrentHit, priorityBlock, MWRender::Animation::BlendMask_All, true, 1, "block start", "block stop", 0.0f, 0); } // Cancel upper body animations @@ -1148,7 +1150,7 @@ bool CharacterController::updateWeaponState() bool animPlaying; if(mAttackingOrSpell) { - if(mUpperBodyState == UpperCharState_WeapEquiped && mHitState == CharState_None) + if(mUpperBodyState == UpperCharState_WeapEquiped && (mHitState == CharState_None || mHitState == CharState_Block)) { MWBase::Environment::get().getWorld()->breakInvisibility(mPtr); mAttackType.clear(); @@ -2029,12 +2031,13 @@ void CharacterController::setAttackingOrSpell(bool attackingOrSpell) bool CharacterController::readyToPrepareAttack() const { - return mHitState == CharState_None && mUpperBodyState <= UpperCharState_WeapEquiped; + return (mHitState == CharState_None || mHitState == CharState_Block) + && mUpperBodyState <= UpperCharState_WeapEquiped; } bool CharacterController::readyToStartAttack() const { - if (mHitState != CharState_None) + if (mHitState != CharState_None && mHitState != CharState_Block) return false; if (mPtr.getClass().hasInventoryStore(mPtr) || mPtr.getClass().isBipedal(mPtr)) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index b239b4a92..6b530ae2a 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -32,6 +32,7 @@ enum Priority { Priority_Movement, Priority_Hit, Priority_Weapon, + Priority_Block, Priority_Knockdown, Priority_Torch, Priority_Storm, From 3656851750b089a897d5b0077f0177808d7412f1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 14:55:33 +0200 Subject: [PATCH 066/419] Remove the now unused changeBlendMask --- apps/openmw/mwrender/animation.cpp | 15 --------------- apps/openmw/mwrender/animation.hpp | 1 - 2 files changed, 16 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2be2165ea..84f46c4ab 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -688,21 +688,6 @@ namespace MWRender addControllers(); } - // TODO: remove - void Animation::changeBlendMask(const std::string &groupname, int mask) - { - AnimStateMap::iterator stateiter = mStates.find(groupname); - if(stateiter != mStates.end()) - { - if(stateiter->second.mBlendMask != mask) - { - stateiter->second.mBlendMask = mask; - resetActiveGroups(); - } - return; - } - } - void Animation::stopLooping(const std::string& groupname) { AnimStateMap::iterator stateiter = mStates.find(groupname); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 35c0b5346..1cf2ce9ba 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -392,7 +392,6 @@ public: * \param groupname Animation group to disable. */ void disable(const std::string &groupname); - void changeBlendMask(const std::string &groupname, int mask); /** Retrieves the velocity (in units per second) that the animation will move. */ float getVelocity(const std::string &groupname) const; From 17ada63fcb87d45b5da89d1efa33d24e229236e8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 15:46:31 +0200 Subject: [PATCH 067/419] Don't play turning animations on the upperbody when in first person mode (Fixes #2287) --- apps/openmw/mwmechanics/character.cpp | 50 ++++++++++++++++----------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a71f8d160..95546dca9 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -355,55 +355,55 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat { mMovementState = movement; - std::string movement; + std::string movementAnimName; MWRender::Animation::BlendMask movemask = MWRender::Animation::BlendMask_All; const StateInfo *movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(mMovementState)); if(movestate != sMovementListEnd) { - movement = movestate->groupname; - if(weap != sWeaponTypeListEnd && movement.find("swim") == std::string::npos) + movementAnimName = movestate->groupname; + if(weap != sWeaponTypeListEnd && movementAnimName.find("swim") == std::string::npos) { - movement += weap->shortgroup; - if(!mAnimation->hasAnimation(movement)) + movementAnimName += weap->shortgroup; + if(!mAnimation->hasAnimation(movementAnimName)) { movemask = MWRender::Animation::BlendMask_LowerBody; - movement = movestate->groupname; + movementAnimName = movestate->groupname; } } - if(!mAnimation->hasAnimation(movement)) + if(!mAnimation->hasAnimation(movementAnimName)) { - std::string::size_type swimpos = movement.find("swim"); + std::string::size_type swimpos = movementAnimName.find("swim"); if(swimpos == std::string::npos) { - std::string::size_type runpos = movement.find("run"); + std::string::size_type runpos = movementAnimName.find("run"); if (runpos != std::string::npos) { - movement.replace(runpos, runpos+3, "walk"); - if (!mAnimation->hasAnimation(movement)) - movement.clear(); + movementAnimName.replace(runpos, runpos+3, "walk"); + if (!mAnimation->hasAnimation(movementAnimName)) + movementAnimName.clear(); } else - movement.clear(); + movementAnimName.clear(); } else { movemask = MWRender::Animation::BlendMask_LowerBody; - movement.erase(swimpos, 4); - if(!mAnimation->hasAnimation(movement)) - movement.clear(); + movementAnimName.erase(swimpos, 4); + if(!mAnimation->hasAnimation(movementAnimName)) + movementAnimName.clear(); } } } /* If we're playing the same animation, restart from the loop start instead of the * beginning. */ - int mode = ((movement == mCurrentMovement) ? 2 : 1); + int mode = ((movementAnimName == mCurrentMovement) ? 2 : 1); mMovementAnimationControlled = true; mAnimation->disable(mCurrentMovement); - mCurrentMovement = movement; + mCurrentMovement = movementAnimName; if(!mCurrentMovement.empty()) { float vel, speedmult = 1.0f; @@ -449,7 +449,17 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } } - mAnimation->play(mCurrentMovement, Priority_Movement, movemask, false, + MWRender::Animation::AnimPriority priorityMovement (Priority_Movement); + if ((movement == CharState_TurnLeft || movement == CharState_TurnRight) + && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() + && MWBase::Environment::get().getWorld()->isFirstPerson()) + { + priorityMovement.mPriority[MWRender::Animation::BoneGroup_Torso] = 0; + priorityMovement.mPriority[MWRender::Animation::BoneGroup_LeftArm] = 0; + priorityMovement.mPriority[MWRender::Animation::BoneGroup_RightArm] = 0; + } + + mAnimation->play(mCurrentMovement, priorityMovement, movemask, false, speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); } } @@ -458,7 +468,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat // FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming update), // the idle animation should be displayed if ((mUpperBodyState != UpperCharState_Nothing - || mMovementState != CharState_None + || (mMovementState != CharState_None && mMovementState != CharState_TurnLeft && mMovementState != CharState_TurnRight) || mHitState != CharState_None) && !mPtr.getClass().isBipedal(mPtr)) idle = CharState_None; From 992b7703155300f6a0c83b47f78f6513561f0a66 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 18:52:23 +0200 Subject: [PATCH 068/419] Don't set OnPcEquip for items that failed to equip (Fixes #2776) --- apps/openmw/mwgui/inventorywindow.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 392a4a84a..39f476403 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -436,6 +436,20 @@ namespace MWGui { const std::string& script = ptr.getClass().getScript(ptr); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + // early-out for items that need to be equipped, but can't be equipped: we don't want to set OnPcEquip in that case + if (!ptr.getClass().getEquipmentSlots(ptr).first.empty()) + { + std::pair canEquip = ptr.getClass().canBeEquipped(ptr, player); + if (canEquip.first == 0) + { + MWBase::Environment::get().getWindowManager()->messageBox(canEquip.second); + updateItemView(); + return; + } + } + // If the item has a script, set its OnPcEquip to 1 if (!script.empty() // Another morrowind oddity: when an item has skipped equipping and pcskipequip is reset to 0 afterwards, @@ -455,7 +469,7 @@ namespace MWGui { boost::shared_ptr action = ptr.getClass().use(ptr); - action->execute (MWBase::Environment::get().getWorld()->getPlayerPtr()); + action->execute (player); mSkippedToEquip = MWWorld::Ptr(); } From f8d360190d7443337e5a1d48d8b0505491c5fd73 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Jul 2015 19:10:09 +0200 Subject: [PATCH 069/419] Remove an unneeded virtual --- apps/openmw/mwgui/windowbase.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 195b6c384..43fb8901e 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -21,16 +21,16 @@ namespace MWGui // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; - ///Unhides the window + /// Notify that window has been made visible virtual void open() {} - ///Hides the window + /// Notify that window has been hidden virtual void close () {} - ///Gracefully exits the window + /// Gracefully exits the window virtual void exit() {} - ///Sets the visibility of the window + /// Sets the visibility of the window virtual void setVisible(bool visible); - ///Returns the visibility state of the window - virtual bool isVisible(); + /// Returns the visibility state of the window + bool isVisible(); void center(); }; From 2016ff773fbf0376c28dfaa9df0ff65d47052f84 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Jul 2015 12:36:20 +0200 Subject: [PATCH 070/419] display script errors in script subview --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/world/scripterrortable.cpp | 87 +++++++++++++++++++++ apps/opencs/view/world/scripterrortable.hpp | 45 +++++++++++ apps/opencs/view/world/scriptsubview.cpp | 33 +++++++- apps/opencs/view/world/scriptsubview.hpp | 4 + 5 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 apps/opencs/view/world/scripterrortable.cpp create mode 100644 apps/opencs/view/world/scripterrortable.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 4c7801d46..96e5a5b32 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -64,7 +64,7 @@ opencs_units (view/world table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator cellcreator referenceablecreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable - dialoguespinbox recordbuttonbar tableeditidaction + dialoguespinbox recordbuttonbar tableeditidaction scripterrortable ) opencs_units_noqt (view/world diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp new file mode 100644 index 000000000..0c97339dc --- /dev/null +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -0,0 +1,87 @@ + +#include "scripterrortable.hpp" + +#include + +#include +#include +#include +#include +#include + +#include "../../model/doc/document.hpp" + + +void CSVWorld::ScriptErrorTable::report (const std::string& message, const Compiler::TokenLoc& loc, Type type) +{ + addMessage (message, type==Compiler::ErrorHandler::WarningMessage ? + CSMDoc::Message::Severity_Warning : CSMDoc::Message::Severity_Error, loc.mLine); +} + +void CSVWorld::ScriptErrorTable::report (const std::string& message, Type type) +{ + addMessage (message, type==Compiler::ErrorHandler::WarningMessage ? + CSMDoc::Message::Severity_Warning : CSMDoc::Message::Severity_Error); +} + +void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, + CSMDoc::Message::Severity severity, int line) +{ + int row = rowCount(); + + setRowCount (row+1); + + setItem (row, 0, new QTableWidgetItem ("")); + + if (line!=-1) + { + QTableWidgetItem *item = new QTableWidgetItem; + item->setData (Qt::DisplayRole, line+1); + setItem (row, 1, item); + } + + setItem (row, 2, new QTableWidgetItem (QString::fromUtf8 (message.c_str()))); +} + +CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent) +: QTableWidget (parent), mContext (document.getData()) +{ + setColumnCount (3); + + QStringList headers; + headers << "Severity" << "Line" << "Description"; + setHorizontalHeaderLabels (headers); + horizontalHeader()->setStretchLastSection (true); + + Compiler::registerExtensions (mExtensions); + mContext.setExtensions (&mExtensions); +} + +void CSVWorld::ScriptErrorTable::updateUserSetting (const QString& name, const QStringList& value) +{ + +} + +void CSVWorld::ScriptErrorTable::update (const std::string& source) +{ + setRowCount (0); + + try + { + std::istringstream input (source); + + Compiler::Scanner scanner (*this, input, mContext.getExtensions()); + + Compiler::FileParser parser (*this, mContext); + + scanner.scan (parser); + } + catch (const Compiler::SourceException&) + { + // error has already been reported via error handler + } + catch (const std::exception& error) + { + addMessage (error.what(), CSMDoc::Message::Severity_SeriousError); + } +} diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp new file mode 100644 index 000000000..791125c12 --- /dev/null +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -0,0 +1,45 @@ +#ifndef CSV_WORLD_SCRIPTERRORTABLE_H +#define CSV_WORLD_SCRIPTERRORTABLE_H + +#include + +#include +#include + +#include "../../model/world/scriptcontext.hpp" +#include "../../model/doc/messages.hpp" + +namespace CSMDoc +{ + class Document; +} + +namespace CSVWorld +{ + class ScriptErrorTable : public QTableWidget, private Compiler::ErrorHandler + { + Q_OBJECT + + Compiler::Extensions mExtensions; + CSMWorld::ScriptContext mContext; + + virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); + ///< Report error to the user. + + virtual void report (const std::string& message, Type type); + ///< Report a file related error + + void addMessage (const std::string& message, CSMDoc::Message::Severity severity, + int line = -1); + + public: + + ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent = 0); + + void updateUserSetting (const QString& name, const QStringList& value); + + void update (const std::string& source); + }; +} + +#endif diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 181400c88..d48e647d9 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "../../model/doc/document.hpp" #include "../../model/world/universalid.hpp" @@ -17,6 +18,7 @@ #include "recordbuttonbar.hpp" #include "tablebottombox.hpp" #include "genericcreator.hpp" +#include "scripterrortable.hpp" void CSVWorld::ScriptSubView::addButtonBar() { @@ -40,7 +42,16 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: std::vector selection (1, id.getId()); mCommandDispatcher.setSelection (selection); - mLayout.addWidget (mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this), 2); + mMain = new QSplitter (this); + mMain->setOrientation (Qt::Vertical); + mLayout.addWidget (mMain, 2); + + mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this); + mMain->addWidget (mEditor); + mMain->setCollapsible (0, false); + + mErrors = new ScriptErrorTable (document, this); + mMain->addWidget (mErrors); QWidget *widget = new QWidget (this);; widget->setLayout (&mLayout); @@ -60,7 +71,9 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: if (mColumn==-1) throw std::logic_error ("Can't find script column"); - mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString()); + QString source = mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString(); + + mEditor->setPlainText (source); // bottom box and buttons mBottom = new TableBottomBox (CreatorFactory(), document, id, this); @@ -83,6 +96,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: updateStatusBar(); connect(mEditor, SIGNAL(cursorPositionChanged()), this, SLOT(updateStatusBar())); + + mErrors->update (source.toUtf8().constData()); } void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) @@ -116,6 +131,8 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr if (mButtons) mButtons->updateUserSetting (name, value); + + mErrors->updateUserSetting (name, value); } void CSVWorld::ScriptSubView::setStatusBar (bool show) @@ -173,8 +190,12 @@ void CSVWorld::ScriptSubView::textChanged() ScriptEdit::ChangeLock lock (*mEditor); + QString source = mEditor->toPlainText(); + mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*mModel, - mModel->getModelIndex (getUniversalId().getId(), mColumn), mEditor->toPlainText())); + mModel->getModelIndex (getUniversalId().getId(), mColumn), source)); + + mErrors->update (source.toUtf8().constData()); } void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) @@ -189,9 +210,13 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo if (index.row()>=topLeft.row() && index.row()<=bottomRight.row() && index.column()>=topLeft.column() && index.column()<=bottomRight.column()) { + QString source = mModel->data (index).toString(); + QTextCursor cursor = mEditor->textCursor(); - mEditor->setPlainText (mModel->data (index).toString()); + mEditor->setPlainText (source); mEditor->setTextCursor (cursor); + + mErrors->update (source.toUtf8().constData()); } } diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 6e5276c68..0b6f4d923 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -10,6 +10,7 @@ class QModelIndex; class QLabel; class QVBoxLayout; +class QSplitter; namespace CSMDoc { @@ -26,6 +27,7 @@ namespace CSVWorld class ScriptEdit; class RecordButtonBar; class TableBottomBox; + class ScriptErrorTable; class ScriptSubView : public CSVDoc::SubView { @@ -39,6 +41,8 @@ namespace CSVWorld RecordButtonBar *mButtons; CSMWorld::CommandDispatcher mCommandDispatcher; QVBoxLayout mLayout; + QSplitter *mMain; + ScriptErrorTable *mErrors; private: From 2d8a78726dbab573041cd97d922a4814bc3471ff Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Jul 2015 14:09:14 +0200 Subject: [PATCH 071/419] improved error reporting --- apps/opencs/view/world/scripterrortable.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 0c97339dc..cb793237a 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -14,7 +14,10 @@ void CSVWorld::ScriptErrorTable::report (const std::string& message, const Compiler::TokenLoc& loc, Type type) { - addMessage (message, type==Compiler::ErrorHandler::WarningMessage ? + std::ostringstream stream; + stream << message << " (" << loc.mLiteral << ")"; + + addMessage (stream.str(), type==Compiler::ErrorHandler::WarningMessage ? CSMDoc::Message::Severity_Warning : CSMDoc::Message::Severity_Error, loc.mLine); } From 9b12b4f1e25dff384137a8915ddc460acdbd749e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 16 Jul 2015 14:46:02 +0200 Subject: [PATCH 072/419] refactored mapping from message severity enum to string --- apps/opencs/model/doc/messages.cpp | 16 +++++++++++++++- apps/opencs/model/doc/messages.hpp | 8 +++++--- apps/opencs/model/tools/reportmodel.cpp | 20 +++++++------------- apps/opencs/view/world/scripterrortable.cpp | 2 +- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/apps/opencs/model/doc/messages.cpp b/apps/opencs/model/doc/messages.cpp index bd6e808c8..c8d26d39b 100644 --- a/apps/opencs/model/doc/messages.cpp +++ b/apps/opencs/model/doc/messages.cpp @@ -8,6 +8,20 @@ CSMDoc::Message::Message (const CSMWorld::UniversalId& id, const std::string& me : mId (id), mMessage (message), mHint (hint), mSeverity (severity) {} +std::string CSMDoc::Message::toString (Severity severity) +{ + switch (severity) + { + case CSMDoc::Message::Severity_Info: return "Information"; + case CSMDoc::Message::Severity_Warning: return "Warning"; + case CSMDoc::Message::Severity_Error: return "Error"; + case CSMDoc::Message::Severity_SeriousError: return "Serious Error"; + case CSMDoc::Message::Severity_Default: break; + } + + return ""; +} + CSMDoc::Messages::Messages (Message::Severity default_) : mDefault (default_) @@ -18,7 +32,7 @@ void CSMDoc::Messages::add (const CSMWorld::UniversalId& id, const std::string& { if (severity==Message::Severity_Default) severity = mDefault; - + mMessages.push_back (Message (id, message, hint, severity)); } diff --git a/apps/opencs/model/doc/messages.hpp b/apps/opencs/model/doc/messages.hpp index 86f5feb15..429feae4e 100644 --- a/apps/opencs/model/doc/messages.hpp +++ b/apps/opencs/model/doc/messages.hpp @@ -21,18 +21,20 @@ namespace CSMDoc // reporting it correctly Severity_Default = 4 }; - + CSMWorld::UniversalId mId; std::string mMessage; std::string mHint; Severity mSeverity; Message(); - + Message (const CSMWorld::UniversalId& id, const std::string& message, const std::string& hint, Severity severity); + + static std::string toString (Severity severity); }; - + class Messages { public: diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 480691710..4bf7d1581 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -13,7 +13,7 @@ CSMTools::ReportModel::ReportModel (bool fieldColumn, bool severityColumn) if (severityColumn) mColumnSeverity = index++; - + if (fieldColumn) mColumnField = index++; @@ -46,7 +46,7 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const case Column_Type: return static_cast (mRows.at (index.row()).mId.getType()); - + case Column_Id: { CSMWorld::UniversalId id = mRows.at (index.row()).mId; @@ -56,7 +56,7 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const return QString ("-"); } - + case Column_Hint: return QString::fromUtf8 (mRows.at (index.row()).mHint.c_str()); @@ -85,16 +85,10 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const if (index.column()==mColumnSeverity) { - switch (mRows.at (index.row()).mSeverity) - { - case CSMDoc::Message::Severity_Info: return "Information"; - case CSMDoc::Message::Severity_Warning: return "Warning"; - case CSMDoc::Message::Severity_Error: return "Error"; - case CSMDoc::Message::Severity_SeriousError: return "Serious Error"; - case CSMDoc::Message::Severity_Default: break; - } + return QString::fromUtf8 ( + CSMDoc::Message::toString (mRows.at (index.row()).mSeverity).c_str()); } - + return QVariant(); } @@ -144,7 +138,7 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p void CSMTools::ReportModel::add (const CSMDoc::Message& message) { beginInsertRows (QModelIndex(), mRows.size(), mRows.size()); - + mRows.push_back (message); endInsertRows(); diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index cb793237a..dfa036824 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -34,7 +34,7 @@ void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, setRowCount (row+1); - setItem (row, 0, new QTableWidgetItem ("")); + setItem (row, 0, new QTableWidgetItem (QString::fromUtf8 (CSMDoc::Message::toString (severity).c_str()))); if (line!=-1) { From f6f82d433c77cb68b16d88785ed210179287addd Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 16 Jul 2015 19:55:05 +0200 Subject: [PATCH 073/419] Fix bug with loop key assignment Animations with time of "loop start" == time of "loop stop" were not getting their loop times assigned correctly. This fixes incorrect playing of the jump animation, one aspect of Bug #2286. --- apps/openmw/mwrender/animation.cpp | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 84f46c4ab..dab289f6c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -598,23 +598,20 @@ namespace MWRender state.setTime(state.mStartTime + ((state.mStopTime - state.mStartTime) * startpoint)); // mLoopStartTime and mLoopStopTime normally get assigned when encountering these keys while playing the animation - // (see handleTextKey). But if startpoint is already past these keys, we need to assign them now. - if(state.getTime() > state.mStartTime) + // (see handleTextKey). But if startpoint is already past these keys, or start time is == stop time, we need to assign them now. + const std::string loopstarttag = groupname+": loop start"; + const std::string loopstoptag = groupname+": loop stop"; + + NifOsg::TextKeyMap::const_reverse_iterator key(groupend); + for (; key != startkey && key != keys.rend(); ++key) { - const std::string loopstarttag = groupname+": loop start"; - const std::string loopstoptag = groupname+": loop stop"; + if (key->first > state.getTime()) + continue; - NifOsg::TextKeyMap::const_reverse_iterator key(groupend); - for (; key != startkey && key != keys.rend(); ++key) - { - if (key->first > state.getTime()) - continue; - - if (key->second == loopstarttag) - state.mLoopStartTime = key->first; - else if (key->second == loopstoptag) - state.mLoopStopTime = key->first; - } + if (key->second == loopstarttag) + state.mLoopStartTime = key->first; + else if (key->second == loopstoptag) + state.mLoopStopTime = key->first; } return true; From b5c79738f10822f0814e3244100ed5ade56bb99b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 16 Jul 2015 19:56:09 +0200 Subject: [PATCH 074/419] Fix enchantments casting more than once per button press, broken by a1432b0255dd659 --- apps/openmw/mwmechanics/character.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 95546dca9..9ccee84f6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -43,6 +43,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/player.hpp" namespace { @@ -1169,6 +1170,10 @@ bool CharacterController::updateWeaponState() // Unset casting flag, otherwise pressing the mouse button down would // continue casting every frame if there is no animation mAttackingOrSpell = false; + if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + { + MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false); + } const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); From cc59493cb2e227561eea680c5e34c8dc794cbf2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 16 Jul 2015 20:03:16 +0200 Subject: [PATCH 075/419] Don't restart the jump animation when equipping a different weapon (Fixes #2286) --- apps/openmw/mwmechanics/character.cpp | 39 ++++++++++++++------------- apps/openmw/mwmechanics/character.hpp | 2 +- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9ccee84f6..8fa02c3cd 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -237,7 +237,7 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i return prefix + toString(roll); } -void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force) +void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force) { // hit recoils/knockdown animations handling if(mPtr.getClass().isActor()) @@ -314,40 +314,41 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if (!mPtr.getClass().isBipedal(mPtr)) weap = sWeaponTypeListEnd; - if(force && mJumpState != JumpState_None) + if(force || jump != mJumpState) { - std::string jump; + bool startAtLoop = (jump == mJumpState); + mJumpState = jump; + + std::string jumpAnimName; MWRender::Animation::BlendMask jumpmask = MWRender::Animation::BlendMask_All; if(mJumpState != JumpState_None) { - jump = "jump"; + jumpAnimName = "jump"; if(weap != sWeaponTypeListEnd) { - jump += weap->shortgroup; - if(!mAnimation->hasAnimation(jump)) + jumpAnimName += weap->shortgroup; + if(!mAnimation->hasAnimation(jumpAnimName)) { jumpmask = MWRender::Animation::BlendMask_LowerBody; - jump = "jump"; + jumpAnimName = "jump"; } } } if(mJumpState == JumpState_InAir) { - int mode = ((jump == mCurrentJump) ? 2 : 1); - mAnimation->disable(mCurrentJump); - mCurrentJump = jump; + mCurrentJump = jumpAnimName; if (mAnimation->hasAnimation("jump")) mAnimation->play(mCurrentJump, Priority_Jump, jumpmask, false, - 1.0f, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); + 1.0f, (startAtLoop?"loop start":"start"), "stop", 0.0f, ~0ul); } else { mAnimation->disable(mCurrentJump); mCurrentJump.clear(); if (mAnimation->hasAnimation("jump")) - mAnimation->play(jump, Priority_Jump, jumpmask, true, + mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, true, 1.0f, "loop stop", "stop", 0.0f, 0); } } @@ -717,7 +718,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if(mDeathState == CharState_None) - refreshCurrentAnims(mIdleState, mMovementState, true); + refreshCurrentAnims(mIdleState, mMovementState, mJumpState, true); mAnimation->runAnimation(0.f); } @@ -1556,6 +1557,8 @@ void CharacterController::update(float duration) CharacterState movestate = CharState_None; CharacterState idlestate = CharState_SpecialIdle; + JumpingState jumpstate = JumpState_None; + bool forcestateupdate = false; mHasMovedInXY = std::abs(vec.x())+std::abs(vec.y()) > 0.0f; @@ -1638,7 +1641,7 @@ void CharacterController::update(float duration) } forcestateupdate = (mJumpState != JumpState_InAir); - mJumpState = JumpState_InAir; + jumpstate = JumpState_InAir; static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat(); static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat(); @@ -1683,7 +1686,7 @@ void CharacterController::update(float duration) else if(mJumpState == JumpState_InAir) { forcestateupdate = true; - mJumpState = JumpState_Landing; + jumpstate = JumpState_Landing; vec.z() = 0.0f; float height = cls.getCreatureStats(mPtr).land(); @@ -1714,7 +1717,7 @@ void CharacterController::update(float duration) } else { - mJumpState = JumpState_None; + jumpstate = JumpState_None; vec.z() = 0.0f; inJump = false; @@ -1792,7 +1795,7 @@ void CharacterController::update(float duration) forcestateupdate = updateCreatureState() || forcestateupdate; if (!mSkipAnim) - refreshCurrentAnims(idlestate, movestate, forcestateupdate); + refreshCurrentAnims(idlestate, movestate, jumpstate, forcestateupdate); if (inJump) mMovementAnimationControlled = false; @@ -1928,7 +1931,7 @@ void CharacterController::forceStateUpdate() return; clearAnimQueue(); - refreshCurrentAnims(mIdleState, mMovementState, true); + refreshCurrentAnims(mIdleState, mMovementState, mJumpState, true); if(mDeathState != CharState_None) { playRandomDeath(); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 6b530ae2a..f37afd996 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -186,7 +186,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener void determineAttackType(); - void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false); + void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false); void clearAnimQueue(); From 9a115fedbc724ce29e3cae8da6a19d24c28a0fa3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 16 Jul 2015 20:11:33 +0200 Subject: [PATCH 076/419] Add ability to copy&paste the version label in the main menu --- files/mygui/openmw_mainmenu.layout | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/files/mygui/openmw_mainmenu.layout b/files/mygui/openmw_mainmenu.layout index f4c7142ce..c4d88ff85 100644 --- a/files/mygui/openmw_mainmenu.layout +++ b/files/mygui/openmw_mainmenu.layout @@ -3,10 +3,12 @@ - + + + From 660e7f5d893ffde813df4f178b891797caa35102 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 17 Jul 2015 03:28:17 +0200 Subject: [PATCH 077/419] Don't update animation states in skipAnim mode (Fixes #2782) --- apps/openmw/mwmechanics/character.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8fa02c3cd..50faaa91b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1788,14 +1788,17 @@ void CharacterController::update(float duration) } } - // bipedal means hand-to-hand could be used (which is handled in updateWeaponState). an existing InventoryStore means an actual weapon could be used. - if(cls.isBipedal(mPtr) || cls.hasInventoryStore(mPtr)) - forcestateupdate = updateWeaponState() || forcestateupdate; - else - forcestateupdate = updateCreatureState() || forcestateupdate; - if (!mSkipAnim) + { + // bipedal means hand-to-hand could be used (which is handled in updateWeaponState). an existing InventoryStore means an actual weapon could be used. + if(cls.isBipedal(mPtr) || cls.hasInventoryStore(mPtr)) + forcestateupdate = updateWeaponState() || forcestateupdate; + else + forcestateupdate = updateCreatureState() || forcestateupdate; + refreshCurrentAnims(idlestate, movestate, jumpstate, forcestateupdate); + } + if (inJump) mMovementAnimationControlled = false; From 91d71d0fcd690559a47dec6a889ca189ee09a199 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 17 Jul 2015 03:39:09 +0200 Subject: [PATCH 078/419] Disable MyGUI's scrollbar autorepeat (Fixes #2779) We are currently using a custom implementation so as to support MyGUI version 3.2.1. When compiled with 3.2.2 or later, we need to disable MyGUI's autorepeat so that it doesn't interfere with ours. --- apps/openmw/mwgui/widgets.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 158d5fd5e..481ffaade 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -539,6 +539,9 @@ namespace MWGui , mRepeatStepTime(0.1f) , mIsIncreasing(true) { +#if MYGUI_VERSION >= MYGUI_DEFINE_VERSION(3,2,2) + ScrollBar::setRepeatEnabled(false); +#endif } MWScrollBar::~MWScrollBar() From 83ef1f7eea99d02be09408398437682f72e0cacf Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 17 Jul 2015 00:56:15 -0500 Subject: [PATCH 079/419] Add support for linking OpenSceneGraph statically Added some basic support for linking to OpenSceneGraph and its plugins statically. Also added a library necessary to statically link MyGUI (previously Ogre pulled it in). --- CMakeLists.txt | 62 +++++++++++++++++++++++++- cmake/FindMyGUI.cmake | 1 + components/resource/texturemanager.cpp | 13 ++++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a133a8d6a..a151c8503 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,8 @@ configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_ option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE) option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE) option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE) +option(OSG_STATIC "Link static build of OpenSceneGraph into the binaries" FALSE) +option(QT_STATIC "Link static build of QT into the binaries" FALSE) option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE) @@ -199,9 +201,67 @@ IF(BOOST_STATIC) set(Boost_USE_STATIC_LIBS ON) endif() -find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt osgUtil osgFX) +find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgQt osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) +if(OSG_STATIC) + macro(use_static_osg_plugin_library PLUGIN_NAME) + set(PLUGIN_NAME_DBG ${PLUGIN_NAME}d ${PLUGIN_NAME}D ${PLUGIN_NAME}_d ${PLUGIN_NAME}_D ${PLUGIN_NAME}_debug ${PLUGIN_NAME}) + + # For now, users wishing to do a static build will need to pass the path to where the plugins reside + # More clever logic would need to deduce the path, probably installed under /lib/osgPlugins- + find_library(${PLUGIN_NAME}_LIBRARY_REL NAMES ${PLUGIN_NAME} HINTS ${OSG_PLUGIN_LIB_SEARCH_PATH}) + find_library(${PLUGIN_NAME}_LIBRARY_DBG NAMES ${PLUGIN_NAME_DBG} HINTS ${OSG_PLUGIN_LIB_SEARCH_PATH}) + make_library_set(${PLUGIN_NAME}_LIBRARY) + + if("${${PLUGIN_NAME}_LIBRARY}" STREQUAL "") + message(FATAL_ERROR "Unable to find static OpenSceneGraph plugin: ${PLUGIN_NAME}") + endif() + + set(OPENSCENEGRAPH_LIBRARIES ${OPENSCENEGRAPH_LIBRARIES} ${${PLUGIN_NAME}_LIBRARY}) + endmacro() + + macro(use_static_osg_plugin_dep DEPENDENCY) + find_package(${DEPENDENCY} REQUIRED) + + set(OPENSCENEGRAPH_LIBRARIES ${OPENSCENEGRAPH_LIBRARIES} ${${DEPENDENCY}_LIBRARIES}) + endmacro() + + add_definitions(-DOSG_LIBRARY_STATIC) + + set(PLUGIN_LIST + osgdb_png # depends on libpng, zlib + osgdb_tga + osgdb_dds + osgdb_jpeg # depends on libjpeg + ) + + foreach(PLUGIN ${PLUGIN_LIST}) + use_static_osg_plugin_library(${PLUGIN}) + endforeach() + + # OSG static plugins need to linked against their respective dependencies + set(PLUGIN_DEPS_LIST + PNG # needed by osgdb_png + ZLIB # needed by osgdb_png + JPEG # needed by osgdb_jpeg + ) + + foreach(DEPENDENCY ${PLUGIN_DEPS_LIST}) + use_static_osg_plugin_dep(${DEPENDENCY}) + endforeach() +endif() + +if(QT_STATIC) + if(WIN32) + if(DESIRED_QT_VERSION MATCHES 4) + # QtCore needs WSAAsyncSelect from Ws2_32.lib + set(QT_QTCORE_LIBRARY ${QT_QTCORE_LIBRARY} Ws2_32.lib) + message("QT_QTCORE_LIBRARY: ${QT_QTCORE_LIBRARY}") + endif() + endif() +endif() + find_package(MyGUI REQUIRED) if (${MYGUI_VERSION} VERSION_LESS "3.2.1") message(FATAL_ERROR "OpenMW requires MyGUI 3.2.1 or later, please install the latest version from http://mygui.info") diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index 320765b53..f85b6ba52 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -54,6 +54,7 @@ IF (WIN32) #Windows if ( MYGUI_STATIC ) set(LIB_SUFFIX "Static") + find_package(freetype) endif ( MYGUI_STATIC ) find_library ( MYGUI_LIBRARIES_REL NAMES MyGUIEngine${LIB_SUFFIX}.lib HINTS ${MYGUI_LIB_DIR} PATH_SUFFIXES "" release relwithdebinfo minsizerel ) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 62cbd6bb3..eca711b3c 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -1,11 +1,24 @@ #include "texturemanager.hpp" #include +#include #include #include +#ifdef OSG_LIBRARY_STATIC +// This list of plugins should match with the list in the top-level CMakelists.txt. +USE_OSGPLUGIN(png) +USE_OSGPLUGIN(tga) +USE_OSGPLUGIN(dds) +USE_OSGPLUGIN(jpeg) + +// Sets the default windowing system interface according to the OS. +// Necessary for OpenSceneGraph to do some things, like decompression. +USE_GRAPHICSWINDOW() +#endif + namespace { From eab1ec9160674db02c5b701479e86d5acb8c3f43 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 11:52:59 +0200 Subject: [PATCH 080/419] consider script warning settings for script subview --- apps/opencs/view/world/scripterrortable.cpp | 19 +++++++++++++++++-- apps/opencs/view/world/scripterrortable.hpp | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index dfa036824..29f1d6820 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -10,7 +10,7 @@ #include #include "../../model/doc/document.hpp" - +#include "../../model/settings/usersettings.hpp" void CSVWorld::ScriptErrorTable::report (const std::string& message, const Compiler::TokenLoc& loc, Type type) { @@ -44,6 +44,18 @@ void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, } setItem (row, 2, new QTableWidgetItem (QString::fromUtf8 (message.c_str()))); + + +} + +void CSVWorld::ScriptErrorTable::setWarningsMode (const QString& value) +{ + if (value=="Ignore") + Compiler::ErrorHandler::setWarningsMode (0); + else if (value=="Normal") + Compiler::ErrorHandler::setWarningsMode (1); + else if (value=="Strict") + Compiler::ErrorHandler::setWarningsMode (2); } CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent) @@ -58,11 +70,14 @@ CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, Compiler::registerExtensions (mExtensions); mContext.setExtensions (&mExtensions); + + setWarningsMode (CSMSettings::UserSettings::instance().settingValue ("script-editor/warnings")); } void CSVWorld::ScriptErrorTable::updateUserSetting (const QString& name, const QStringList& value) { - + if (name=="script-editor/warnings" && !value.isEmpty()) + setWarningsMode (value.at (0)); } void CSVWorld::ScriptErrorTable::update (const std::string& source) diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp index 791125c12..99557fb0d 100644 --- a/apps/opencs/view/world/scripterrortable.hpp +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -32,6 +32,8 @@ namespace CSVWorld void addMessage (const std::string& message, CSMDoc::Message::Severity severity, int line = -1); + void setWarningsMode (const QString& value); + public: ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent = 0); From 56ed0926bd9360365214450f61e3166f952f8ef3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 12:45:08 +0200 Subject: [PATCH 081/419] improved error table layout --- apps/opencs/view/world/scripterrortable.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 29f1d6820..dc28b8907 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -66,7 +66,10 @@ CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, QStringList headers; headers << "Severity" << "Line" << "Description"; setHorizontalHeaderLabels (headers); + horizontalHeader()->setResizeMode (0, QHeaderView::ResizeToContents); + horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents); horizontalHeader()->setStretchLastSection (true); + verticalHeader()->hide(); Compiler::registerExtensions (mExtensions); mContext.setExtensions (&mExtensions); From 100af80388c197e191e71b6d6e533395b006d427 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 13:06:51 +0200 Subject: [PATCH 082/419] made error table read only --- apps/opencs/view/world/scripterrortable.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index dc28b8907..460bedefc 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -34,16 +34,22 @@ void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, setRowCount (row+1); - setItem (row, 0, new QTableWidgetItem (QString::fromUtf8 (CSMDoc::Message::toString (severity).c_str()))); + QTableWidgetItem *severityItem = new QTableWidgetItem ( + QString::fromUtf8 (CSMDoc::Message::toString (severity).c_str())); + severityItem->setFlags (severityItem->flags() ^ Qt::ItemIsEditable); + setItem (row, 0, severityItem); if (line!=-1) { - QTableWidgetItem *item = new QTableWidgetItem; - item->setData (Qt::DisplayRole, line+1); - setItem (row, 1, item); + QTableWidgetItem *lineItem = new QTableWidgetItem; + lineItem->setData (Qt::DisplayRole, line+1); + lineItem->setFlags (lineItem->flags() ^ Qt::ItemIsEditable); + setItem (row, 1, lineItem); } - setItem (row, 2, new QTableWidgetItem (QString::fromUtf8 (message.c_str()))); + QTableWidgetItem *messageItem = new QTableWidgetItem (QString::fromUtf8 (message.c_str())); + messageItem->setFlags (messageItem->flags() ^ Qt::ItemIsEditable); + setItem (row, 2, messageItem); } From 0abd29a3b455e9fa0f55be0565ee8a1723473816 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 13:42:25 +0200 Subject: [PATCH 083/419] jump to line in source text when clicking on an error in error table --- apps/opencs/view/world/scripterrortable.cpp | 10 ++++++++++ apps/opencs/view/world/scripterrortable.hpp | 8 ++++++++ apps/opencs/view/world/scriptsubview.cpp | 16 ++++++++++++++++ apps/opencs/view/world/scriptsubview.hpp | 2 ++ 4 files changed, 36 insertions(+) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 460bedefc..242d6c8ac 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -77,10 +77,14 @@ CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, horizontalHeader()->setStretchLastSection (true); verticalHeader()->hide(); + setSelectionMode (QAbstractItemView::NoSelection); + Compiler::registerExtensions (mExtensions); mContext.setExtensions (&mExtensions); setWarningsMode (CSMSettings::UserSettings::instance().settingValue ("script-editor/warnings")); + + connect (this, SIGNAL (cellClicked (int, int)), this, SLOT (cellClicked (int, int))); } void CSVWorld::ScriptErrorTable::updateUserSetting (const QString& name, const QStringList& value) @@ -112,3 +116,9 @@ void CSVWorld::ScriptErrorTable::update (const std::string& source) addMessage (error.what(), CSMDoc::Message::Severity_SeriousError); } } + +void CSVWorld::ScriptErrorTable::cellClicked (int row, int column) +{ + int line = item (row, 1)->data (Qt::DisplayRole).toInt(); + emit highlightError (line-1); +} diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp index 99557fb0d..5c6e75164 100644 --- a/apps/opencs/view/world/scripterrortable.hpp +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -41,6 +41,14 @@ namespace CSVWorld void updateUserSetting (const QString& name, const QStringList& value); void update (const std::string& source); + + private slots: + + void cellClicked (int row, int column); + + signals: + + void highlightError (int line); }; } diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index d48e647d9..36e21d53b 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -98,6 +98,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect(mEditor, SIGNAL(cursorPositionChanged()), this, SLOT(updateStatusBar())); mErrors->update (source.toUtf8().constData()); + + connect (mErrors, SIGNAL (highlightError (int)), this, SLOT (highlightError (int))); } void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) @@ -244,3 +246,17 @@ void CSVWorld::ScriptSubView::switchToId (const std::string& id) { switchToRow (mModel->getModelIndex (id, 0).row()); } + +void CSVWorld::ScriptSubView::highlightError (int line) +{ + QTextCursor cursor = mEditor->textCursor(); + + cursor.movePosition (QTextCursor::Start); + if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line)) + { +// cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column); + } + + mEditor->setFocus(); + mEditor->setTextCursor (cursor); +} diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 0b6f4d923..6be943bb8 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -75,6 +75,8 @@ namespace CSVWorld void switchToRow (int row); void switchToId (const std::string& id); + + void highlightError (int line); }; } From f665919046bf1b923424ad0af7944f60f8a5d47b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 13:53:22 +0200 Subject: [PATCH 084/419] consider column when jumping to error in source text --- apps/opencs/view/world/scripterrortable.cpp | 20 +++++++++++++------- apps/opencs/view/world/scripterrortable.hpp | 4 ++-- apps/opencs/view/world/scriptsubview.cpp | 9 ++++----- apps/opencs/view/world/scriptsubview.hpp | 2 +- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 242d6c8ac..ec84a8328 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -18,7 +18,8 @@ void CSVWorld::ScriptErrorTable::report (const std::string& message, const Compi stream << message << " (" << loc.mLiteral << ")"; addMessage (stream.str(), type==Compiler::ErrorHandler::WarningMessage ? - CSMDoc::Message::Severity_Warning : CSMDoc::Message::Severity_Error, loc.mLine); + CSMDoc::Message::Severity_Warning : CSMDoc::Message::Severity_Error, + loc.mLine, loc.mColumn-loc.mLiteral.length()); } void CSVWorld::ScriptErrorTable::report (const std::string& message, Type type) @@ -28,7 +29,7 @@ void CSVWorld::ScriptErrorTable::report (const std::string& message, Type type) } void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, - CSMDoc::Message::Severity severity, int line) + CSMDoc::Message::Severity severity, int line, int column) { int row = rowCount(); @@ -45,13 +46,16 @@ void CSVWorld::ScriptErrorTable::addMessage (const std::string& message, lineItem->setData (Qt::DisplayRole, line+1); lineItem->setFlags (lineItem->flags() ^ Qt::ItemIsEditable); setItem (row, 1, lineItem); + + QTableWidgetItem *columnItem = new QTableWidgetItem; + columnItem->setData (Qt::DisplayRole, column); + columnItem->setFlags (columnItem->flags() ^ Qt::ItemIsEditable); + setItem (row, 3, columnItem); } QTableWidgetItem *messageItem = new QTableWidgetItem (QString::fromUtf8 (message.c_str())); messageItem->setFlags (messageItem->flags() ^ Qt::ItemIsEditable); setItem (row, 2, messageItem); - - } void CSVWorld::ScriptErrorTable::setWarningsMode (const QString& value) @@ -67,7 +71,7 @@ void CSVWorld::ScriptErrorTable::setWarningsMode (const QString& value) CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, QWidget *parent) : QTableWidget (parent), mContext (document.getData()) { - setColumnCount (3); + setColumnCount (4); QStringList headers; headers << "Severity" << "Line" << "Description"; @@ -76,6 +80,7 @@ CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents); horizontalHeader()->setStretchLastSection (true); verticalHeader()->hide(); + setColumnHidden (3, true); setSelectionMode (QAbstractItemView::NoSelection); @@ -119,6 +124,7 @@ void CSVWorld::ScriptErrorTable::update (const std::string& source) void CSVWorld::ScriptErrorTable::cellClicked (int row, int column) { - int line = item (row, 1)->data (Qt::DisplayRole).toInt(); - emit highlightError (line-1); + int scriptLine = item (row, 1)->data (Qt::DisplayRole).toInt(); + int scriptColumn = item (row, 3)->data (Qt::DisplayRole).toInt(); + emit highlightError (scriptLine-1, scriptColumn); } diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp index 5c6e75164..f16a96a74 100644 --- a/apps/opencs/view/world/scripterrortable.hpp +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -30,7 +30,7 @@ namespace CSVWorld ///< Report a file related error void addMessage (const std::string& message, CSMDoc::Message::Severity severity, - int line = -1); + int line = -1, int column = -1); void setWarningsMode (const QString& value); @@ -48,7 +48,7 @@ namespace CSVWorld signals: - void highlightError (int line); + void highlightError (int line, int column); }; } diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 36e21d53b..7b5b1131e 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -99,7 +99,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: mErrors->update (source.toUtf8().constData()); - connect (mErrors, SIGNAL (highlightError (int)), this, SLOT (highlightError (int))); + connect (mErrors, SIGNAL (highlightError (int, int)), + this, SLOT (highlightError (int, int))); } void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) @@ -247,15 +248,13 @@ void CSVWorld::ScriptSubView::switchToId (const std::string& id) switchToRow (mModel->getModelIndex (id, 0).row()); } -void CSVWorld::ScriptSubView::highlightError (int line) +void CSVWorld::ScriptSubView::highlightError (int line, int column) { QTextCursor cursor = mEditor->textCursor(); cursor.movePosition (QTextCursor::Start); if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line)) - { -// cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column); - } + cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column); mEditor->setFocus(); mEditor->setTextCursor (cursor); diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 6be943bb8..a9c8dccb3 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -76,7 +76,7 @@ namespace CSVWorld void switchToId (const std::string& id); - void highlightError (int line); + void highlightError (int line, int column); }; } From 5febb96012ea68dda6cb367a18e1fe59a41cb39d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 17 Jul 2015 13:59:50 +0200 Subject: [PATCH 085/419] do not try to jump to source location for errors that do not have a source location --- apps/opencs/view/world/scripterrortable.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index ec84a8328..20b197c54 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -124,7 +124,10 @@ void CSVWorld::ScriptErrorTable::update (const std::string& source) void CSVWorld::ScriptErrorTable::cellClicked (int row, int column) { - int scriptLine = item (row, 1)->data (Qt::DisplayRole).toInt(); - int scriptColumn = item (row, 3)->data (Qt::DisplayRole).toInt(); - emit highlightError (scriptLine-1, scriptColumn); + if (item (row, 1)) + { + int scriptLine = item (row, 1)->data (Qt::DisplayRole).toInt(); + int scriptColumn = item (row, 3)->data (Qt::DisplayRole).toInt(); + emit highlightError (scriptLine-1, scriptColumn); + } } From 72728b9c01058ee2d2a6625fd0e542eeb45b14db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 16:32:35 +0200 Subject: [PATCH 086/419] disable cusor when item/container is owned --- apps/openmw/mwgui/tooltips.cpp | 22 +++++++++++++++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 6 +++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 526cbaabe..18f65e3ba 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -17,6 +17,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/mechanicsmanagerimp.hpp" #include "mapwindow.hpp" #include "inventorywindow.hpp" @@ -342,6 +343,27 @@ namespace MWGui if (!image) info.icon = ""; tooltipSize = createToolTip(info); + + // start owned check + MWWorld::CellRef& cellref = mFocusObject.getCellRef(); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr victim; + + MWMechanics::MechanicsManager* mm = new MWMechanics::MechanicsManager; + bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned + + MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); + if(allowed) + { + // if 'item' is not owned + wm->showCrosshair(true); + } + else + { + // if 'item' is owned + wm->showCrosshair(false); + } + } return tooltipSize; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 5cc2ce254..392d7fbbe 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -175,13 +175,15 @@ namespace MWMechanics /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); + + /// @return is \a ptr allowed to take/use \a cellref or is it a crime? + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim); private: void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0); - /// @return is \a ptr allowed to take/use \a cellref or is it a crime? - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim); + }; } From df99d5a59d98410391cd2bfe70290db79748b7d9 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 17 Jul 2015 09:56:21 -0500 Subject: [PATCH 087/419] Move setup code for OSG when statically linked --- components/resource/texturemanager.cpp | 13 ------------- components/sdlutil/sdlcursormanager.cpp | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index eca711b3c..62cbd6bb3 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -1,24 +1,11 @@ #include "texturemanager.hpp" #include -#include #include #include -#ifdef OSG_LIBRARY_STATIC -// This list of plugins should match with the list in the top-level CMakelists.txt. -USE_OSGPLUGIN(png) -USE_OSGPLUGIN(tga) -USE_OSGPLUGIN(dds) -USE_OSGPLUGIN(jpeg) - -// Sets the default windowing system interface according to the OS. -// Necessary for OpenSceneGraph to do some things, like decompression. -USE_GRAPHICSWINDOW() -#endif - namespace { diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index d8d4b0b50..508d72589 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -10,9 +10,23 @@ #include #include #include +#include +#include #include "imagetosurface.hpp" +#ifdef OSG_LIBRARY_STATIC +// This list of plugins should match with the list in the top-level CMakelists.txt. +USE_OSGPLUGIN(png) +USE_OSGPLUGIN(tga) +USE_OSGPLUGIN(dds) +USE_OSGPLUGIN(jpeg) + +// Sets the default windowing system interface according to the OS. +// Necessary for OpenSceneGraph to do some things, like decompression. +USE_GRAPHICSWINDOW() +#endif + namespace { From 66edae9b932988fbe0fff29260c3d5bf82d88bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 17:29:00 +0200 Subject: [PATCH 088/419] change collor of crosshair --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/hud.cpp | 16 +++++++++++- apps/openmw/mwgui/hud.hpp | 1 + apps/openmw/mwgui/tooltips.cpp | 36 ++++++++++++++------------ apps/openmw/mwgui/tooltips.hpp | 3 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 6 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 1 + 7 files changed, 47 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index f8bf157c2..86b42c9f9 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -219,6 +219,7 @@ namespace MWBase virtual void unsetSelectedWeapon() = 0; virtual void showCrosshair(bool show) = 0; + virtual void setCrosshairOwned(bool owned) = 0; virtual bool getSubtitlesEnabled() = 0; virtual bool toggleGui() = 0; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 76a7248ee..0f107f4e3 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -518,7 +518,21 @@ namespace MWGui { mCrosshair->setVisible (visible); } - + + void HUD::setCrosshairOwned(bool owned) + { + MyGUI::Colour red = MyGUI::Colour(1.0, 0, 0); + MyGUI::Colour white = MyGUI::Colour(1.0, 1.0, 1.0); + if(owned) + { + mCrosshair->setColour(red); + } + else + { + mCrosshair->setColour(white); + } + } + void HUD::setHmsVisible(bool visible) { mHealth->setVisible(visible); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 72fc06f6a..629613c98 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -47,6 +47,7 @@ namespace MWGui void unsetSelectedWeapon(); void setCrosshairVisible(bool visible); + void setCrosshairOwned(bool owned); void onFrame(float dt); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 18f65e3ba..34762de5a 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -299,7 +299,10 @@ namespace MWGui tooltipSize.height); mDynamicToolTipBox->setVisible(true); + } + + checkOwned(); } } @@ -344,29 +347,30 @@ namespace MWGui info.icon = ""; tooltipSize = createToolTip(info); - // start owned check + } + + return tooltipSize; + } + + void ToolTips::checkOwned() + { + MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); + + if(!mFocusObject.isEmpty()) + { MWWorld::CellRef& cellref = mFocusObject.getCellRef(); MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr victim; MWMechanics::MechanicsManager* mm = new MWMechanics::MechanicsManager; bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned - - MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); - if(allowed) - { - // if 'item' is not owned - wm->showCrosshair(true); - } - else - { - // if 'item' is owned - wm->showCrosshair(false); - } - - } - return tooltipSize; + wm->setCrosshairOwned(!allowed); + } + else + { + wm->setCrosshairOwned(false); + } } MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index d14993639..a54888780 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -95,6 +95,9 @@ namespace MWGui MyGUI::IntSize getToolTipViaPtr (bool image=true); ///< @return requested tooltip size + + void checkOwned(); + /// Checks if object is owned and sets correct crosshair mode MyGUI::IntSize createToolTip(const ToolTipInfo& info); ///< @return requested tooltip size diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a2a826161..2588f2d86 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1423,6 +1423,12 @@ namespace MWGui if (mHud) mHud->setCrosshairVisible (show && mCrosshairEnabled); } + + void WindowManager::setCrosshairOwned (bool owned) + { + if (mHud) + mHud->setCrosshairOwned (owned); + } void WindowManager::activateQuickKey (int index) { diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index e6c8d0a81..94538840b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -233,6 +233,7 @@ namespace MWGui virtual void unsetSelectedWeapon(); virtual void showCrosshair(bool show); + virtual void setCrosshairOwned(bool owned); virtual bool getSubtitlesEnabled(); /// Turn visibility of *all* GUI elements on or off (HUD and all windows, except the console) From 15107ca5cf4085792a57e10dbcdb7974e8d675b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 17:48:38 +0200 Subject: [PATCH 089/419] crosshair owned - settings option --- apps/openmw/mwgui/tooltips.cpp | 29 ++++++++++++++++------------- files/settings-default.cfg | 3 +++ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 34762de5a..51bdd97f9 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -354,22 +354,25 @@ namespace MWGui void ToolTips::checkOwned() { - MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); - - if(!mFocusObject.isEmpty()) + if(Settings::Manager::getBool("show owned", "Game")) { - MWWorld::CellRef& cellref = mFocusObject.getCellRef(); - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - MWWorld::Ptr victim; + MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); - MWMechanics::MechanicsManager* mm = new MWMechanics::MechanicsManager; - bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned + if(!mFocusObject.isEmpty()) + { + MWWorld::CellRef& cellref = mFocusObject.getCellRef(); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr victim; + + MWMechanics::MechanicsManager* mm = new MWMechanics::MechanicsManager; + bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned - wm->setCrosshairOwned(!allowed); - } - else - { - wm->setCrosshairOwned(false); + wm->setCrosshairOwned(!allowed); + } + else + { + wm->setCrosshairOwned(false); + } } } diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 0581d7356..4ec0c2480 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -162,6 +162,9 @@ best attack = false difficulty = 0 +# change crosshair color when pointing on owned object +show owned = false + [Saves] character = # Save when resting From c019f8e23dcef0a38ac9d934eb639eab2cf5cf21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 18:49:47 +0200 Subject: [PATCH 090/419] use correct mechanics manager --- apps/openmw/mwbase/mechanicsmanager.hpp | 4 ++++ apps/openmw/mwgui/tooltips.cpp | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 1d3619d3d..7889988e9 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -6,6 +6,8 @@ #include #include +#include "../mwworld/ptr.hpp" + namespace osg { class Vec3f; @@ -211,6 +213,8 @@ namespace MWBase /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; + + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim) = 0; }; } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 51bdd97f9..40df4a4b4 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -17,7 +17,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/spellcasting.hpp" -#include "../mwmechanics/mechanicsmanagerimp.hpp" #include "mapwindow.hpp" #include "inventorywindow.hpp" @@ -364,7 +363,7 @@ namespace MWGui MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr victim; - MWMechanics::MechanicsManager* mm = new MWMechanics::MechanicsManager; + MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned wm->setCrosshairOwned(!allowed); From e68b388d161030ca1122bbebd4772017701b8dfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 19:13:45 +0200 Subject: [PATCH 091/419] removed setCrosshairOwned from windowmanager --- apps/openmw/mwbase/windowmanager.hpp | 1 - apps/openmw/mwgui/tooltips.cpp | 32 +++++++++++--------------- apps/openmw/mwgui/tooltips.hpp | 6 ++--- apps/openmw/mwgui/windowmanagerimp.cpp | 12 +++++----- apps/openmw/mwgui/windowmanagerimp.hpp | 1 - 5 files changed, 22 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 86b42c9f9..f8bf157c2 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -219,7 +219,6 @@ namespace MWBase virtual void unsetSelectedWeapon() = 0; virtual void showCrosshair(bool show) = 0; - virtual void setCrosshairOwned(bool owned) = 0; virtual bool getSubtitlesEnabled() = 0; virtual bool toggleGui() = 0; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 40df4a4b4..28ff47260 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -300,8 +300,6 @@ namespace MWGui mDynamicToolTipBox->setVisible(true); } - - checkOwned(); } } @@ -351,27 +349,23 @@ namespace MWGui return tooltipSize; } - void ToolTips::checkOwned() + bool ToolTips::checkOwned() { - if(Settings::Manager::getBool("show owned", "Game")) + // true=owned, false=notOwned + if(!mFocusObject.isEmpty()) { - MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); + MWWorld::CellRef& cellref = mFocusObject.getCellRef(); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr victim; - if(!mFocusObject.isEmpty()) - { - MWWorld::CellRef& cellref = mFocusObject.getCellRef(); - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - MWWorld::Ptr victim; - - MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); - bool allowed = mm->isAllowedToUse(ptr, cellref, victim); // 0 - owned, 1 - not owned + MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); + bool allowed = mm->isAllowedToUse(ptr, cellref, victim); - wm->setCrosshairOwned(!allowed); - } - else - { - wm->setCrosshairOwned(false); - } + return !allowed; + } + else + { + return false; } } diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index a54888780..26a4fe2c7 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -87,6 +87,9 @@ namespace MWGui static void createRaceToolTip(MyGUI::Widget* widget, const ESM::Race* playerRace); static void createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playerClass); static void createMagicEffectToolTip(MyGUI::Widget* widget, short id); + + bool checkOwned(); + /// Checks if object is owned and sets correct crosshair mode private: MyGUI::Widget* mDynamicToolTipBox; @@ -95,9 +98,6 @@ namespace MWGui MyGUI::IntSize getToolTipViaPtr (bool image=true); ///< @return requested tooltip size - - void checkOwned(); - /// Checks if object is owned and sets correct crosshair mode MyGUI::IntSize createToolTip(const ToolTipInfo& info); ///< @return requested tooltip size diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2588f2d86..2f8cfbf62 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1038,6 +1038,12 @@ namespace MWGui void WindowManager::setFocusObject(const MWWorld::Ptr& focus) { mToolTips->setFocusObject(focus); + + if(Settings::Manager::getBool("show owned", "Game") && mHud) + { + bool owned = mToolTips->checkOwned(); + mHud->setCrosshairOwned(owned); + } } void WindowManager::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) @@ -1423,12 +1429,6 @@ namespace MWGui if (mHud) mHud->setCrosshairVisible (show && mCrosshairEnabled); } - - void WindowManager::setCrosshairOwned (bool owned) - { - if (mHud) - mHud->setCrosshairOwned (owned); - } void WindowManager::activateQuickKey (int index) { diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 94538840b..e6c8d0a81 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -233,7 +233,6 @@ namespace MWGui virtual void unsetSelectedWeapon(); virtual void showCrosshair(bool show); - virtual void setCrosshairOwned(bool owned); virtual bool getSubtitlesEnabled(); /// Turn visibility of *all* GUI elements on or off (HUD and all windows, except the console) From 4a6d80612729e58d0a8c6441e39035423194ac7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Fri, 17 Jul 2015 20:30:00 +0200 Subject: [PATCH 092/419] fixed comment, save settings to member variable, removed usless include, changed variable to const --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 +-- apps/openmw/mwgui/tooltips.cpp | 5 +---- apps/openmw/mwgui/tooltips.hpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 5 ++++- apps/openmw/mwgui/windowmanagerimp.hpp | 2 ++ 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 7889988e9..b66e60e1d 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -6,8 +6,6 @@ #include #include -#include "../mwworld/ptr.hpp" - namespace osg { class Vec3f; @@ -25,6 +23,7 @@ namespace MWWorld { class Ptr; class CellStore; + class CellRef; } namespace Loading diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 28ff47260..22d5d14f7 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -298,7 +298,6 @@ namespace MWGui tooltipSize.height); mDynamicToolTipBox->setVisible(true); - } } } @@ -343,7 +342,6 @@ namespace MWGui if (!image) info.icon = ""; tooltipSize = createToolTip(info); - } return tooltipSize; @@ -351,10 +349,9 @@ namespace MWGui bool ToolTips::checkOwned() { - // true=owned, false=notOwned if(!mFocusObject.isEmpty()) { - MWWorld::CellRef& cellref = mFocusObject.getCellRef(); + const MWWorld::CellRef& cellref = mFocusObject.getCellRef(); MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr victim; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 26a4fe2c7..bd4a81c32 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -89,8 +89,8 @@ namespace MWGui static void createMagicEffectToolTip(MyGUI::Widget* widget, short id); bool checkOwned(); - /// Checks if object is owned and sets correct crosshair mode - + /// Returns True if taking mFocusObject would be crime + private: MyGUI::Widget* mDynamicToolTipBox; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2f8cfbf62..cb5d4442f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -187,6 +187,7 @@ namespace MWGui , mRestAllowed(true) , mFPS(0.0f) , mFallbackMap(fallbackMap) + , mShowOwned(false) { float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getTextureManager(), uiScale); @@ -261,6 +262,8 @@ namespace MWGui MyGUI::ClipboardManager::getInstance().eventClipboardChanged += MyGUI::newDelegate(this, &WindowManager::onClipboardChanged); MyGUI::ClipboardManager::getInstance().eventClipboardRequested += MyGUI::newDelegate(this, &WindowManager::onClipboardRequested); + + mShowOwned = Settings::Manager::getBool("show owned", "Game"); } void WindowManager::initUI() @@ -1039,7 +1042,7 @@ namespace MWGui { mToolTips->setFocusObject(focus); - if(Settings::Manager::getBool("show owned", "Game") && mHud) + if(mShowOwned && mHud) { bool owned = mToolTips->checkOwned(); mHud->setCrosshairOwned(owned); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index e6c8d0a81..5c4b2d447 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -486,6 +486,8 @@ namespace MWGui float mFPS; std::map mFallbackMap; + + bool mShowOwned; /** * Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property. From 41bed4c7d9c2a1dc4a7f3e4444433a0d50df4a16 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 17 Jul 2015 20:49:10 +0200 Subject: [PATCH 093/419] Use multimap to speed up custom map marker code --- apps/openmw/mwgui/mapwindow.cpp | 118 ++++++++++++++----------- apps/openmw/mwgui/mapwindow.hpp | 12 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +- components/esm/cellid.cpp | 23 +++++ components/esm/cellid.hpp | 1 + 5 files changed, 100 insertions(+), 58 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 442fbeb08..7778569d2 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -92,31 +92,41 @@ namespace MWGui void CustomMarkerCollection::addMarker(const ESM::CustomMarker &marker, bool triggerEvent) { - mMarkers.push_back(marker); + mMarkers.insert(std::make_pair(marker.mCell, marker)); if (triggerEvent) eventMarkersChanged(); } void CustomMarkerCollection::deleteMarker(const ESM::CustomMarker &marker) { - std::vector::iterator it = std::find(mMarkers.begin(), mMarkers.end(), marker); - if (it != mMarkers.end()) - mMarkers.erase(it); - else - throw std::runtime_error("can't find marker to delete"); + std::pair range = mMarkers.equal_range(marker.mCell); - eventMarkersChanged(); + for (ContainerType::iterator it = range.first; it != range.second; ++it) + { + if (it->second == marker) + { + mMarkers.erase(it); + eventMarkersChanged(); + return; + } + } + throw std::runtime_error("can't find marker to delete"); } void CustomMarkerCollection::updateMarker(const ESM::CustomMarker &marker, const std::string &newNote) { - std::vector::iterator it = std::find(mMarkers.begin(), mMarkers.end(), marker); - if (it != mMarkers.end()) - it->mNote = newNote; - else - throw std::runtime_error("can't find marker to update"); + std::pair range = mMarkers.equal_range(marker.mCell); - eventMarkersChanged(); + for (ContainerType::iterator it = range.first; it != range.second; ++it) + { + if (it->second == marker) + { + it->second.mNote = newNote; + eventMarkersChanged(); + return; + } + } + throw std::runtime_error("can't find marker to update"); } void CustomMarkerCollection::clear() @@ -125,16 +135,21 @@ namespace MWGui eventMarkersChanged(); } - std::vector::const_iterator CustomMarkerCollection::begin() const + CustomMarkerCollection::ContainerType::const_iterator CustomMarkerCollection::begin() const { return mMarkers.begin(); } - std::vector::const_iterator CustomMarkerCollection::end() const + CustomMarkerCollection::ContainerType::const_iterator CustomMarkerCollection::end() const { return mMarkers.end(); } + CustomMarkerCollection::RangeType CustomMarkerCollection::getMarkers(const ESM::CellId &cellId) const + { + return mMarkers.equal_range(cellId); + } + size_t CustomMarkerCollection::size() const { return mMarkers.size(); @@ -299,44 +314,43 @@ namespace MWGui MyGUI::Gui::getInstance().destroyWidget(*it); mCustomMarkerWidgets.clear(); - for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) + for (int dX = -1; dX <= 1; ++dX) { - const ESM::CustomMarker& marker = *it; - - if (marker.mCell.mPaged != !mInterior) - continue; - if (mInterior) + for (int dY =-1; dY <= 1; ++dY) { - if (marker.mCell.mWorldspace != mPrefix) - continue; - } - else - { - if (std::abs(marker.mCell.mIndex.mX - mCurX) > 1) - continue; - if (std::abs(marker.mCell.mIndex.mY - mCurY) > 1) - continue; - } + ESM::CellId cellId; + cellId.mPaged = !mInterior; + cellId.mWorldspace = (mInterior ? mPrefix : "sys::default"); + cellId.mIndex.mX = mCurX+dX; + cellId.mIndex.mY = mCurY+dY; - MarkerUserData markerPos (mLocalMapRender); - MyGUI::IntPoint widgetPos = getMarkerPosition(marker.mWorldX, marker.mWorldY, markerPos); + CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellId); + for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it) + { + const ESM::CustomMarker& marker = it->second; - MyGUI::IntCoord widgetCoord(widgetPos.left - 8, - widgetPos.top - 8, - 16, 16); - MarkerWidget* markerWidget = mLocalMap->createWidget("CustomMarkerButton", - widgetCoord, MyGUI::Align::Default); - markerWidget->setDepth(Local_MarkerAboveFogLayer); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", MyGUI::TextIterator::toTagsString(marker.mNote)); - markerWidget->setNormalColour(MyGUI::Colour(0.6f, 0.6f, 0.6f)); - markerWidget->setHoverColour(MyGUI::Colour(1.0f, 1.0f, 1.0f)); - markerWidget->setUserData(marker); - markerWidget->setNeedMouseFocus(true); - customMarkerCreated(markerWidget); - mCustomMarkerWidgets.push_back(markerWidget); + MarkerUserData markerPos (mLocalMapRender); + MyGUI::IntPoint widgetPos = getMarkerPosition(marker.mWorldX, marker.mWorldY, markerPos); + + MyGUI::IntCoord widgetCoord(widgetPos.left - 8, + widgetPos.top - 8, + 16, 16); + MarkerWidget* markerWidget = mLocalMap->createWidget("CustomMarkerButton", + widgetCoord, MyGUI::Align::Default); + markerWidget->setDepth(Local_MarkerAboveFogLayer); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", MyGUI::TextIterator::toTagsString(marker.mNote)); + markerWidget->setNormalColour(MyGUI::Colour(0.6f, 0.6f, 0.6f)); + markerWidget->setHoverColour(MyGUI::Colour(1.0f, 1.0f, 1.0f)); + markerWidget->setUserData(marker); + markerWidget->setNeedMouseFocus(true); + customMarkerCreated(markerWidget); + mCustomMarkerWidgets.push_back(markerWidget); + } + } } + redraw(); } @@ -411,11 +425,9 @@ namespace MWGui MWBase::World::DoorMarker marker = *it; std::vector destNotes; - for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) - { - if (it->mCell == marker.dest) - destNotes.push_back(it->mNote); - } + CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(marker.dest); + for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it) + destNotes.push_back(it->second.mNote); MarkerUserData data (mLocalMapRender); data.notes = destNotes; diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 388103b5d..ec4298786 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -42,14 +42,20 @@ namespace MWGui size_t size() const; - std::vector::const_iterator begin() const; - std::vector::const_iterator end() const; + typedef std::multimap ContainerType; + + typedef std::pair RangeType; + + ContainerType::const_iterator begin() const; + ContainerType::const_iterator end() const; + + RangeType getMarkers(const ESM::CellId& cellId) const; typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; EventHandle_Void eventMarkersChanged; private: - std::vector mMarkers; + ContainerType mMarkers; }; class LocalMapBase diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 582519b19..4dbef8a74 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1672,10 +1672,10 @@ namespace MWGui writer.endRecord(ESM::REC_ASPL); } - for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) + for (CustomMarkerCollection::ContainerType::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) { writer.startRecord(ESM::REC_MARK); - (*it).save(writer); + it->second.save(writer); writer.endRecord(ESM::REC_MARK); } } diff --git a/components/esm/cellid.cpp b/components/esm/cellid.cpp index 3c6e23ffd..c77b27b22 100644 --- a/components/esm/cellid.cpp +++ b/components/esm/cellid.cpp @@ -35,3 +35,26 @@ bool ESM::operator!= (const CellId& left, const CellId& right) { return !(left==right); } + +bool ESM::operator < (const CellId& left, const CellId& right) +{ + if (left.mPaged < right.mPaged) + return true; + if (left.mPaged > right.mPaged) + return false; + + if (left.mPaged) + { + if (left.mIndex.mX < right.mIndex.mX) + return true; + if (left.mIndex.mX > right.mIndex.mX) + return false; + + if (left.mIndex.mY < right.mIndex.mY) + return true; + if (left.mIndex.mY > right.mIndex.mY) + return false; + } + + return left.mWorldspace < right.mWorldspace; +} diff --git a/components/esm/cellid.hpp b/components/esm/cellid.hpp index 44a1b387a..56d5a674e 100644 --- a/components/esm/cellid.hpp +++ b/components/esm/cellid.hpp @@ -26,6 +26,7 @@ namespace ESM bool operator== (const CellId& left, const CellId& right); bool operator!= (const CellId& left, const CellId& right); + bool operator< (const CellId& left, const CellId& right); } #endif From 1b3cc957f836195cac56b0f7275ee0a646712c72 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 17 Jul 2015 15:13:43 -0500 Subject: [PATCH 094/419] Move some OSG static library setup code --- components/resource/texturemanager.cpp | 8 ++++++++ components/sdlutil/sdlcursormanager.cpp | 6 ------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 62cbd6bb3..5da0a008a 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -6,6 +6,14 @@ #include +#ifdef OSG_LIBRARY_STATIC +// This list of plugins should match with the list in the top-level CMakelists.txt. +USE_OSGPLUGIN(png) +USE_OSGPLUGIN(tga) +USE_OSGPLUGIN(dds) +USE_OSGPLUGIN(jpeg) +#endif + namespace { diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 508d72589..2004e806c 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -16,12 +16,6 @@ #include "imagetosurface.hpp" #ifdef OSG_LIBRARY_STATIC -// This list of plugins should match with the list in the top-level CMakelists.txt. -USE_OSGPLUGIN(png) -USE_OSGPLUGIN(tga) -USE_OSGPLUGIN(dds) -USE_OSGPLUGIN(jpeg) - // Sets the default windowing system interface according to the OS. // Necessary for OpenSceneGraph to do some things, like decompression. USE_GRAPHICSWINDOW() From 420789baa9f8418c146f0532d84171d697ec2f61 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 17 Jul 2015 15:26:04 -0500 Subject: [PATCH 095/419] Remove an unused include --- components/sdlutil/sdlcursormanager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 2004e806c..89928d165 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include "imagetosurface.hpp" From 6e493500c9099a646598ae92984cd66f54aa6ca7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 00:14:11 +0200 Subject: [PATCH 096/419] Show custom map markers on the tooltip of the world map marker (Fixes #2711) --- apps/openmw/mwgui/mapwindow.cpp | 57 +++++++++++++++++++++++++++++---- apps/openmw/mwgui/mapwindow.hpp | 7 ++-- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 7778569d2..2485f3c94 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -783,15 +783,19 @@ namespace MWGui MyGUI::Widget* markerWidget = mGlobalMap->createWidget("MarkerButton", widgetCoord, MyGUI::Align::Default); + + markerWidget->setUserString("Caption_TextOneLine", name); + + setGlobalMapMarkerTooltip(markerWidget, x, y); + + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setNeedMouseFocus(true); markerWidget->setColour(MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=normal}"))); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", name); markerWidget->setDepth(Global_MarkerLayer); markerWidget->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); markerWidget->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); - mGlobalMapMarkers.push_back(markerWidget); + mGlobalMapMarkers[std::make_pair(x,y)] = markerWidget; } } @@ -816,6 +820,45 @@ namespace MWGui NoDrop::onFrame(dt); } + void MapWindow::setGlobalMapMarkerTooltip(MyGUI::Widget* markerWidget, int x, int y) + { + ESM::CellId cellId; + cellId.mIndex.mX = x; + cellId.mIndex.mY = y; + cellId.mWorldspace = "sys::default"; + cellId.mPaged = true; + CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellId); + std::vector destNotes; + for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it) + destNotes.push_back(it->second.mNote); + + if (!destNotes.empty()) + { + MarkerUserData data (NULL); + data.notes = destNotes; + data.caption = markerWidget->getUserString("Caption_TextOneLine"); + markerWidget->setUserData(data); + markerWidget->setUserString("ToolTipType", "MapMarker"); + } + else + { + markerWidget->setUserString("ToolTipType", "Layout"); + } + } + + void MapWindow::updateCustomMarkers() + { + LocalMapBase::updateCustomMarkers(); + + for (std::map, MyGUI::Widget*>::iterator widgetIt = mGlobalMapMarkers.begin(); widgetIt != mGlobalMapMarkers.end(); ++widgetIt) + { + int x = widgetIt->first.first; + int y = widgetIt->first.second; + MyGUI::Widget* markerWidget = widgetIt->second; + setGlobalMapMarkerTooltip(markerWidget, x, y); + } + } + void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { if (_id!=MyGUI::MouseButton::Left) return; @@ -913,8 +956,8 @@ namespace MWGui mGlobalMapRender->clear(); mChanged = true; - for (std::vector::iterator it = mGlobalMapMarkers.begin(); it != mGlobalMapMarkers.end(); ++it) - MyGUI::Gui::getInstance().destroyWidget(*it); + for (std::map, MyGUI::Widget*>::iterator it = mGlobalMapMarkers.begin(); it != mGlobalMapMarkers.end(); ++it) + MyGUI::Gui::getInstance().destroyWidget(it->second); mGlobalMapMarkers.clear(); } @@ -1034,6 +1077,8 @@ namespace MWGui bool LocalMapBase::MarkerUserData::isPositionExplored() const { + if (!mLocalMapRender) + return true; return mLocalMapRender->isPositionExplored(nX, nY, cellX, cellY, interior); } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index ec4298786..a5594bee8 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -126,7 +126,7 @@ namespace MWGui std::vector mMagicMarkerWidgets; std::vector mCustomMarkerWidgets; - void updateCustomMarkers(); + virtual void updateCustomMarkers(); void applyFogOfWar(); @@ -203,6 +203,8 @@ namespace MWGui void onFrame(float dt); + virtual void updateCustomMarkers(); + /// Clear all savegame-specific data void clear(); @@ -221,6 +223,7 @@ namespace MWGui void onNoteDoubleClicked(MyGUI::Widget* sender); void onChangeScrollWindowCoord(MyGUI::Widget* sender); void globalMapUpdatePlayer(); + void setGlobalMapMarkerTooltip(MyGUI::Widget* widget, int x, int y); MyGUI::ScrollView* mGlobalMap; std::auto_ptr mGlobalMapTexture; @@ -248,7 +251,7 @@ namespace MWGui MWRender::GlobalMap* mGlobalMapRender; - std::vector mGlobalMapMarkers; + std::map, MyGUI::Widget*> mGlobalMapMarkers; EditNoteDialog mEditNoteDialog; ESM::CustomMarker mEditingMarker; From c783b50a8399411f705cad3c4fc91a0e60f13144 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 01:38:35 +0200 Subject: [PATCH 097/419] Fix config file priority in the launcher to match OpenMW --- apps/launcher/maindialog.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 4b7c0504f..99c40b88b 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -309,11 +309,11 @@ bool Launcher::MainDialog::setupGameSettings() mGameSettings.readUserFile(stream); } - // Now the rest + // Now the rest - priority: user > local > global QStringList paths; - paths.append(userPath + QString("openmw.cfg")); - paths.append(QString("openmw.cfg")); paths.append(globalPath + QString("openmw.cfg")); + paths.append(QString("openmw.cfg")); + paths.append(userPath + QString("openmw.cfg")); foreach (const QString &path, paths) { qDebug() << "Loading config file:" << qPrintable(path); From f09e4620b6a730f0f2bbf660e18dd65d13a94d9f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 03:01:06 +0200 Subject: [PATCH 098/419] Move OpenMW version information to a textfile instead of compiling it in Now we don't need to recompile 3 .cpp files and re-link whenever the current git HEAD changes. --- .gitignore | 1 - CMakeLists.txt | 2 ++ apps/launcher/maindialog.cpp | 47 +++++++++++++++----------- apps/launcher/maindialog.hpp | 2 ++ apps/openmw/engine.cpp | 5 +-- apps/openmw/main.cpp | 16 ++++----- apps/openmw/mwgui/mainmenu.cpp | 19 ++--------- apps/openmw/mwgui/mainmenu.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +-- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++- cmake/GitVersion.cmake | 2 +- components/CMakeLists.txt | 26 +++++++------- components/version/version.cpp | 41 ++++++++++++++++++++++ components/version/version.hpp | 28 +++++++++++++++ components/version/version.hpp.cmake | 13 ------- files/version.in | 3 ++ 16 files changed, 135 insertions(+), 81 deletions(-) create mode 100644 components/version/version.cpp create mode 100644 components/version/version.hpp delete mode 100644 components/version/version.hpp.cmake create mode 100644 files/version.in diff --git a/.gitignore b/.gitignore index 944fb8418..88f591aae 100644 --- a/.gitignore +++ b/.gitignore @@ -41,7 +41,6 @@ resources ## generated objects apps/openmw/config.hpp -components/version/version.hpp docs/mainpage.hpp moc_*.cxx *.cxx_parameters diff --git a/CMakeLists.txt b/CMakeLists.txt index a133a8d6a..37680c13e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -366,6 +366,7 @@ IF(NOT WIN32 AND NOT APPLE) # Install global configuration files INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/resources/version" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") IF(BUILD_OPENCS) @@ -381,6 +382,7 @@ if(WIN32) FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll") INSTALL(FILES ${dll_files} DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") + INSTALL(FILES "${OpenMW_BINARY_DIR}/resources/version" DESTINATION ".") INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt") INSTALL(FILES diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 99c40b88b..c18c26cdd 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -57,26 +57,6 @@ Launcher::MainDialog::MainDialog(QWidget *parent) // Remove what's this? button setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint); - // Add version information to bottom of the window - QString revision(OPENMW_VERSION_COMMITHASH); - QString tag(OPENMW_VERSION_TAGHASH); - - versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); - if (!revision.isEmpty() && !tag.isEmpty()) - { - if (revision == tag) { - versionLabel->setText(tr("OpenMW %1 release").arg(OPENMW_VERSION)); - } else { - versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10))); - } - - // Add the compile date and time - versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(), - QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate), - QLocale(QLocale::C).toTime(QString(__TIME__).simplified(), - QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate))); - } - createIcons(); } @@ -186,11 +166,38 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog() return setup() ? FirstRunDialogResultContinue : FirstRunDialogResultFailure; } +void Launcher::MainDialog::setVersionLabel() +{ + // Add version information to bottom of the window + Version::Version v = Version::getOpenmwVersion(mGameSettings.value("resources").toUtf8().constData()); + + QString revision(QString::fromUtf8(v.mCommitHash.c_str())); + QString tag(QString::fromUtf8(v.mTagHash.c_str())); + + versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + if (!revision.isEmpty() && !tag.isEmpty()) + { + if (revision == tag) { + versionLabel->setText(tr("OpenMW %1 release").arg(QString::fromUtf8(v.mVersion.c_str()))); + } else { + versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10))); + } + + // Add the compile date and time + versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(), + QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate), + QLocale(QLocale::C).toTime(QString(__TIME__).simplified(), + QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate))); + } +} + bool Launcher::MainDialog::setup() { if (!setupGameSettings()) return false; + setVersionLabel(); + mLauncherSettings.setContentList(mGameSettings); if (!setupGraphicsSettings()) diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index c90309990..298682d20 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -72,6 +72,8 @@ namespace Launcher bool setupGameSettings(); bool setupGraphicsSettings(); + void setVersionLabel(); + void loadSettings(); void saveSettings(); diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index dc2cb8f37..fb879d273 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include "mwinput/inputmanagerimp.hpp" @@ -493,7 +493,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) rootNode->addChild(guiRoot); MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem.get(), mCfgMgr.getLogPath().string() + std::string("/"), myguiResources, - mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); + mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap, + Version::getOpenmwVersionDescription(mResDir.string())); mEnvironment.setWindowManager (window); // Create sound system diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 85a0dbe55..3d631c743 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -199,18 +199,14 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat return false; } - std::cout << "OpenMW version " << OPENMW_VERSION; - std::string rev = OPENMW_VERSION_COMMITHASH; - std::string tag = OPENMW_VERSION_TAGHASH; - if (!rev.empty() && !tag.empty()) - { - rev = rev.substr(0, 10); - std::cout << " (revision " << rev << ")"; - } - std::cout << std::endl; - if (variables.count ("version")) + { + cfgMgr.readConfiguration(variables, desc, true); + + Version::Version v = Version::getOpenmwVersion(variables["resources"].as()); + std::cout << v.describe() << std::endl; return false; + } cfgMgr.readConfiguration(variables, desc); diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index e24894e89..409306986 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include #include #include @@ -28,7 +26,7 @@ namespace MWGui { - MainMenu::MainMenu(int w, int h, const VFS::Manager* vfs) + MainMenu::MainMenu(int w, int h, const VFS::Manager* vfs, const std::string& versionDescription) : Layout("openmw_mainmenu.layout") , mWidth (w), mHeight (h) , mVFS(vfs), mButtonBox(0) @@ -38,20 +36,7 @@ namespace MWGui , mSaveGameDialog(NULL) { getWidget(mVersionText, "VersionText"); - std::stringstream sstream; - sstream << "OpenMW Version: " << OPENMW_VERSION; - - // adding info about git hash if available - std::string rev = OPENMW_VERSION_COMMITHASH; - std::string tag = OPENMW_VERSION_TAGHASH; - if (!rev.empty() && !tag.empty()) - { - rev = rev.substr(0,10); - sstream << "\nRevision: " << rev; - } - - std::string output = sstream.str(); - mVersionText->setCaption(output); + mVersionText->setCaption(versionDescription); mHasAnimatedMenu = mVFS->exists("video/menu_background.bik"); diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index d01f67fbd..fe256dc8e 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -29,7 +29,7 @@ namespace MWGui public: - MainMenu(int w, int h, const VFS::Manager* vfs); + MainMenu(int w, int h, const VFS::Manager* vfs, const std::string& versionDescription); ~MainMenu(); void onResChange(int w, int h); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a2a826161..a739ea6e7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -113,7 +113,7 @@ namespace MWGui WindowManager::WindowManager( osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem , const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, - Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) + Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap, const std::string& versionDescription) : mResourceSystem(resourceSystem) , mViewer(viewer) , mConsoleOnlyScripts(consoleOnlyScripts) @@ -187,6 +187,7 @@ namespace MWGui , mRestAllowed(true) , mFPS(0.0f) , mFallbackMap(fallbackMap) + , mVersionDescription(versionDescription) { float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getTextureManager(), uiScale); @@ -272,7 +273,7 @@ namespace MWGui mDragAndDrop = new DragAndDrop(); mRecharge = new Recharge(); - mMenu = new MainMenu(w, h, mResourceSystem->getVFS()); + mMenu = new MainMenu(w, h, mResourceSystem->getVFS(), mVersionDescription); mLocalMapRender = new MWRender::LocalMap(mViewer); mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender); trackWindow(mMap, "map"); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index e6c8d0a81..38af1a79e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -116,7 +116,7 @@ namespace MWGui WindowManager(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, - Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap); + Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap, const std::string& versionDescription); virtual ~WindowManager(); void initUI(); @@ -487,6 +487,8 @@ namespace MWGui std::map mFallbackMap; + std::string mVersionDescription; + /** * Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property. * Supported syntax: diff --git a/cmake/GitVersion.cmake b/cmake/GitVersion.cmake index 0087461a1..0679e406c 100644 --- a/cmake/GitVersion.cmake +++ b/cmake/GitVersion.cmake @@ -21,4 +21,4 @@ else (SUCCESS) message(WARNING "Failed to get valid version information from Git") endif (SUCCESS) -configure_file(${VERSION_HPP_IN} ${VERSION_HPP}) +configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index d91bb5c30..85e61cee5 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -1,23 +1,23 @@ project (Components) # Version file -set (VERSION_HPP_IN ${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp.cmake) -set (VERSION_HPP ${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp) +set (VERSION_IN_FILE "${OpenMW_SOURCE_DIR}/files/version.in") +set (VERSION_FILE "${OpenMW_BINARY_DIR}/resources/version") if (GIT_CHECKOUT) - add_custom_target (git-version - COMMAND ${CMAKE_COMMAND} - -DGIT_EXECUTABLE=${GIT_EXECUTABLE} + add_custom_target (git-version + COMMAND ${CMAKE_COMMAND} + -DGIT_EXECUTABLE=${GIT_EXECUTABLE} -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} - -DVERSION_HPP_IN=${VERSION_HPP_IN} - -DVERSION_HPP=${VERSION_HPP} - -DOPENMW_VERSION_MAJOR=${OPENMW_VERSION_MAJOR} - -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} - -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} - -DOPENMW_VERSION=${OPENMW_VERSION} + -DVERSION_IN_FILE=${VERSION_IN_FILE} + -DVERSION_FILE=${VERSION_FILE} + -DOPENMW_VERSION_MAJOR=${OPENMW_VERSION_MAJOR} + -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} + -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} + -DOPENMW_VERSION=${OPENMW_VERSION} -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake - VERBATIM) + VERBATIM) else (GIT_CHECKOUT) - configure_file(${VERSION_HPP_IN} ${VERSION_HPP}) + configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) endif (GIT_CHECKOUT) find_package(OpenGL REQUIRED) diff --git a/components/version/version.cpp b/components/version/version.cpp new file mode 100644 index 000000000..c87943f9e --- /dev/null +++ b/components/version/version.cpp @@ -0,0 +1,41 @@ +#include "version.hpp" + +#include +#include + +namespace Version +{ + +Version getOpenmwVersion(const std::string &resourcePath) +{ + boost::filesystem::path path (resourcePath + "/version"); + + boost::filesystem::ifstream stream (path); + + Version v; + std::getline(stream, v.mVersion); + std::getline(stream, v.mCommitHash); + std::getline(stream, v.mTagHash); + return v; +} + +std::string Version::describe() +{ + std::string str = "OpenMW version " + mVersion; + std::string rev = mCommitHash; + std::string tag = mTagHash; + if (!rev.empty() && !tag.empty()) + { + rev = rev.substr(0, 10); + str += "\nRevision: " + rev; + } + return str; +} + +std::string getOpenmwVersionDescription(const std::string &resourcePath) +{ + Version v = getOpenmwVersion(resourcePath); + return v.describe(); +} + +} diff --git a/components/version/version.hpp b/components/version/version.hpp new file mode 100644 index 000000000..7371e786e --- /dev/null +++ b/components/version/version.hpp @@ -0,0 +1,28 @@ +#ifndef VERSION_HPP +#define VERSION_HPP + +#include + +namespace Version +{ + + struct Version + { + std::string mVersion; + std::string mCommitHash; + std::string mTagHash; + + std::string describe(); + }; + + /// Read OpenMW version from the version file located in resourcePath. + Version getOpenmwVersion(const std::string& resourcePath); + + /// Helper function to getOpenmwVersion and describe() it + std::string getOpenmwVersionDescription(const std::string& resourcePath); + +} + + +#endif // VERSION_HPP + diff --git a/components/version/version.hpp.cmake b/components/version/version.hpp.cmake deleted file mode 100644 index 4cdfa32f0..000000000 --- a/components/version/version.hpp.cmake +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef VERSION_HPP -#define VERSION_HPP - -#define OPENMW_VERSION_MAJOR @OPENMW_VERSION_MAJOR@ -#define OPENMW_VERSION_MINOR @OPENMW_VERSION_MINOR@ -#define OPENMW_VERSION_RELEASE @OPENMW_VERSION_RELEASE@ -#define OPENMW_VERSION "@OPENMW_VERSION@" - -#define OPENMW_VERSION_COMMITHASH "@OPENMW_VERSION_COMMITHASH@" -#define OPENMW_VERSION_TAGHASH "@OPENMW_VERSION_TAGHASH@" - -#endif // VERSION_HPP - diff --git a/files/version.in b/files/version.in new file mode 100644 index 000000000..f894d3b4a --- /dev/null +++ b/files/version.in @@ -0,0 +1,3 @@ +@OPENMW_VERSION@ +@OPENMW_VERSION_COMMITHASH@ +@OPENMW_VERSION_TAGHASH@ From a33ca75742cc0be779041f236fcba2a3ef9f7320 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 03:23:41 +0200 Subject: [PATCH 099/419] Pass AnimPriority by const reference --- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index dab289f6c..ee0ce6df1 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -461,7 +461,7 @@ namespace MWRender mTextKeyListener->handleTextKey(groupname, key, map); } - void Animation::play(const std::string &groupname, AnimPriority priority, int blendMask, bool autodisable, float speedmult, + void Animation::play(const std::string &groupname, const AnimPriority& priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback) { if(!mObjectRoot || mAnimSources.empty()) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 1cf2ce9ba..23f807238 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -353,7 +353,7 @@ public: * \param loopFallback Allow looping an animation that has no loop keys, i.e. fall back to use * the "start" and "stop" keys for looping? */ - void play(const std::string &groupname, AnimPriority priority, int blendMask, bool autodisable, + void play(const std::string &groupname, const AnimPriority& priority, int blendMask, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops, bool loopfallback=false); From 58720e6a28400a935733a3999229bceeb39c7a5b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 03:52:38 +0200 Subject: [PATCH 100/419] Fix the OpenCS rendering crash on exit (Fixes #2735) --- apps/opencs/model/world/data.cpp | 10 +++++----- apps/opencs/model/world/data.hpp | 6 +++--- apps/opencs/view/render/cell.cpp | 2 +- apps/opencs/view/render/object.cpp | 2 +- apps/opencs/view/render/previewwidget.cpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 7 ++++--- apps/opencs/view/render/scenewidget.hpp | 8 +++++--- apps/opencs/view/render/worldspacewidget.cpp | 2 +- 8 files changed, 21 insertions(+), 18 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index a92a7ad79..3714117b6 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -62,7 +62,7 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager) : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells), - mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0), mResourceSystem(resourcesManager.getVFS()) + mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0), mResourceSystem(new Resource::ResourceSystem(resourcesManager.getVFS())) { int index = 0; @@ -537,14 +537,14 @@ CSMWorld::Data::~Data() delete mReader; } -Resource::ResourceSystem* CSMWorld::Data::getResourceSystem() +boost::shared_ptr CSMWorld::Data::getResourceSystem() { - return &mResourceSystem; + return mResourceSystem; } -const Resource::ResourceSystem* CSMWorld::Data::getResourceSystem() const +boost::shared_ptr CSMWorld::Data::getResourceSystem() const { - return &mResourceSystem; + return mResourceSystem; } const CSMWorld::IdCollection& CSMWorld::Data::getGlobals() const diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 6e651b374..06f76607f 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -113,7 +113,7 @@ namespace CSMWorld std::map > mRefLoadCache; int mReaderIndex; - Resource::ResourceSystem mResourceSystem; + boost::shared_ptr mResourceSystem; std::vector > mReaders; @@ -138,9 +138,9 @@ namespace CSMWorld const VFS::Manager* getVFS() const; - Resource::ResourceSystem* getResourceSystem(); + boost::shared_ptr getResourceSystem(); - const Resource::ResourceSystem* getResourceSystem() const; + boost::shared_ptr getResourceSystem() const; const IdCollection& getGlobals() const; diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 063413248..fe2eab066 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -71,7 +71,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT) { - mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); + mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); mTerrain->loadCell(esmLand->mX, esmLand->mY); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index ea27b1432..973893a71 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -116,7 +116,7 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, bool forceBaseToZero) -: mData (data), mBaseNode(0), mParentNode(parentNode), mResourceSystem(data.getResourceSystem()), mForceBaseToZero (forceBaseToZero) +: mData (data), mBaseNode(0), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero) { mBaseNode = new osg::PositionAttitudeTransform; parentNode->addChild(mBaseNode); diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index f0cbc939a..f512a8bb6 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -8,7 +8,7 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) -: SceneWidget (data.getResourceSystem()->getSceneManager(), parent), mData (data), mObject(data, mRootNode, id, referenceable) +: SceneWidget (data.getResourceSystem(), parent), mData (data), mObject(data, mRootNode, id, referenceable) { mView->setCameraManipulator(new osgGA::TrackballManipulator); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 208a7a5b7..d91c075e1 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "../widget/scenetoolmode.hpp" #include "../../model/settings/usersettings.hpp" @@ -132,9 +133,9 @@ void CompositeViewer::update() // --------------------------------------------------- -SceneWidget::SceneWidget(Resource::SceneManager* sceneManager, QWidget *parent, Qt::WindowFlags f) +SceneWidget::SceneWidget(boost::shared_ptr resourceSystem, QWidget *parent, Qt::WindowFlags f) : RenderWidget(parent, f) - , mSceneManager(sceneManager) + , mResourceSystem(resourceSystem) , mLighting(NULL) , mHasDefaultAmbient(false) { @@ -147,7 +148,7 @@ SceneWidget::SceneWidget(Resource::SceneManager* sceneManager, QWidget *parent, SceneWidget::~SceneWidget() { // Since we're holding on to the scene templates past the existance of this graphics context, we'll need to manually release the created objects - mSceneManager->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState()); + mResourceSystem->getSceneManager()->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState()); } void SceneWidget::setLighting(Lighting *lighting) diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index c269f355d..f5c36b641 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -4,6 +4,8 @@ #include #include +#include + #include "lightingday.hpp" #include "lightingnight.hpp" #include "lightingbright.hpp" @@ -13,7 +15,7 @@ namespace Resource { - class SceneManager; + class ResourceSystem; } namespace osg @@ -57,7 +59,7 @@ namespace CSVRender { Q_OBJECT public: - SceneWidget(Resource::SceneManager* sceneManager, QWidget* parent = 0, Qt::WindowFlags f = 0); + SceneWidget(boost::shared_ptr resourceSystem, QWidget* parent = 0, Qt::WindowFlags f = 0); virtual ~SceneWidget(); CSVWidget::SceneToolMode *makeLightingSelector (CSVWidget::SceneToolbar *parent); @@ -73,7 +75,7 @@ namespace CSVRender void setAmbient(const osg::Vec4f& ambient); - Resource::SceneManager* mSceneManager; + boost::shared_ptr mResourceSystem; Lighting* mLighting; diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 3a70b7844..39ce09f31 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -24,7 +24,7 @@ #include "editmode.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) -: SceneWidget (document.getData().getResourceSystem()->getSceneManager(), parent), mSceneElements(0), mRun(0), mDocument(document), +: SceneWidget (document.getData().getResourceSystem(), parent), mSceneElements(0), mRun(0), mDocument(document), mInteractionMask (0) { setAcceptDrops(true); From f8f03804138ad6f5c7e0422fe89b251b998b7a62 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 17 Jul 2015 21:41:53 -0500 Subject: [PATCH 101/419] Fix for loading window icon on Windows --- apps/openmw/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index dc2cb8f37..bfb8c7113 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -414,7 +414,7 @@ void OMW::Engine::setWindowIcon() { boost::filesystem::ifstream windowIconStream; std::string windowIcon = (mResDir / "mygui" / "openmw.png").string(); - windowIconStream.open(windowIcon); + windowIconStream.open(windowIcon, std::ios_base::in | std::ios_base::binary); if (windowIconStream.fail()) std::cerr << "Failed to open " << windowIcon << std::endl; osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png"); From 39ab9948f637d5d30cf5ac780a5de2756ab1b053 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Jul 2015 11:40:18 +0200 Subject: [PATCH 102/419] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index ce76c104e..7774b5afa 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -59,6 +59,7 @@ Programmers Julien Voisin (jvoisin/ap0) Karl-Felix Glatzer (k1ll) Kevin Poitra (PuppyKevin) + kunesj Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) From 73b6df8280dee4ad747c5f296401f63eab9f1efd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Jul 2015 13:09:17 +0200 Subject: [PATCH 103/419] put script compilation in script subview behind a timer --- apps/opencs/view/world/scriptsubview.cpp | 29 ++++++++++++++++++++++-- apps/opencs/view/world/scriptsubview.hpp | 6 +++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 7b5b1131e..dfdca8b48 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "../../model/doc/document.hpp" #include "../../model/world/universalid.hpp" @@ -35,6 +36,12 @@ void CSVWorld::ScriptSubView::addButtonBar() mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&))); } +void CSVWorld::ScriptSubView::recompile() +{ + if (!mCompileDelay->isActive()) + mCompileDelay->start (5000); +} + CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) @@ -101,6 +108,12 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mErrors, SIGNAL (highlightError (int, int)), this, SLOT (highlightError (int, int))); + + mCompileDelay = new QTimer (this); + mCompileDelay->setSingleShot (true); + connect (mCompileDelay, SIGNAL (timeout()), this, SLOT (updateRequest())); + + recompile(); } void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) @@ -136,6 +149,9 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr mButtons->updateUserSetting (name, value); mErrors->updateUserSetting (name, value); + + if (name=="script-editor/warnings") + recompile(); } void CSVWorld::ScriptSubView::setStatusBar (bool show) @@ -198,7 +214,7 @@ void CSVWorld::ScriptSubView::textChanged() mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*mModel, mModel->getModelIndex (getUniversalId().getId(), mColumn), source)); - mErrors->update (source.toUtf8().constData()); + recompile(); } void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) @@ -219,7 +235,7 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo mEditor->setPlainText (source); mEditor->setTextCursor (cursor); - mErrors->update (source.toUtf8().constData()); + recompile(); } } @@ -259,3 +275,12 @@ void CSVWorld::ScriptSubView::highlightError (int line, int column) mEditor->setFocus(); mEditor->setTextCursor (cursor); } + +void CSVWorld::ScriptSubView::updateRequest() +{ + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); + + QString source = mModel->data (index).toString(); + + mErrors->update (source.toUtf8().constData()); +} diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index a9c8dccb3..3481989f1 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -11,6 +11,7 @@ class QModelIndex; class QLabel; class QVBoxLayout; class QSplitter; +class QTime; namespace CSMDoc { @@ -43,11 +44,14 @@ namespace CSVWorld QVBoxLayout mLayout; QSplitter *mMain; ScriptErrorTable *mErrors; + QTimer *mCompileDelay; private: void addButtonBar(); + void recompile(); + public: ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); @@ -77,6 +81,8 @@ namespace CSVWorld void switchToId (const std::string& id); void highlightError (int line, int column); + + void updateRequest(); }; } From 8763a3b3c3e9250bd3399102b0f27fce102d7610 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Jul 2015 15:32:38 +0200 Subject: [PATCH 104/419] make compilation delay configurable via a user setting --- apps/opencs/model/settings/usersettings.cpp | 6 ++++++ apps/opencs/view/world/scriptsubview.cpp | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 673db4057..5a4b58266 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -319,6 +319,12 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() Setting *toolbar = createSetting (Type_CheckBox, "toolbar", "Show toolbar"); toolbar->setDefaultValue ("true"); + Setting *delay = createSetting (Type_SpinBox, "compile-delay", + "Delay between updating of source errors"); + delay->setDefaultValue (100); + delay->setRange (0, 10000); + delay->setToolTip ("Delay in milliseconds"); + Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int"); formatInt->setDefaultValues (QStringList() << "Dark magenta"); formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index dfdca8b48..ee0adb6f5 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -39,7 +39,8 @@ void CSVWorld::ScriptSubView::addButtonBar() void CSVWorld::ScriptSubView::recompile() { if (!mCompileDelay->isActive()) - mCompileDelay->start (5000); + mCompileDelay->start ( + CSMSettings::UserSettings::instance().setting ("script-editor/compile-delay").toInt()); } CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) @@ -144,6 +145,10 @@ void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStr } } } + else if (name=="script-editor/compile-delay") + { + mCompileDelay->setInterval (value.at (0).toInt()); + } if (mButtons) mButtons->updateUserSetting (name, value); From df077f8649b89a0f85e2c6b3db4c355e92dd8c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Sat, 18 Jul 2015 16:56:57 +0200 Subject: [PATCH 105/419] color tooltip red when taking item would result in crime --- apps/openmw/mwgui/tooltips.cpp | 9 +++++++++ files/mygui/openmw_hud_box.skin.xml | 12 ++++++++++++ files/mygui/openmw_windows.skin.xml | 8 ++++++++ 3 files changed, 29 insertions(+) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 22d5d14f7..e901714a5 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -369,6 +369,15 @@ namespace MWGui MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) { mDynamicToolTipBox->setVisible(true); + + if(checkOwned()) + { + mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_R"); + } + else + { + mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp"); + } std::string caption = info.caption; std::string image = info.icon; diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index 4e6349768..7019351bd 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -31,5 +31,17 @@ + + + + + + + + + + + + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index e74038391..29299dc06 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -128,6 +128,14 @@ + + + + + + + + From f1ac440b7832dce0745c2e35bfa8c40ca4c66c36 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Jul 2015 17:00:00 +0200 Subject: [PATCH 106/419] do not allow editing of deleted scripts --- apps/opencs/view/world/scripterrortable.cpp | 7 ++- apps/opencs/view/world/scripterrortable.hpp | 2 + apps/opencs/view/world/scriptsubview.cpp | 57 ++++++++++++++------- apps/opencs/view/world/scriptsubview.hpp | 5 ++ 4 files changed, 51 insertions(+), 20 deletions(-) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 20b197c54..3e80c5bd4 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -100,7 +100,7 @@ void CSVWorld::ScriptErrorTable::updateUserSetting (const QString& name, const Q void CSVWorld::ScriptErrorTable::update (const std::string& source) { - setRowCount (0); + clear(); try { @@ -122,6 +122,11 @@ void CSVWorld::ScriptErrorTable::update (const std::string& source) } } +void CSVWorld::ScriptErrorTable::clear() +{ + setRowCount (0); +} + void CSVWorld::ScriptErrorTable::cellClicked (int row, int column) { if (item (row, 1)) diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp index f16a96a74..98db425cf 100644 --- a/apps/opencs/view/world/scripterrortable.hpp +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -42,6 +42,8 @@ namespace CSVWorld void update (const std::string& source); + void clear(); + private slots: void cellClicked (int row, int column); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index ee0adb6f5..d405d1765 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -38,11 +38,31 @@ void CSVWorld::ScriptSubView::addButtonBar() void CSVWorld::ScriptSubView::recompile() { - if (!mCompileDelay->isActive()) + if (!mCompileDelay->isActive() && !isDeleted()) mCompileDelay->start ( CSMSettings::UserSettings::instance().setting ("script-editor/compile-delay").toInt()); } +bool CSVWorld::ScriptSubView::isDeleted() const +{ + return mModel->data (mModel->getModelIndex (getUniversalId().getId(), mStateColumn)).toInt() + ==CSMWorld::RecordBase::State_Deleted; +} + +void CSVWorld::ScriptSubView::updateDeletedState() +{ + if (isDeleted()) + { + mErrors->clear(); + mEditor->setEnabled (false); + } + else + { + mEditor->setEnabled (true); + recompile(); + } +} + CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mDocument (document), mColumn (-1), mBottom(0), mButtons (0), mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) @@ -68,16 +88,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: mModel = &dynamic_cast ( *document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts)); - for (int i=0; icolumnCount(); ++i) - if (mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display)== - CSMWorld::ColumnBase::Display_ScriptFile) - { - mColumn = i; - break; - } - - if (mColumn==-1) - throw std::logic_error ("Can't find script column"); + mColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_ScriptText); + mStateColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification); QString source = mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString(); @@ -114,7 +126,7 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: mCompileDelay->setSingleShot (true); connect (mCompileDelay, SIGNAL (timeout()), this, SLOT (updateRequest())); - recompile(); + updateDeletedState(); } void CSVWorld::ScriptSubView::updateUserSetting (const QString& name, const QStringList& value) @@ -231,16 +243,21 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); - if (index.row()>=topLeft.row() && index.row()<=bottomRight.row() && - index.column()>=topLeft.column() && index.column()<=bottomRight.column()) + if (index.row()>=topLeft.row() && index.row()<=bottomRight.row()) { - QString source = mModel->data (index).toString(); + if (mStateColumn>=topLeft.column() && mStateColumn<=bottomRight.column()) + updateDeletedState(); - QTextCursor cursor = mEditor->textCursor(); - mEditor->setPlainText (source); - mEditor->setTextCursor (cursor); + if (mColumn>=topLeft.column() && mColumn<=bottomRight.column()) + { + QString source = mModel->data (index).toString(); - recompile(); + QTextCursor cursor = mEditor->textCursor(); + mEditor->setPlainText (source); + mEditor->setTextCursor (cursor); + + recompile(); + } } } @@ -262,6 +279,8 @@ void CSVWorld::ScriptSubView::switchToRow (int row) std::vector selection (1, id); mCommandDispatcher.setSelection (selection); + + updateDeletedState(); } void CSVWorld::ScriptSubView::switchToId (const std::string& id) diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 3481989f1..6125dd259 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -38,6 +38,7 @@ namespace CSVWorld CSMDoc::Document& mDocument; CSMWorld::IdTable *mModel; int mColumn; + int mStateColumn; TableBottomBox *mBottom; RecordButtonBar *mButtons; CSMWorld::CommandDispatcher mCommandDispatcher; @@ -52,6 +53,10 @@ namespace CSVWorld void recompile(); + bool isDeleted() const; + + void updateDeletedState(); + public: ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); From 75f59728984df63a43d9eaa2e42dee572738cb70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Sat, 18 Jul 2015 17:13:20 +0200 Subject: [PATCH 107/419] show owned - better settings --- apps/openmw/mwgui/tooltips.cpp | 18 ++++++++++++------ apps/openmw/mwgui/tooltips.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 6 +++--- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- files/mygui/openmw_windows.skin.xml | 2 +- files/settings-default.cfg | 8 ++++++-- 6 files changed, 25 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index e901714a5..a51c68acf 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -38,6 +38,7 @@ namespace MWGui , mLastMouseY(0) , mEnabled(true) , mFullHelp(false) + , mShowOwned(0) { getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); @@ -55,6 +56,8 @@ namespace MWGui { mMainWidget->getChildAt(i)->setVisible(false); } + + mShowOwned = Settings::Manager::getInt("show owned", "Game"); } void ToolTips::setEnabled(bool enabled) @@ -370,13 +373,16 @@ namespace MWGui { mDynamicToolTipBox->setVisible(true); - if(checkOwned()) + if(mShowOwned == 1 || mShowOwned == 3) { - mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_R"); - } - else - { - mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp"); + if(checkOwned()) + { + mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_R"); + } + else + { + mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp"); + } } std::string caption = info.caption; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index bd4a81c32..b2f172076 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -122,6 +122,8 @@ namespace MWGui bool mEnabled; bool mFullHelp; + + int mShowOwned; }; } #endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 44eed6623..7b618efa7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -187,7 +187,7 @@ namespace MWGui , mRestAllowed(true) , mFPS(0.0f) , mFallbackMap(fallbackMap) - , mShowOwned(false) + , mShowOwned(0) , mVersionDescription(versionDescription) { float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); @@ -264,7 +264,7 @@ namespace MWGui MyGUI::ClipboardManager::getInstance().eventClipboardChanged += MyGUI::newDelegate(this, &WindowManager::onClipboardChanged); MyGUI::ClipboardManager::getInstance().eventClipboardRequested += MyGUI::newDelegate(this, &WindowManager::onClipboardRequested); - mShowOwned = Settings::Manager::getBool("show owned", "Game"); + mShowOwned = Settings::Manager::getInt("show owned", "Game"); } void WindowManager::initUI() @@ -1043,7 +1043,7 @@ namespace MWGui { mToolTips->setFocusObject(focus); - if(mShowOwned && mHud) + if(mHud && (mShowOwned == 2 || mShowOwned == 3)) { bool owned = mToolTips->checkOwned(); mHud->setCrosshairOwned(owned); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 7dae50209..af82c27c0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -487,7 +487,7 @@ namespace MWGui std::map mFallbackMap; - bool mShowOwned; + int mShowOwned; std::string mVersionDescription; diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 29299dc06..47f8cada8 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -131,7 +131,7 @@ - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 4ec0c2480..d84291a24 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -162,8 +162,12 @@ best attack = false difficulty = 0 -# change crosshair color when pointing on owned object -show owned = false +# Change crosshair/toolTip color when pointing on owned object +#0: nothing changed +#1: tint toolTip +#2: tint crosshair +#3: both +show owned = 0 [Saves] character = From cdfa3006a3b94e8cf2f1b0ca50acf783aaa3ec45 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 18 Jul 2015 17:47:50 +0200 Subject: [PATCH 108/419] incorrect sBribe GMSTs for new omwgame files (Fixes #2785) --- apps/opencs/model/doc/document.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 215dbd304..44e6142b0 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -798,9 +798,9 @@ void CSMDoc::Document::addGmsts() "sBookSkillMessage", "sBounty", "sBreath", - "sBribe", - "sBribe", - "sBribe", + "sBribe 10 Gold", + "sBribe 100 Gold", + "sBribe 1000 Gold", "sBribeFail", "sBribeSuccess", "sBuy", From 77f1387da8180c2e8603d6642bc41e366effa7c6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 19:40:31 +0200 Subject: [PATCH 109/419] Include cleanup --- apps/openmw/mwgui/birth.cpp | 2 -- apps/openmw/mwgui/companionitemmodel.cpp | 1 - apps/openmw/mwgui/companionwindow.cpp | 3 --- apps/openmw/mwgui/container.cpp | 2 -- apps/openmw/mwgui/dialogue.cpp | 4 ++-- apps/openmw/mwgui/enchantingdialog.cpp | 1 - apps/openmw/mwgui/hud.cpp | 1 - apps/openmw/mwgui/inventoryitemmodel.cpp | 2 -- apps/openmw/mwgui/inventorywindow.cpp | 4 +--- apps/openmw/mwgui/loadingscreen.cpp | 2 -- apps/openmw/mwgui/mainmenu.cpp | 4 ---- apps/openmw/mwgui/mapwindow.cpp | 1 - apps/openmw/mwgui/pickpocketitemmodel.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 5 +---- apps/openmw/mwgui/recharge.cpp | 2 -- apps/openmw/mwgui/spellbuyingwindow.cpp | 1 - apps/openmw/mwgui/tradewindow.cpp | 1 - apps/openmw/mwgui/windowmanagerimp.cpp | 3 +-- apps/openmw/mwmechanics/actors.cpp | 4 +--- 19 files changed, 7 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 1122a4069..de8614004 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/companionitemmodel.cpp b/apps/openmw/mwgui/companionitemmodel.cpp index 983ef5017..0ff0b648e 100644 --- a/apps/openmw/mwgui/companionitemmodel.cpp +++ b/apps/openmw/mwgui/companionitemmodel.cpp @@ -1,6 +1,5 @@ #include "companionitemmodel.hpp" -#include "../mwmechanics/npcstats.hpp" #include "../mwworld/class.hpp" namespace diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index b61d46400..fc4a98489 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -3,11 +3,8 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwmechanics/npcstats.hpp" - #include "../mwworld/class.hpp" #include "messagebox.hpp" diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 2f874119d..b2cc09b43 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -11,13 +11,11 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/containerstore.hpp" #include "../mwmechanics/pickpocket.hpp" #include "../mwmechanics/creaturestats.hpp" #include "countdialog.hpp" -#include "tradewindow.hpp" #include "inventorywindow.hpp" #include "itemview.hpp" diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 0cb0475c9..ce33a74dd 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -16,12 +16,12 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/dialoguemanager.hpp" -#include "../mwmechanics/npcstats.hpp" - #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwmechanics/creaturestats.hpp" + #include "widgets.hpp" #include "bookpage.hpp" diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 43f2493a9..61a935a6f 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 0f107f4e3..7307e6f87 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -10,7 +10,6 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index e8354b740..b80850ba1 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -4,8 +4,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwmechanics/creaturestats.hpp" - namespace MWGui { diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 39f476403..9c9138ed5 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -16,19 +16,17 @@ #include -#include - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/scriptmanager.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/action.hpp" #include "../mwscript/interpretercontext.hpp" -#include "../mwbase/scriptmanager.hpp" #include "../mwrender/characterpreview.hpp" #include "itemview.hpp" diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 7e733686d..9b99ad7bf 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -17,9 +17,7 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/statemanager.hpp" - #include "../mwbase/windowmanager.hpp" #include "../mwbase/inputmanager.hpp" diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 409306986..258f0dfb0 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -12,12 +12,8 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/journal.hpp" -#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/statemanager.hpp" -#include "../mwstate/character.hpp" - #include "savegamedialog.hpp" #include "confirmationdialog.hpp" #include "backgroundimage.hpp" diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 2485f3c94..d564dfcbc 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -27,7 +27,6 @@ #include "../mwrender/globalmap.hpp" #include "../mwrender/localmap.hpp" -#include "widgets.hpp" #include "confirmationdialog.hpp" #include "tooltips.hpp" diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index a0550ae25..ab0d02f95 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -1,8 +1,8 @@ #include "pickpocketitemmodel.hpp" #include +#include -#include "../mwmechanics/npcstats.hpp" #include "../mwworld/class.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 8c919e8bd..3f896bae2 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -15,18 +15,15 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwgui/inventorywindow.hpp" -#include "windowmanagerimp.hpp" #include "itemselection.hpp" - #include "spellview.hpp" - - #include "itemwidget.hpp" #include "sortfilteritemmodel.hpp" diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 76961af5d..69c5c61c4 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -7,8 +7,6 @@ #include -#include - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index ae7b7588a..61dd599e7 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -12,7 +12,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 1c5dc4632..0ae661eb3 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -15,7 +15,6 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" -#include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 44eed6623..31eef5c01 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -45,6 +45,7 @@ #include "../mwbase/inputmanager.hpp" #include "../mwbase/statemanager.hpp" +#include "../mwbase/soundmanager.hpp" #include "../mwrender/vismask.hpp" @@ -58,8 +59,6 @@ #include "../mwrender/localmap.hpp" -#include "../mwsound/soundmanagerimp.hpp" - #include "console.hpp" #include "journalwindow.hpp" #include "journalviewmodel.hpp" diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d9a8ce72f..d436eca31 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -7,12 +7,10 @@ #include #include #include -#include #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwworld/manualref.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/player.hpp" @@ -22,7 +20,7 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwrender/animation.hpp" +#include "../mwmechanics/spellcasting.hpp" #include "npcstats.hpp" #include "creaturestats.hpp" From 278a078e9d39340fbf907ba156931b00bf0c0376 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 18 Jul 2015 20:39:45 +0200 Subject: [PATCH 110/419] Unify magic effect tick functions - Removes duplicated code - Handle some zero-duration instant effects that were not handled before (disintegrate, sun damage, elemental damage) --- apps/openmw/mwbase/mechanicsmanager.hpp | 5 + apps/openmw/mwclass/npc.cpp | 7 +- apps/openmw/mwmechanics/actors.cpp | 165 ++----------- .../mwmechanics/mechanicsmanagerimp.cpp | 21 ++ .../mwmechanics/mechanicsmanagerimp.hpp | 5 + apps/openmw/mwmechanics/spellcasting.cpp | 228 ++++++++++++++---- apps/openmw/mwmechanics/spellcasting.hpp | 3 + 7 files changed, 229 insertions(+), 205 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index b66e60e1d..2c4a22c07 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -129,6 +129,11 @@ namespace MWBase OffenseType type, int arg=0, bool victimAware=false) = 0; /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0; + + /// Notify that actor was killed, add a murder bounty if applicable + /// @note No-op for non-player attackers + virtual void actorKilled (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0; + /// Utility to check if taking this item is illegal and calling commitCrime if so /// @param container The container the item is in; may be empty for an item in the world virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c7b407fb8..d0dd9f994 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -751,12 +751,7 @@ namespace MWClass attacker.getClass().getNpcStats(attacker).addWerewolfKill(); } - // Simple check for who attacked first: if the player attacked first, a crimeId should be set - // Doesn't handle possible edge case where no one reported the assault, but in such a case, - // for bystanders it is not possible to tell who attacked first, anyway. - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - if (attacker == player && ptr.getClass().getNpcStats(ptr).getCrimeId() != -1 && ptr != player) - MWBase::Environment::get().getMechanicsManager()->commitCrime(player, ptr, MWBase::MechanicsManager::OT_Murder); + MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, attacker); } } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d436eca31..4a08176d1 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -67,44 +67,6 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a } } -bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate) -{ - if (ptr.getClass().hasInventoryStore(ptr)) - { - MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr); - MWWorld::ContainerStoreIterator item = - inv.getSlot(slot); - if (item != inv.end()) - { - if (!item->getClass().hasItemHealth(*item)) - return false; - int charge = item->getClass().getItemHealth(*item); - - if (charge == 0) - return false; - - // FIXME: charge should be a float, not int so that damage < 1 per frame can be applied. - // This was also a bug in the original engine. - charge -= - std::min(static_cast(disintegrate), - charge); - item->getCellRef().setCharge(charge); - - if (charge == 0) - { - // Will unequip the broken item and try to find a replacement - if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) - inv.autoEquip(ptr); - else - inv.unequipItem(*item, ptr); - } - - return true; - } - } - return false; -} - class CheckActorCommanded : public MWMechanics::EffectSourceVisitor { MWWorld::Ptr mActor; @@ -516,8 +478,12 @@ namespace MWMechanics bool wasDead = creatureStats.isDead(); - // FIXME: effect ticks should go into separate functions so they can be used with either - // magnitude (instant effect) or magnitude*duration + // tickable effects (i.e. effects having a lasting impact after expiry) + // these effects can be applied as "instant" (handled in spellcasting.cpp) or with a duration, handled here + for (MagicEffects::Collection::const_iterator it = effects.begin(); it != effects.end(); ++it) + { + effectTick(creatureStats, ptr, it->first, it->second.getMagnitude() * duration); + } // attributes for(int i = 0;i < ESM::Attribute::Length;++i) @@ -527,9 +493,6 @@ namespace MWMechanics effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude())); - stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration); - stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration); - creatureStats.setAttribute(i, stat); } @@ -559,12 +522,6 @@ namespace MWMechanics // Fatigue can be decreased below zero meaning the actor will be knocked out i == 2); - - float currentDiff = creatureStats.getMagicEffects().get(ESM::MagicEffect::RestoreHealth+i).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::DamageHealth+i).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::AbsorbHealth+i).getMagnitude(); - stat.setCurrent(stat.getCurrent() + currentDiff * duration, i == 2); - creatureStats.setDynamic(i, stat); } @@ -592,90 +549,11 @@ namespace MWMechanics creatureStats.setAiSetting(CreatureStats::AI_Flee, stat); } - // Apply disintegration (reduces item health) - float disintegrateWeapon = effects.get(ESM::MagicEffect::DisintegrateWeapon).getMagnitude(); - if (disintegrateWeapon > 0) - disintegrateSlot(ptr, MWWorld::InventoryStore::Slot_CarriedRight, disintegrateWeapon*duration); - float disintegrateArmor = effects.get(ESM::MagicEffect::DisintegrateArmor).getMagnitude(); - if (disintegrateArmor > 0) - { - // According to UESP - int priorities[] = { - MWWorld::InventoryStore::Slot_CarriedLeft, - MWWorld::InventoryStore::Slot_Cuirass, - MWWorld::InventoryStore::Slot_LeftPauldron, - MWWorld::InventoryStore::Slot_RightPauldron, - MWWorld::InventoryStore::Slot_LeftGauntlet, - MWWorld::InventoryStore::Slot_RightGauntlet, - MWWorld::InventoryStore::Slot_Helmet, - MWWorld::InventoryStore::Slot_Greaves, - MWWorld::InventoryStore::Slot_Boots - }; - - for (unsigned int i=0; i 0.0f - || creatureStats.getMagicEffects().get(ESM::MagicEffect::AbsorbHealth).getMagnitude() > 0.0f) - receivedMagicDamage = true; - - // Apply damage ticks - int damageEffects[] = { - ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison, - ESM::MagicEffect::SunDamage - }; - - DynamicStat health = creatureStats.getHealth(); - for (unsigned int i=0; iisExterior()) - continue; - float time = MWBase::Environment::get().getWorld()->getTimeStamp().getHour(); - float timeDiff = std::min(7.f, std::max(0.f, std::abs(time - 13))); - float damageScale = 1.f - timeDiff / 7.f; - // When cloudy, the sun damage effect is halved - static float fMagicSunBlockedMult = MWBase::Environment::get().getWorld()->getStore().get().find( - "fMagicSunBlockedMult")->getFloat(); - - int weather = MWBase::Environment::get().getWorld()->getCurrentWeather(); - if (weather > 1) - damageScale *= fMagicSunBlockedMult; - health.setCurrent(health.getCurrent() - magnitude * duration * damageScale); - - if (magnitude * damageScale > 0.0f) - receivedMagicDamage = true; - } - else - { - health.setCurrent(health.getCurrent() - magnitude * duration); - - if (magnitude > 0.0f) - receivedMagicDamage = true; - } - } - - if (receivedMagicDamage && ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) - MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); - - creatureStats.setHealth(health); - if (!wasDead && creatureStats.isDead()) { // The actor was killed by a magic effect. Figure out if the player was responsible for it. const ActiveSpells& spells = creatureStats.getActiveSpells(); bool killedByPlayer = false; - bool murderedByPlayer = false; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); for (ActiveSpells::TIterator it = spells.begin(); it != spells.end(); ++it) { @@ -685,33 +563,29 @@ namespace MWMechanics { int effectId = effectIt->mEffectId; bool isDamageEffect = false; + + int damageEffects[] = { + ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison, + ESM::MagicEffect::SunDamage, ESM::MagicEffect::DamageHealth, ESM::MagicEffect::AbsorbHealth + }; + for (unsigned int i=0; isearchPtrViaActorId(spell.mCasterActorId); if (isDamageEffect && caster == player) - { killedByPlayer = true; - // Simple check for who attacked first: if the player attacked first, a crimeId should be set - // Doesn't handle possible edge case where no one reported the assault, but in such a case, - // for bystanders it is not possible to tell who attacked first, anyway. - if (ptr.getClass().isNpc() && ptr.getClass().getNpcStats(ptr).getCrimeId() != -1 - && ptr != player) - murderedByPlayer = true; - } } } - if (murderedByPlayer) - MWBase::Environment::get().getMechanicsManager()->commitCrime(player, ptr, MWBase::MechanicsManager::OT_Murder); - if (killedByPlayer && player.getClass().getNpcStats(player).isWerewolf()) - player.getClass().getNpcStats(player).addWerewolfKill(); + if (killedByPlayer) + { + MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, player); + if (player.getClass().getNpcStats(player).isWerewolf()) + player.getClass().getNpcStats(player).addWerewolfKill(); + } } // TODO: dirty flag for magic effects to avoid some unnecessary work below? @@ -795,9 +669,6 @@ namespace MWMechanics skill.setModifier(static_cast(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude())); - - skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration); - skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration); } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index fef99dc61..e9ef99454 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1330,6 +1330,27 @@ namespace MWMechanics return true; } + void MechanicsManager::actorKilled(const MWWorld::Ptr &victim, const MWWorld::Ptr &attacker) + { + if (attacker.isEmpty() || attacker != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + + if (victim == attacker) + return; // known to happen + + if (!victim.getClass().isNpc()) + return; // TODO: implement animal rights + + const MWMechanics::NpcStats& victimStats = victim.getClass().getNpcStats(victim); + + // Simple check for who attacked first: if the player attacked first, a crimeId should be set + // Doesn't handle possible edge case where no one reported the assault, but in such a case, + // for bystanders it is not possible to tell who attacked first, anyway. + if (victimStats.getCrimeId() != -1) + MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, victim, MWBase::MechanicsManager::OT_Murder); + + } + bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer) { if (observer.getClass().getCreatureStats(observer).isDead() || !observer.getRefData().isEnabled()) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 392d7fbbe..6386b4a2a 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -120,6 +120,11 @@ namespace MWMechanics OffenseType type, int arg=0, bool victimAware=false); /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker); + + /// Notify that actor was killed, add a murder bounty if applicable + /// @note No-op for non-player attackers + virtual void actorKilled (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker); + /// Utility to check if taking this item is illegal and calling commitCrime if so /// @param container The container the item is in; may be empty for an item in the world virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index a47da7bf4..1613300d7 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -19,6 +19,8 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/inventorystore.hpp" + #include "../mwrender/animation.hpp" #include "magiceffects.hpp" @@ -65,57 +67,6 @@ namespace target.getClass().getCreatureStats(target).setDynamic(attribute, value); } - // TODO: refactor the effect tick functions in Actors so they can be reused here - void applyInstantEffectTick(MWMechanics::EffectKey effect, const MWWorld::Ptr& target, float magnitude) - { - int effectId = effect.mId; - if (effectId == ESM::MagicEffect::DamageHealth) - { - applyDynamicStatsEffect(0, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreHealth) - { - applyDynamicStatsEffect(0, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageFatigue) - { - applyDynamicStatsEffect(2, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreFatigue) - { - applyDynamicStatsEffect(2, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageMagicka) - { - applyDynamicStatsEffect(1, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreMagicka) - { - applyDynamicStatsEffect(1, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute) - { - int attribute = effect.mArg; - MWMechanics::AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute); - if (effectId == ESM::MagicEffect::DamageAttribute) - value.damage(magnitude); - else - value.restore(magnitude); - target.getClass().getCreatureStats(target).setAttribute(attribute, value); - } - else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) - { - if (target.getTypeName() != typeid(ESM::NPC).name()) - return; - int skill = effect.mArg; - MWMechanics::SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill); - if (effectId == ESM::MagicEffect::DamageSkill) - value.damage(magnitude); - else - value.restore(magnitude); - } - } - } namespace MWMechanics @@ -530,7 +481,14 @@ namespace MWMechanics else { if (hasDuration && target.getClass().isActor()) - applyInstantEffectTick(EffectKey(*effectIt), target, magnitude); + { + bool wasDead = target.getClass().getCreatureStats(target).isDead(); + effectTick(target.getClass().getCreatureStats(target), target, EffectKey(*effectIt), magnitude); + bool isDead = target.getClass().getCreatureStats(target).isDead(); + + if (!wasDead && isDead) + MWBase::Environment::get().getMechanicsManager()->actorKilled(target, caster); + } else applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); } @@ -960,4 +918,170 @@ namespace MWMechanics || (effectId >= ESM::MagicEffect::SummonFabricant && effectId <= ESM::MagicEffect::SummonCreature05)); } + + bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate) + { + if (ptr.getClass().hasInventoryStore(ptr)) + { + MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr); + MWWorld::ContainerStoreIterator item = + inv.getSlot(slot); + if (item != inv.end()) + { + if (!item->getClass().hasItemHealth(*item)) + return false; + int charge = item->getClass().getItemHealth(*item); + + if (charge == 0) + return false; + + // FIXME: charge should be a float, not int so that damage < 1 per frame can be applied. + // This was also a bug in the original engine. + charge -= + std::min(static_cast(disintegrate), + charge); + item->getCellRef().setCharge(charge); + + if (charge == 0) + { + // Will unequip the broken item and try to find a replacement + if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + inv.autoEquip(ptr); + else + inv.unequipItem(*item, ptr); + } + + return true; + } + } + return false; + } + + void adjustDynamicStat(CreatureStats& creatureStats, int index, float magnitude) + { + DynamicStat stat = creatureStats.getDynamic(index); + stat.setCurrent(stat.getCurrent() + magnitude, index == 2); + creatureStats.setDynamic(index, stat); + } + + void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey &effectKey, float magnitude) + { + if (magnitude == 0.f) + return; + + bool receivedMagicDamage = false; + + switch (effectKey.mId) + { + case ESM::MagicEffect::DamageAttribute: + { + AttributeValue attr = creatureStats.getAttribute(effectKey.mArg); + attr.damage(magnitude); + creatureStats.setAttribute(effectKey.mArg, attr); + break; + } + case ESM::MagicEffect::RestoreAttribute: + { + AttributeValue attr = creatureStats.getAttribute(effectKey.mArg); + attr.restore(magnitude); + creatureStats.setAttribute(effectKey.mArg, attr); + break; + } + case ESM::MagicEffect::RestoreHealth: + case ESM::MagicEffect::RestoreMagicka: + case ESM::MagicEffect::RestoreFatigue: + adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::RestoreHealth, magnitude); + break; + case ESM::MagicEffect::DamageHealth: + case ESM::MagicEffect::DamageMagicka: + case ESM::MagicEffect::DamageFatigue: + receivedMagicDamage = true; + adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude); + break; + case ESM::MagicEffect::AbsorbHealth: + case ESM::MagicEffect::AbsorbMagicka: + case ESM::MagicEffect::AbsorbFatigue: + if (magnitude > 0.f) + receivedMagicDamage = true; + adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude); + break; + + case ESM::MagicEffect::DisintegrateArmor: + { + // According to UESP + int priorities[] = { + MWWorld::InventoryStore::Slot_CarriedLeft, + MWWorld::InventoryStore::Slot_Cuirass, + MWWorld::InventoryStore::Slot_LeftPauldron, + MWWorld::InventoryStore::Slot_RightPauldron, + MWWorld::InventoryStore::Slot_LeftGauntlet, + MWWorld::InventoryStore::Slot_RightGauntlet, + MWWorld::InventoryStore::Slot_Helmet, + MWWorld::InventoryStore::Slot_Greaves, + MWWorld::InventoryStore::Slot_Boots + }; + + for (unsigned int i=0; iisExterior()) + break; + float time = MWBase::Environment::get().getWorld()->getTimeStamp().getHour(); + float timeDiff = std::min(7.f, std::max(0.f, std::abs(time - 13))); + float damageScale = 1.f - timeDiff / 7.f; + // When cloudy, the sun damage effect is halved + static float fMagicSunBlockedMult = MWBase::Environment::get().getWorld()->getStore().get().find( + "fMagicSunBlockedMult")->getFloat(); + + int weather = MWBase::Environment::get().getWorld()->getCurrentWeather(); + if (weather > 1) + damageScale *= fMagicSunBlockedMult; + + adjustDynamicStat(creatureStats, 0, -magnitude * damageScale); + if (magnitude * damageScale > 0.f) + receivedMagicDamage = true; + break; + } + + case ESM::MagicEffect::FireDamage: + case ESM::MagicEffect::ShockDamage: + case ESM::MagicEffect::FrostDamage: + case ESM::MagicEffect::Poison: + { + adjustDynamicStat(creatureStats, 0, -magnitude); + receivedMagicDamage = true; + break; + } + + case ESM::MagicEffect::DamageSkill: + case ESM::MagicEffect::RestoreSkill: + { + if (!actor.getClass().isNpc()) + break; + NpcStats &npcStats = actor.getClass().getNpcStats(actor); + SkillValue& skill = npcStats.getSkill(effectKey.mArg); + if (effectKey.mId == ESM::MagicEffect::RestoreSkill) + skill.restore(magnitude); + else + skill.damage(magnitude); + break; + } + + } + + if (receivedMagicDamage && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); + } + } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 2540b87db..418e9f56d 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -17,6 +17,7 @@ namespace MWMechanics { struct EffectKey; class MagicEffects; + class CreatureStats; ESM::Skill::SkillEnum spellSchoolToSkill(int school); @@ -60,6 +61,8 @@ namespace MWMechanics int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor); + void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude); + class CastSpell { private: From cbc44b33ba01ae4aa4eac7386fcde048b7eeb613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Sat, 18 Jul 2015 21:29:38 +0200 Subject: [PATCH 111/419] define crosshair owned colour in openmw_hud_box.skin.xml --- AUTHORS.md | 2 +- apps/openmw/mwgui/hud.cpp | 6 ++---- apps/openmw/mwgui/tooltips.cpp | 2 +- files/mygui/openmw_hud.layout | 3 +-- files/mygui/openmw_hud_box.skin.xml | 19 +++++++++++++++++-- files/mygui/openmw_windows.skin.xml | 5 +++-- 6 files changed, 25 insertions(+), 12 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index 7774b5afa..2bd96e3a1 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -52,6 +52,7 @@ Programmers jeaye Jeffrey Haines (Jyby) Jengerer + Jiří KuneÅ¡ (kunesj) Joel Graff (graffy) John Blomberg (fstp) Jordan Ayers @@ -59,7 +60,6 @@ Programmers Julien Voisin (jvoisin/ap0) Karl-Felix Glatzer (k1ll) Kevin Poitra (PuppyKevin) - kunesj Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 0f107f4e3..c8d8b61d5 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -521,15 +521,13 @@ namespace MWGui void HUD::setCrosshairOwned(bool owned) { - MyGUI::Colour red = MyGUI::Colour(1.0, 0, 0); - MyGUI::Colour white = MyGUI::Colour(1.0, 1.0, 1.0); if(owned) { - mCrosshair->setColour(red); + mCrosshair->changeWidgetSkin("HUD_Crosshair_Owned"); } else { - mCrosshair->setColour(white); + mCrosshair->changeWidgetSkin("HUD_Crosshair"); } } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index a51c68acf..dbf27ad91 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -377,7 +377,7 @@ namespace MWGui { if(checkOwned()) { - mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_R"); + mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_Owned"); } else { diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index dd114097e..97b018469 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -122,8 +122,7 @@ - - + diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index 7019351bd..dfe717c6f 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -32,16 +32,31 @@ - + - + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 47f8cada8..c9a1f1ccc 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -129,9 +129,10 @@ - - + + + From a5b4e087c56518c6e0a75413f9c7f5cfa9f377a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Sat, 18 Jul 2015 22:17:46 +0200 Subject: [PATCH 112/419] define owned colours in settings.cfg --- apps/openmw/mwgui/windowmanagerimp.cpp | 15 +++++++++++++-- files/mygui/openmw_hud_box.skin.xml | 2 +- files/mygui/openmw_windows.skin.xml | 3 +-- files/settings-default.cfg | 4 ++++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7b618efa7..0fe71632a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1095,11 +1095,22 @@ namespace MWGui void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result) { std::string tag(_tag); + + std::string MyGuiPrefix = "setting="; + size_t MyGuiPrefixLength = MyGuiPrefix.length(); std::string tokenToFind = "sCell="; size_t tokenLength = tokenToFind.length(); - - if (tag.compare(0, tokenLength, tokenToFind) == 0) + + if(tag.compare(0, MyGuiPrefixLength, MyGuiPrefix) == 0) + { + tag = tag.substr(MyGuiPrefixLength, tag.length()); + std::string settingSection = tag.substr(0, tag.find(",")); + std::string settingTag = tag.substr(tag.find(",")+1, tag.length()); + + _result = Settings::Manager::getString(settingTag, settingSection); + } + else if (tag.compare(0, tokenLength, tokenToFind) == 0) { _result = mTranslationDataStorage.translateCellName(tag.substr(tokenLength)); } diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index dfe717c6f..33199d6ae 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -53,7 +53,7 @@ - + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index c9a1f1ccc..682d89ebc 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -131,8 +131,7 @@ - - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index d84291a24..dcb9b8893 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -36,6 +36,10 @@ werewolf overlay = true stretch menu background = false +# colour definitions (red green blue alpha) +color background owned = 0.15 0 0 1 +color crosshair owned = 1 0.15 0.15 1 + [General] # Camera field of view field of view = 55 From 115666884308dca010d2ce60c8e40b25d0b88e9a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Jul 2015 00:45:02 +0200 Subject: [PATCH 113/419] Render certain map markers on top of the player arrow (Fixes #2559) --- apps/openmw/mwgui/mapwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index d564dfcbc..e26c076e7 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -37,8 +37,8 @@ namespace enum LocalMapWidgetDepth { - Local_CompassLayer = 0, - Local_MarkerAboveFogLayer = 1, + Local_MarkerAboveFogLayer = 0, + Local_CompassLayer = 1, Local_FogLayer = 2, Local_MarkerLayer = 3, Local_MapLayer = 4 From b01abe4d19c32e15945c9193c032ca7a141f8df8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Jul 2015 02:08:24 +0200 Subject: [PATCH 114/419] Stop title music when the game starts (Fixes #2468) --- apps/openmw/engine.cpp | 3 --- apps/openmw/mwmechanics/actors.cpp | 10 +++++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 001ce2750..8d25a923f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -646,9 +646,6 @@ void OMW::Engine::go() prepareEngine (settings); - // Play some good 'ol tunes - MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); - if (!mSaveGameFile.empty()) { MWBase::Environment::get().getStateManager()->loadGame(mSaveGameFile); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d9a8ce72f..ee3f4b8f4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1200,18 +1200,18 @@ namespace MWMechanics killDeadActors(); // check if we still have any player enemies to switch music - static bool isBattleMusic = false; + static int currentMusic = 0; - if (isBattleMusic && hostilesCount == 0 && !(player.getClass().getCreatureStats(player).isDead() && + if (currentMusic != 1 && hostilesCount == 0 && !(player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getSoundManager()->isMusicPlaying())) { MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); - isBattleMusic = false; + currentMusic = 1; } - else if (!isBattleMusic && hostilesCount > 0) + else if (currentMusic != 2 && hostilesCount > 0) { MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle")); - isBattleMusic = true; + currentMusic = 2; } static float sneakTimer = 0.f; // times update of sneak icon From 3ebe9fb34f99c59979adbb68df1d6621e5d9b931 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 19 Jul 2015 18:00:49 +1200 Subject: [PATCH 115/419] renamed mRotate to mTurnActorGivingGreetingToFacePlayer --- apps/openmw/mwmechanics/aiwander.cpp | 32 ++++++++++++++-------------- apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 1375b5807..43fd67be1 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -51,10 +51,10 @@ namespace MWMechanics /// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive. struct AiWanderStorage : AiTemporaryBase { - // the z rotation angle (degrees) we want to reach - // used every frame when mRotate is true + // the z rotation angle to reach + // when mTurnActorGivingGreetingToFacePlayer is true float mTargetAngleRadians; - bool mRotate; + bool mTurnActorGivingGreetingToFacePlayer; float mReaction; // update some actions infrequently @@ -75,7 +75,7 @@ namespace MWMechanics AiWanderStorage(): mTargetAngleRadians(0), - mRotate(false), + mTurnActorGivingGreetingToFacePlayer(false), mReaction(0), mSaidGreeting(AiWander::Greet_None), mGreetingTimer(0), @@ -240,15 +240,13 @@ namespace MWMechanics evadeObstacles(actor, storage, duration); } - - float& targetAngleRadians = storage.mTargetAngleRadians; - bool& rotate = storage.mRotate; + bool& rotate = storage.mTurnActorGivingGreetingToFacePlayer; if (rotate) { // Reduce the turning animation glitch by using a *HUGE* value of // epsilon... TODO: a proper fix might be in either the physics or the // animation subsystem - if (zTurn(actor, targetAngleRadians, osg::DegreesToRadians(5.f))) + if (zTurn(actor, storage.mTargetAngleRadians, osg::DegreesToRadians(5.f))) rotate = false; } @@ -491,14 +489,7 @@ namespace MWMechanics getRandomIdle(storage.mPlayedIdle); } - if (!storage.mRotate) - { - osg::Vec3f dir = playerPos - actorPos; - - float faceAngleRadians = std::atan2(dir.x(), dir.y()); - storage.mTargetAngleRadians = faceAngleRadians; - storage.mRotate = true; - } + turnActorToFacePlayer(actorPos, playerPos, storage); if (greetingTimer >= GREETING_SHOULD_END) { @@ -515,6 +506,15 @@ namespace MWMechanics } } + void AiWander::turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage) + { + osg::Vec3f dir = playerPosition - actorPosition; + + float faceAngleRadians = std::atan2(dir.x(), dir.y()); + storage.mTargetAngleRadians = faceAngleRadians; + storage.mTurnActorGivingGreetingToFacePlayer = true; + } + void AiWander::setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos) { unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size()); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 82baeedf3..d06887600 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -75,6 +75,7 @@ namespace MWMechanics void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); void playIdleDialogueRandomly(const MWWorld::Ptr& actor); + void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 1ed6e95c07d4eab8fb2e95eb980215695710ab64 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 19 Jul 2015 18:01:25 +1200 Subject: [PATCH 116/419] Got rid of some radians to degrees to radians conversions. --- apps/openmw/mwmechanics/aicombat.cpp | 8 ++++---- apps/openmw/mwmechanics/aipackage.cpp | 4 ++-- apps/openmw/mwmechanics/aiwander.cpp | 4 ++-- apps/openmw/mwmechanics/pathfinding.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.hpp | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 4eeea6f1f..6a39178ce 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -36,13 +36,13 @@ namespace float getZAngleToDir(const osg::Vec3f& dir) { - return osg::RadiansToDegrees(std::atan2(dir.x(), dir.y())); + return std::atan2(dir.x(), dir.y()); } float getXAngleToDir(const osg::Vec3f& dir, float dirLen = 0.0f) { float len = (dirLen > 0.0f)? dirLen : dir.length(); - return osg::RadiansToDegrees(-std::asin(dir.z() / len)); + return -std::asin(dir.z() / len); } @@ -221,12 +221,12 @@ namespace MWMechanics if(movement.mRotation[2] != 0) { - if(zTurn(actor, osg::DegreesToRadians(movement.mRotation[2]))) movement.mRotation[2] = 0; + if(zTurn(actor, movement.mRotation[2])) movement.mRotation[2] = 0; } if(movement.mRotation[0] != 0) { - if(smoothTurn(actor, osg::DegreesToRadians(movement.mRotation[0]), 0)) movement.mRotation[0] = 0; + if(smoothTurn(actor, movement.mRotation[0], 0)) movement.mRotation[0] = 0; } bool& attack = storage.mAttack; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 22c907588..0e68d9d79 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -104,7 +104,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po actor.getClass().getMovementSettings(actor).mPosition[0] = 1; actor.getClass().getMovementSettings(actor).mPosition[1] = 1; // change the angle a bit, too - zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); + zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])); } } else { //Not stuck, so reset things @@ -117,7 +117,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward the rest of the time } - zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); + zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); return false; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 43fd67be1..9f50d07b4 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -234,7 +234,7 @@ namespace MWMechanics if(walking) // have not yet reached the destination { // turn towards the next point in mPath - zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); + zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); actor.getClass().getMovementSettings(actor).mPosition[1] = 1; evadeObstacles(actor, storage, duration); @@ -397,7 +397,7 @@ namespace MWMechanics actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; // change the angle a bit, too const ESM::Position& pos = actor.getRefData().getPosition(); - zTurn(actor, osg::DegreesToRadians(storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); + zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])); } mStuckCount++; // TODO: maybe no longer needed } diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 3c1a40fe0..79cee9f32 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -264,7 +264,7 @@ namespace MWMechanics float directionX = nextPoint.mX - x; float directionY = nextPoint.mY - y; - return osg::RadiansToDegrees(std::atan2(directionX, directionY)); + return std::atan2(directionX, directionY); } bool PathFinder::checkPathCompleted(float x, float y, float tolerance) diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index a4886a840..4000f5d80 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -40,7 +40,7 @@ namespace MWMechanics bool checkPathCompleted(float x, float y, float tolerance = PathTolerance); ///< \Returns true if we are within \a tolerance units of the last path point. - /// In degrees + /// In radians float getZAngleToNext(float x, float y) const; bool isPathConstructed() const From 22f49128ccb2a6e12a36fb31f992155a6a967c38 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 19 Jul 2015 18:02:13 +1200 Subject: [PATCH 117/419] replaced multiple booleans with single state variable. --- apps/openmw/mwmechanics/aiwander.cpp | 65 ++++++++++------------------ apps/openmw/mwmechanics/aiwander.hpp | 7 +++ 2 files changed, 29 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 9f50d07b4..fc730cc89 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -64,10 +64,7 @@ namespace MWMechanics const MWWorld::CellStore* mCell; // for detecting cell change // AiWander states - bool mChooseAction; - bool mIdleNow; - bool mMoveNow; - bool mWalking; + AiWander::WanderState mState; unsigned short mPlayedIdle; @@ -80,10 +77,7 @@ namespace MWMechanics mSaidGreeting(AiWander::Greet_None), mGreetingTimer(0), mCell(NULL), - mChooseAction(true), - mIdleNow(false), - mMoveNow(false), - mWalking(false), + mState(AiWander::Wander_ChooseAction), mPlayedIdle(0) {}; }; @@ -200,38 +194,33 @@ namespace MWMechanics ESM::Position pos = actor.getRefData().getPosition(); - bool& idleNow = storage.mIdleNow; - bool& moveNow = storage.mMoveNow; - bool& walking = storage.mWalking; + WanderState& wanderState = storage.mState; // Check if an idle actor is too close to a door - if so start walking mDoorCheckDuration += duration; if(mDoorCheckDuration >= DOOR_CHECK_INTERVAL) { mDoorCheckDuration = 0; // restart timer if(mDistance && // actor is not intended to be stationary - idleNow && // but is in idle - !walking && // FIXME: some actors are idle while walking + (wanderState == Wander_IdleNow) && // but is in idle proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only { - idleNow = false; - moveNow = true; + wanderState = Wander_MoveNow; mTrimCurrentNode = false; // just in case } } // Are we there yet? - bool& chooseAction = storage.mChooseAction; - if(walking && + if ((wanderState == Wander_Walking) && storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) { stopWalking(actor, storage); - chooseAction = true; + wanderState = Wander_ChooseAction; mHasReturnPosition = false; } - if(walking) // have not yet reached the destination + if (wanderState == Wander_Walking) // have not yet reached the destination { // turn towards the next point in mPath zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); @@ -253,24 +242,23 @@ namespace MWMechanics // Check if idle animation finished short unsigned& playedIdle = storage.mPlayedIdle; GreetingState& greetingState = storage.mSaidGreeting; - if(idleNow && !checkIdle(actor, playedIdle) && (greetingState == Greet_Done || greetingState == Greet_None)) + if ((wanderState == Wander_IdleNow) && + !checkIdle(actor, playedIdle) && (greetingState == Greet_Done || greetingState == Greet_None)) { playedIdle = 0; - idleNow = false; - chooseAction = true; + wanderState = Wander_ChooseAction; } MWBase::World *world = MWBase::Environment::get().getWorld(); - if(chooseAction) + if (wanderState == Wander_ChooseAction) { playedIdle = 0; getRandomIdle(playedIdle); // NOTE: sets mPlayedIdle with a random selection if(!playedIdle && mDistance) { - chooseAction = false; - moveNow = true; + wanderState = Wander_MoveNow; } else { @@ -278,8 +266,7 @@ namespace MWMechanics MWWorld::TimeStamp currentTime = world->getTimeStamp(); mStartTime = currentTime; playIdle(actor, playedIdle); - chooseAction = false; - idleNow = true; + wanderState = Wander_IdleNow; } } @@ -332,9 +319,6 @@ namespace MWMechanics mHasReturnPosition = false; if (mDistance == 0 && mHasReturnPosition && (pos.asVec3() - mReturnPosition).length2() > 20*20) { - chooseAction = false; - idleNow = false; - if (!storage.mPathFinder.isPathConstructed()) { ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition)); @@ -347,19 +331,18 @@ namespace MWMechanics if(storage.mPathFinder.isPathConstructed()) { - moveNow = false; - walking = true; + wanderState = Wander_Walking; } } } // Allow interrupting a walking actor to trigger a greeting - if(idleNow || walking) + if ((wanderState == Wander_IdleNow) || (wanderState == Wander_Walking)) { playGreetingIfPlayerGetsTooClose(actor, storage); } - if(moveNow && mDistance) + if ((wanderState == Wander_MoveNow) && mDistance) { // Construct a new path if there isn't one if(!storage.mPathFinder.isPathConstructed()) @@ -386,8 +369,7 @@ namespace MWMechanics trimAllowedNodes(mAllowedNodes, storage.mPathFinder); mObstacleCheck.clear(); storage.mPathFinder.clearPath(); - storage.mWalking = false; - storage.mMoveNow = true; + storage.mState = Wander_MoveNow; } else // probably walking into another NPC { @@ -409,7 +391,7 @@ namespace MWMechanics mObstacleCheck.clear(); stopWalking(actor, storage); - storage.mChooseAction = true; + storage.mState = Wander_ChooseAction; mStuckCount = 0; } //#endif @@ -481,11 +463,11 @@ namespace MWMechanics { greetingTimer++; - if (storage.mWalking) + if (storage.mState == Wander_Walking) { stopWalking(actor, storage); mObstacleCheck.clear(); - storage.mIdleNow = true; + storage.mState = Wander_IdleNow; getRandomIdle(storage.mPlayedIdle); } @@ -539,8 +521,7 @@ namespace MWMechanics mAllowedNodes.push_back(mCurrentNode); mCurrentNode = temp; - storage.mMoveNow = false; - storage.mWalking = true; + storage.mState = Wander_Walking; } // Choose a different node and delete this one from possible nodes because it is uncreachable: else @@ -591,8 +572,6 @@ namespace MWMechanics { storage.mPathFinder.clearPath(); actor.getClass().getMovementSettings(actor).mPosition[1] = 0; - storage.mMoveNow = false; - storage.mWalking = false; } void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index d06887600..8a4921b83 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -63,6 +63,13 @@ namespace MWMechanics Greet_InProgress, Greet_Done }; + + enum WanderState { + Wander_ChooseAction, + Wander_IdleNow, + Wander_MoveNow, + Wander_Walking, + }; private: // NOTE: mDistance and mDuration must be set already void init(); From 00eef585afde4b0a2ef532a06a82938d7cc1d43c Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 19 Jul 2015 18:04:42 +1200 Subject: [PATCH 118/419] renamed mPlayedIdle to mIdleAnimation. --- apps/openmw/mwmechanics/aiwander.cpp | 23 +++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 2 +- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index fc730cc89..5c9949a5a 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -66,7 +66,7 @@ namespace MWMechanics // AiWander states AiWander::WanderState mState; - unsigned short mPlayedIdle; + unsigned short mIdleAnimation; PathFinder mPathFinder; @@ -78,7 +78,7 @@ namespace MWMechanics mGreetingTimer(0), mCell(NULL), mState(AiWander::Wander_ChooseAction), - mPlayedIdle(0) + mIdleAnimation(0) {}; }; @@ -240,12 +240,11 @@ namespace MWMechanics } // Check if idle animation finished - short unsigned& playedIdle = storage.mPlayedIdle; + short unsigned& idleAnimation = storage.mIdleAnimation; GreetingState& greetingState = storage.mSaidGreeting; if ((wanderState == Wander_IdleNow) && - !checkIdle(actor, playedIdle) && (greetingState == Greet_Done || greetingState == Greet_None)) + !checkIdle(actor, idleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None)) { - playedIdle = 0; wanderState = Wander_ChooseAction; } @@ -253,10 +252,9 @@ namespace MWMechanics if (wanderState == Wander_ChooseAction) { - playedIdle = 0; - getRandomIdle(playedIdle); // NOTE: sets mPlayedIdle with a random selection + idleAnimation = getRandomIdle(); - if(!playedIdle && mDistance) + if(!idleAnimation && mDistance) { wanderState = Wander_MoveNow; } @@ -265,7 +263,7 @@ namespace MWMechanics // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: MWWorld::TimeStamp currentTime = world->getTimeStamp(); mStartTime = currentTime; - playIdle(actor, playedIdle); + playIdle(actor, idleAnimation); wanderState = Wander_IdleNow; } } @@ -468,7 +466,6 @@ namespace MWMechanics stopWalking(actor, storage); mObstacleCheck.clear(); storage.mState = Wander_IdleNow; - getRandomIdle(storage.mPlayedIdle); } turnActorToFacePlayer(actorPos, playerPos, storage); @@ -605,9 +602,10 @@ namespace MWMechanics } } - void AiWander::getRandomIdle(short unsigned& playedIdle) + short unsigned AiWander::getRandomIdle() { unsigned short idleRoll = 0; + short unsigned selectedAnimation = 0; for(unsigned int counter = 0; counter < mIdle.size(); counter++) { @@ -618,10 +616,11 @@ namespace MWMechanics unsigned short randSelect = (int)(Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier)); if(randSelect < idleChance && randSelect > idleRoll) { - playedIdle = counter+2; + selectedAnimation = counter + GroupIndex_MinIdle; idleRoll = randSelect; } } + return selectedAnimation; } void AiWander::fastForward(const MWWorld::Ptr& actor, AiState &state) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 8a4921b83..df389a34e 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -77,7 +77,7 @@ namespace MWMechanics void stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage); void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); - void getRandomIdle(unsigned short& playedIdle); + short unsigned getRandomIdle(); void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); From 7924ecef3e640f68ddd3ddf5d59bff97713af3b5 Mon Sep 17 00:00:00 2001 From: Koncord Date: Sun, 19 Jul 2015 23:37:20 +0900 Subject: [PATCH 119/419] Fix definition conflict --- components/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 85e61cee5..cf0c83fbd 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -201,7 +201,10 @@ if (GIT_CHECKOUT) endif (GIT_CHECKOUT) if (WIN32) -target_link_libraries(components shlwapi) + target_link_libraries(components shlwapi) + if(MINGW) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNOGDI") + endif(MINGW) endif() # Fix for not visible pthreads functions for linker with glibc 2.15 From a14a3c82ded2f4d2702abaeefd74905b35e21e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Kune=C5=A1?= Date: Sun, 19 Jul 2015 19:52:50 +0200 Subject: [PATCH 120/419] added description of new syntax to the onRetrieveTag function comment --- apps/openmw/mwgui/windowmanagerimp.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index af82c27c0..336a2a19a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -495,6 +495,7 @@ namespace MWGui * Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property. * Supported syntax: * #{GMSTName}: retrieves String value of the GMST called GMSTName + * #{setting=CATEGORY_NAME,SETTING_NAME}: retrieves String value of SETTING_NAME under category CATEGORY_NAME from settings.cfg * #{sCell=CellID}: retrieves translated name of the given CellID (used only by some Morrowind localisations, in others cell ID is == cell name) * #{fontcolour=FontColourName}: retrieves the value of the fallback setting "FontColor_color_" from openmw.cfg, * in the format "r g b a", float values in range 0-1. Useful for "Colour" and "TextColour" properties in skins. From 75e50235904d1394f95269d3a98db950bdce0ec4 Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 08:05:52 +0900 Subject: [PATCH 121/419] fix code duplication --- apps/openmw/mwclass/misc.cpp | 20 ++++++++------------ apps/openmw/mwclass/misc.hpp | 2 ++ apps/openmw/mwworld/containerstore.cpp | 8 +++----- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index b7c39b50a..0c80209f2 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -25,20 +25,16 @@ #include -namespace -{ -bool isGold (const MWWorld::Ptr& ptr) -{ - return Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_001") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_005") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_010") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_025") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_100"); -} -} - namespace MWClass { + bool Miscellaneous::isGold (const MWWorld::Ptr& ptr) const + { + return Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_001") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_005") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_010") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_025") + || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_100"); + } std::string Miscellaneous::getId (const MWWorld::Ptr& ptr) const { return ptr.get()->mBase->mId; diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 66699f9df..394c9ffc0 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -62,6 +62,8 @@ namespace MWClass virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; virtual bool isKey (const MWWorld::Ptr &ptr) const; + + virtual bool isGold (const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index d4aadc6c7..26fcc33cb 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -13,6 +13,8 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/levelledlist.hpp" +#include "../mwclass/misc.hpp" + #include "manualref.hpp" #include "refdata.hpp" #include "class.hpp" @@ -298,11 +300,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr, // gold needs special handling: when it is inserted into a container, the base object automatically becomes Gold_001 // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold) - if (Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_001") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_005") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_010") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_025") - || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "gold_100")) + if(MWClass::Miscellaneous().isGold(ptr)) { int realCount = count * ptr.getClass().getValue(ptr); From aefcd1ad07181b92d1daaebdb2e504efb42d81ad Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 08:20:28 +0900 Subject: [PATCH 122/419] Fix "additem gold_100" behavior --- apps/openmw/mwworld/containerstore.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 26fcc33cb..9d4ec552e 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -302,20 +302,18 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr, // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold) if(MWClass::Miscellaneous().isGold(ptr)) { - int realCount = count * ptr.getClass().getValue(ptr); - for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { if (Misc::StringUtils::ciEqual((*iter).getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) { - iter->getRefData().setCount(iter->getRefData().getCount() + realCount); + iter->getRefData().setCount(iter->getRefData().getCount() + count); flagAsModified(); return iter; } } - MWWorld::ManualRef ref(esmStore, MWWorld::ContainerStore::sGoldId, realCount); - return addNewStack(ref.getPtr(), realCount); + MWWorld::ManualRef ref(esmStore, MWWorld::ContainerStore::sGoldId, count); + return addNewStack(ref.getPtr(), count); } // determine whether to stack or not From 9485aa5e44dfb1cec74f2d36156fbd7e5b3251ed Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 09:53:08 +0900 Subject: [PATCH 123/419] Fix "removeitem gold_100" behavior --- apps/openmw/mwworld/containerstore.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 9d4ec552e..c21fdd662 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -362,8 +362,18 @@ int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const { int toRemove = count; + std::string id = itemId; + + if(Misc::StringUtils::ciEqual(itemId, "gold_005") + || Misc::StringUtils::ciEqual(itemId, "gold_010") + || Misc::StringUtils::ciEqual(itemId, "gold_025") + || Misc::StringUtils::ciEqual(itemId, "gold_100")) + { + id = MWWorld::ContainerStore::sGoldId; + } + for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter) - if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), itemId)) + if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), id)) toRemove -= remove(*iter, toRemove, actor); flagAsModified(); From a24df8cb66e68eca2b665d25121d7cfb5989fb5b Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 12:43:58 +0900 Subject: [PATCH 124/419] Revert addImp() and remove() add isGold() in MWWorld::Class --- apps/openmw/mwworld/class.hpp | 2 ++ apps/openmw/mwworld/containerstore.cpp | 22 +++++++--------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 7ef173555..3f091380f 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -284,6 +284,8 @@ namespace MWWorld virtual bool isKey (const MWWorld::Ptr& ptr) const { return false; } + virtual bool isGold(const MWWorld::Ptr& ptr) const { return false; }; + /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) virtual int getBloodTexture (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index c21fdd662..f7ede6c98 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -300,20 +300,22 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr, // gold needs special handling: when it is inserted into a container, the base object automatically becomes Gold_001 // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold) - if(MWClass::Miscellaneous().isGold(ptr)) + if(ptr.getClass().isGold(ptr)) { + int realCount = count * ptr.getClass().getValue(ptr); + for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { if (Misc::StringUtils::ciEqual((*iter).getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) { - iter->getRefData().setCount(iter->getRefData().getCount() + count); + iter->getRefData().setCount(iter->getRefData().getCount() + realCount); flagAsModified(); return iter; } } - MWWorld::ManualRef ref(esmStore, MWWorld::ContainerStore::sGoldId, count); - return addNewStack(ref.getPtr(), count); + MWWorld::ManualRef ref(esmStore, MWWorld::ContainerStore::sGoldId, realCount); + return addNewStack(ref.getPtr(), realCount); } // determine whether to stack or not @@ -362,18 +364,8 @@ int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const { int toRemove = count; - std::string id = itemId; - - if(Misc::StringUtils::ciEqual(itemId, "gold_005") - || Misc::StringUtils::ciEqual(itemId, "gold_010") - || Misc::StringUtils::ciEqual(itemId, "gold_025") - || Misc::StringUtils::ciEqual(itemId, "gold_100")) - { - id = MWWorld::ContainerStore::sGoldId; - } - for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter) - if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), id)) + if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), itemId)) toRemove -= remove(*iter, toRemove, actor); flagAsModified(); From 7a86c8d8b6e880cd1212cc07bcd40efa6d098f42 Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 12:48:19 +0900 Subject: [PATCH 125/419] Fix OpAddItem, OpGetItemCount and OpRemoveItem. --- apps/openmw/mwscript/containerextensions.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 70475d8e2..ac9bbef66 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -56,6 +56,12 @@ namespace MWScript if (count == 0) return; + if(Misc::StringUtils::ciEqual(item, "gold_005") + || Misc::StringUtils::ciEqual(item, "gold_010") + || Misc::StringUtils::ciEqual(item, "gold_025") + || Misc::StringUtils::ciEqual(item, "gold_100")) + item = "gold_001"; + MWWorld::Ptr itemPtr = *ptr.getClass().getContainerStore (ptr).add (item, count, ptr); // Spawn a messagebox (only for items added to player's inventory and if player is talking to someone) @@ -91,6 +97,12 @@ namespace MWScript std::string item = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); + if(Misc::StringUtils::ciEqual(item, "gold_005") + || Misc::StringUtils::ciEqual(item, "gold_010") + || Misc::StringUtils::ciEqual(item, "gold_025") + || Misc::StringUtils::ciEqual(item, "gold_100")) + item = "gold_001"; + MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); runtime.push (store.count(item)); @@ -119,6 +131,12 @@ namespace MWScript if (count == 0) return; + if(Misc::StringUtils::ciEqual(item, "gold_005") + || Misc::StringUtils::ciEqual(item, "gold_010") + || Misc::StringUtils::ciEqual(item, "gold_025") + || Misc::StringUtils::ciEqual(item, "gold_100")) + item = "gold_001"; + MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); std::string itemName; From 2a4d35b98c0ad0fcab06f25bd8ba113dcf87ab41 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 20 Jul 2015 18:20:57 +1200 Subject: [PATCH 126/419] fixed "comma at end of enumerator list" warning. --- apps/openmw/mwmechanics/aiwander.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index df389a34e..d1dab3f50 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -68,7 +68,7 @@ namespace MWMechanics Wander_ChooseAction, Wander_IdleNow, Wander_MoveNow, - Wander_Walking, + Wander_Walking }; private: // NOTE: mDistance and mDuration must be set already From 6c3c85f0d4f0ebead4fbf0856e98ace2b2b888e0 Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 20 Jul 2015 21:53:20 +0900 Subject: [PATCH 127/419] Fix indent Remove misc.hpp in containerstore.cpp --- apps/openmw/mwscript/containerextensions.cpp | 8 ++++---- apps/openmw/mwworld/containerstore.cpp | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index ac9bbef66..ba18d8e37 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -132,10 +132,10 @@ namespace MWScript return; if(Misc::StringUtils::ciEqual(item, "gold_005") - || Misc::StringUtils::ciEqual(item, "gold_010") - || Misc::StringUtils::ciEqual(item, "gold_025") - || Misc::StringUtils::ciEqual(item, "gold_100")) - item = "gold_001"; + || Misc::StringUtils::ciEqual(item, "gold_010") + || Misc::StringUtils::ciEqual(item, "gold_025") + || Misc::StringUtils::ciEqual(item, "gold_100")) + item = "gold_001"; MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index f7ede6c98..3a7c02332 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -13,8 +13,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/levelledlist.hpp" -#include "../mwclass/misc.hpp" - #include "manualref.hpp" #include "refdata.hpp" #include "class.hpp" From 3c3bd7976ecd5a43c9eddf1fb45e3a25967ca7d3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 22 Jul 2015 08:36:06 +0200 Subject: [PATCH 128/419] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 2bd96e3a1..def0b2b89 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -60,6 +60,7 @@ Programmers Julien Voisin (jvoisin/ap0) Karl-Felix Glatzer (k1ll) Kevin Poitra (PuppyKevin) + Koncord Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) From 8286dc6c5aaa2f9f5c6c5aff4644f93d9bbdcdb0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Jul 2015 16:37:19 +0200 Subject: [PATCH 129/419] Player followers don't report crimes (Fixes #2457) --- .../mwmechanics/mechanicsmanagerimp.cpp | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index e9ef99454..07fa6d592 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1049,6 +1049,19 @@ namespace MWMechanics commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } + + void getFollowers (const MWWorld::Ptr& actor, std::set& out) + { + std::list followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor); + for(std::list::iterator it = followers.begin();it != followers.end();++it) + { + if (out.insert(*it).second) + { + getFollowers(*it, out); + } + } + } + bool MechanicsManager::commitCrime(const MWWorld::Ptr &player, const MWWorld::Ptr &victim, OffenseType type, int arg, bool victimAware) { // NOTE: victim may be empty @@ -1070,6 +1083,10 @@ namespace MWMechanics if (!victim.isEmpty() && (from - victim.getRefData().getPosition().asVec3()).length2() > radius*radius) neighbors.push_back(victim); + // get the player's followers / allies (works recursively) that will not report crimes + std::set playerFollowers; + getFollowers(player, playerFollowers); + // Did anyone see it? bool crimeSeen = false; for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) @@ -1085,11 +1102,6 @@ namespace MWMechanics // TODO: Add mod support for stealth executions! || (type == OT_Murder && *it != victim)) { - if (type == OT_Theft || type == OT_Pickpocket) - MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); - else if (type == OT_Trespassing) - MWBase::Environment::get().getDialogueManager()->say(*it, "intruder"); - // Crime reporting only applies to NPCs if (!it->getClass().isNpc()) continue; @@ -1097,6 +1109,14 @@ namespace MWMechanics if (it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(victim)) continue; + if (playerFollowers.find(*it) != playerFollowers.end()) + continue; + + if (type == OT_Theft || type == OT_Pickpocket) + MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); + else if (type == OT_Trespassing) + MWBase::Environment::get().getDialogueManager()->say(*it, "intruder"); + crimeSeen = true; } } From 7900631d51be62726598bd70177b182b0992783c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 19 Jul 2015 16:39:22 +0200 Subject: [PATCH 130/419] Print the missing player cell to error output --- apps/openmw/mwworld/player.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index b17b8e1f0..d3c0110ac 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -1,7 +1,7 @@ - #include "player.hpp" #include +#include #include #include @@ -19,7 +19,6 @@ #include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" -#include "../mwmechanics/actors.hpp" #include "class.hpp" #include "ptr.hpp" @@ -327,6 +326,7 @@ namespace MWWorld } catch (...) { + std::cerr << "Player cell '" << player.mCellId.mWorldspace << "' no longer exists" << std::endl; // Cell no longer exists. Place the player in a default cell. ESM::Position pos = mPlayer.mData.getPosition(); MWBase::Environment::get().getWorld()->indexToPosition(0, 0, pos.pos[0], pos.pos[1], true); From 7e4e59efb9640135d2ea265f458cfd1cbb6425d6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 23 Jul 2015 02:28:38 +0200 Subject: [PATCH 131/419] Fix excessive auto-equipping in InventoryStore::removeItem (Fixes #2792) --- apps/openmw/mwworld/inventorystore.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 6c283bb3e..2fe914a4e 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -490,6 +490,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor { int retCount = ContainerStore::remove(item, count, actor); + bool wasEquipped = false; if (!item.getRefData().getCount()) { for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) @@ -500,6 +501,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor if (*mSlots[slot] == item) { unequipSlot(slot, actor); + wasEquipped = true; break; } } @@ -507,7 +509,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor // If an armor/clothing item is removed, try to find a replacement, // but not for the player nor werewolves. - if ((actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (wasEquipped && (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) && !(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())) { std::string type = item.getTypeName(); From a7b3248ee7a042d4c481c8215ab850cfb9891dc1 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 23 Jul 2015 20:35:16 +0300 Subject: [PATCH 132/419] Proper sorting of columns with enum values --- apps/opencs/model/world/idtableproxymodel.cpp | 14 ++++++++++++++ apps/opencs/model/world/idtableproxymodel.hpp | 7 +++++++ 2 files changed, 21 insertions(+) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 516644713..1f8f2e4b4 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -60,6 +60,20 @@ void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr(left.data(ColumnBase::Role_ColumnId).toInt()); + EnumColumnCache::const_iterator valuesIt = mEnumColumnCache.find(id); + if (valuesIt == mEnumColumnCache.end()) + { + if (Columns::hasEnums(id)) + { + valuesIt = mEnumColumnCache.insert(std::make_pair(id, Columns::getEnums(id))).first; + } + } + + if (valuesIt != mEnumColumnCache.end()) + { + return valuesIt->second[left.data().toInt()] < valuesIt->second[right.data().toInt()]; + } return QSortFilterProxyModel::lessThan(left, right); } diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp index d2a240529..decad157c 100644 --- a/apps/opencs/model/world/idtableproxymodel.hpp +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -11,6 +11,8 @@ #include "../filter/node.hpp" +#include "columns.hpp" + namespace CSMWorld { class IdTableProxyModel : public QSortFilterProxyModel @@ -20,6 +22,11 @@ namespace CSMWorld boost::shared_ptr mFilter; std::map mColumnMap; // column ID, column index in this model (or -1) + // Cache of enum values for enum columns (e.g. Modified, Record Type). + // Used to speed up comparisons during the sort by such columns. + typedef std::map > EnumColumnCache; + mutable EnumColumnCache mEnumColumnCache; + private: void updateColumnMap(); From f5b1447c9226adb89db38ea52b7435d4e2072cc6 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 23 Jul 2015 21:05:00 +0300 Subject: [PATCH 133/419] IdTableProxyModel refreshes the filter when the source model data or rows changed --- apps/opencs/model/world/idtableproxymodel.cpp | 28 +++++++++++++++++++ apps/opencs/model/world/idtableproxymodel.hpp | 8 ++++++ apps/opencs/view/world/table.cpp | 4 --- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 1f8f2e4b4..ce9d44ed6 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -50,6 +50,24 @@ QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, i return mapFromSource (dynamic_cast (*sourceModel()).getModelIndex (id, column)); } +void CSMWorld::IdTableProxyModel::setSourceModel(QAbstractItemModel *model) +{ + QSortFilterProxyModel::setSourceModel(model); + + connect(sourceModel(), + SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, + SLOT(sourceRowsChanged(const QModelIndex &, int, int))); + connect(sourceModel(), + SIGNAL(rowsInserted(const QModelIndex &, int, int)), + this, + SLOT(sourceRowsChanged(const QModelIndex &, int, int))); + connect(sourceModel(), + SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), + this, + SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &))); +} + void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr& filter) { beginResetModel(); @@ -82,3 +100,13 @@ void CSMWorld::IdTableProxyModel::refreshFilter() updateColumnMap(); invalidateFilter(); } + +void CSMWorld::IdTableProxyModel::sourceRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) +{ + refreshFilter(); +} + +void CSMWorld::IdTableProxyModel::sourceDataChanged(const QModelIndex &/*topLeft*/, const QModelIndex &/*bottomRight*/) +{ + refreshFilter(); +} diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp index decad157c..17c30361a 100644 --- a/apps/opencs/model/world/idtableproxymodel.hpp +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -37,6 +37,8 @@ namespace CSMWorld virtual QModelIndex getModelIndex (const std::string& id, int column) const; + virtual void setSourceModel(QAbstractItemModel *model); + void setFilter (const boost::shared_ptr& filter); void refreshFilter(); @@ -46,6 +48,12 @@ namespace CSMWorld bool lessThan(const QModelIndex &left, const QModelIndex &right) const; virtual bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const; + + private slots: + + void sourceRowsChanged(const QModelIndex &parent, int start, int end); + + void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); }; } diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 74343a5f6..5a2a572e2 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -653,10 +653,6 @@ void CSVWorld::Table::tableSizeUpdate() } emit tableSizeChanged (size, deleted, modified); - - // not really related to tableSizeUpdate() but placed here for convenience rather than - // creating a bunch of extra connections & slot - mProxyModel->refreshFilter(); } void CSVWorld::Table::selectionSizeUpdate() From 6d2d32485fa051260dfe3643786891d070f21480 Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Thu, 23 Jul 2015 22:22:22 -0500 Subject: [PATCH 134/419] Fix building OpenCS with Qt 5. --- apps/opencs/view/world/scripterrortable.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 3e80c5bd4..415e6c9dc 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -76,8 +76,13 @@ CSVWorld::ScriptErrorTable::ScriptErrorTable (const CSMDoc::Document& document, QStringList headers; headers << "Severity" << "Line" << "Description"; setHorizontalHeaderLabels (headers); +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + horizontalHeader()->setSectionResizeMode (0, QHeaderView::ResizeToContents); + horizontalHeader()->setSectionResizeMode (1, QHeaderView::ResizeToContents); +#else horizontalHeader()->setResizeMode (0, QHeaderView::ResizeToContents); horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents); +#endif horizontalHeader()->setStretchLastSection (true); verticalHeader()->hide(); setColumnHidden (3, true); From 71bc22401f103532e8ad4eec3b0a8140f60226f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Jul 2015 18:23:23 +0200 Subject: [PATCH 135/419] Include cleanup --- apps/openmw/mwworld/actioneat.cpp | 2 -- apps/openmw/mwworld/worldimp.cpp | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 660915523..8bb80b564 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -1,8 +1,6 @@ #include "actioneat.hpp" -#include - #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8011f81ce..15c8cbeb2 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -14,13 +14,11 @@ #include #include +#include #include #include -#include -#include -#include #include #include From 7f66339790a8f25aedeb610cb792ad043af8caf6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Jul 2015 20:23:27 +0200 Subject: [PATCH 136/419] Remove a redundant function --- apps/openmw/mwclass/creature.cpp | 26 ++++---------------------- apps/openmw/mwclass/creature.hpp | 2 -- apps/openmw/mwclass/npc.cpp | 25 +++---------------------- apps/openmw/mwclass/npc.hpp | 2 -- apps/openmw/mwmechanics/actors.cpp | 4 +++- apps/openmw/mwworld/class.cpp | 5 ----- apps/openmw/mwworld/class.hpp | 6 ------ 7 files changed, 10 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index f312a41c7..8b7bcf6b9 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -394,8 +394,10 @@ namespace MWClass damage = scaleDamage(damage, attacker, ptr); MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Health Damage", 1.0f, 1.0f); - float health = getCreatureStats(ptr).getHealth().getCurrent() - damage; - setActorHealth(ptr, health, attacker); + + MWMechanics::DynamicStat health(getCreatureStats(ptr).getHealth()); + health.setCurrent(health.getCurrent() - damage); + getCreatureStats(ptr).setHealth(health); } else { @@ -430,26 +432,6 @@ namespace MWClass } } - void Creature::setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const - { - MWMechanics::CreatureStats &crstats = getCreatureStats(ptr); - bool wasDead = crstats.isDead(); - - MWMechanics::DynamicStat stat(crstats.getHealth()); - stat.setCurrent(health); - crstats.setHealth(stat); - - if(!wasDead && crstats.isDead()) - { - // actor was just killed - } - else if(wasDead && !crstats.isDead()) - { - // actor was just resurrected - } - } - - boost::shared_ptr Creature::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 740552a60..b2a333beb 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -72,8 +72,6 @@ namespace MWClass virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; - virtual void setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const; - virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; ///< Generate action for activation diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d0dd9f994..75b612dad 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -733,8 +733,9 @@ namespace MWClass if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(); } - float health = getCreatureStats(ptr).getHealth().getCurrent() - damage; - setActorHealth(ptr, health, attacker); + MWMechanics::DynamicStat health(getCreatureStats(ptr).getHealth()); + health.setCurrent(health.getCurrent() - damage); + getCreatureStats(ptr).setHealth(health); } else { @@ -779,26 +780,6 @@ namespace MWClass } } - void Npc::setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const - { - MWMechanics::CreatureStats &crstats = getCreatureStats(ptr); - bool wasDead = crstats.isDead(); - - MWMechanics::DynamicStat stat(crstats.getHealth()); - stat.setCurrent(health); - crstats.setHealth(stat); - - if(!wasDead && crstats.isDead()) - { - // actor was just killed - } - else if(wasDead && !crstats.isDead()) - { - // actor was just resurrected - } - } - - boost::shared_ptr Npc::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index f032ae77c..b12b7b13f 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -87,8 +87,6 @@ namespace MWClass virtual void block(const MWWorld::Ptr &ptr) const; - virtual void setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const; - virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; ///< Generate action for activation diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 14561b4bb..c135811dd 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -699,7 +699,9 @@ namespace MWMechanics { // If drowning, apply 3 points of damage per second static const float fSuffocationDamage = world->getStore().get().find("fSuffocationDamage")->getFloat(); - ptr.getClass().setActorHealth(ptr, stats.getHealth().getCurrent() - fSuffocationDamage*duration); + DynamicStat health = stats.getHealth(); + health.setCurrent(health.getCurrent() - fSuffocationDamage*duration); + stats.setHealth(health); // Play a drowning sound MWBase::SoundManager *sndmgr = MWBase::Environment::get().getSoundManager(); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 5ec2d4e16..180cba332 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -109,11 +109,6 @@ namespace MWWorld throw std::runtime_error("class cannot be hit"); } - void Class::setActorHealth(const Ptr& ptr, float health, const Ptr& attacker) const - { - throw std::runtime_error("class does not have actor health"); - } - boost::shared_ptr Class::activate (const Ptr& ptr, const Ptr& actor) const { return boost::shared_ptr (new NullAction); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 3f091380f..cd05b471b 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -136,12 +136,6 @@ namespace MWWorld ///< Play the appropriate sound for a blocked attack, depending on the currently equipped shield /// (default implementation: throw an exception) - virtual void setActorHealth(const Ptr& ptr, float health, const Ptr& attacker=Ptr()) const; - ///< Sets a new current health value for the actor, optionally specifying the object causing - /// the change. Use this instead of using CreatureStats directly as this will make sure the - /// correct dialog and actor states are properly handled when being hurt or healed. - /// (default implementation: throw an exception) - virtual boost::shared_ptr activate (const Ptr& ptr, const Ptr& actor) const; ///< Generate action for activation (default implementation: return a null action). From 47922f6c35a9f88374ff0f6301b5706f43e3e9af Mon Sep 17 00:00:00 2001 From: Pawel Kubik Date: Fri, 24 Jul 2015 21:54:58 +0200 Subject: [PATCH 137/419] Changed a settings variable responsible for number of loaded exterior cells. --- apps/openmw/mwworld/scene.cpp | 2 +- files/settings-default.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 8029cb773..13e6593e5 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -327,7 +327,7 @@ namespace MWWorld std::string loadingExteriorText = "#{sLoadingMessage3}"; loadingListener->setLabel(loadingExteriorText); - const int halfGridSize = Settings::Manager::getInt("exterior grid size", "Cells")/2; + const int halfGridSize = Settings::Manager::getInt("exterior cell load distance", "Cells"); CellStoreCollection::iterator active = mActiveCells.begin(); while (active!=mActiveCells.end()) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index dcb9b8893..0f7349eb9 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -101,7 +101,7 @@ local map widget size = 512 local map hud widget size = 256 [Cells] -exterior grid size = 3 +exterior cell load distance = 1 [Camera] near clip = 5 From 4f6e5345ccd831169bfec8432cebce6f125942a1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Jul 2015 23:28:36 +0200 Subject: [PATCH 138/419] Include cleanup --- apps/openmw/mwworld/cellstore.hpp | 1 - apps/openmw/mwworld/manualref.cpp | 1 - apps/openmw/mwworld/player.cpp | 1 - apps/openmw/mwworld/scene.cpp | 5 +---- apps/openmw/mwworld/store.cpp | 1 - 5 files changed, 1 insertion(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index f879343d9..fd3f364e9 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -10,7 +10,6 @@ #include "livecellref.hpp" #include "cellreflist.hpp" -#include #include #include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld diff --git a/apps/openmw/mwworld/manualref.cpp b/apps/openmw/mwworld/manualref.cpp index b926c5799..d6e40ad09 100644 --- a/apps/openmw/mwworld/manualref.cpp +++ b/apps/openmw/mwworld/manualref.cpp @@ -1,7 +1,6 @@ #include "manualref.hpp" #include "esmstore.hpp" -#include "cellstore.hpp" namespace { diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index d3c0110ac..6bfdd2986 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -22,7 +22,6 @@ #include "class.hpp" #include "ptr.hpp" -#include "inventorystore.hpp" #include "cellstore.hpp" namespace MWWorld diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 8029cb773..1c51d4570 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -1,15 +1,12 @@ #include "scene.hpp" #include +#include -#include #include #include #include #include -#include - -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index d873ab468..29187f950 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1,5 +1,4 @@ #include "store.hpp" -#include "esmstore.hpp" #include #include From 3f3c3d0ad354b12309a6f023d8885fee61a3cd50 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 24 Jul 2015 23:28:43 +0200 Subject: [PATCH 139/419] Remove an already resolved todo comment --- apps/openmw/mwworld/inventorystore.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index a60d1f464..95c16c115 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -87,7 +87,6 @@ namespace MWWorld float mMultiplier; }; - // TODO: store in savegame typedef std::map > TEffectMagnitudes; TEffectMagnitudes mPermanentMagicEffectMagnitudes; From e6b28d84f0b58317a73ec6b20964da8bb9f76dfa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 00:28:47 +0200 Subject: [PATCH 140/419] Outdated comment fix --- apps/openmw/mwmechanics/aicombat.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 6a39178ce..f0bb198a0 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -20,7 +20,7 @@ #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" -#include "character.hpp" // fixme: for getActiveWeapon +#include "character.hpp" #include "aicombataction.hpp" #include "combat.hpp" @@ -291,7 +291,7 @@ namespace MWMechanics // Get weapon characteristics if (actorClass.hasInventoryStore(actor)) { - //Get weapon speed and range + //Get weapon range MWWorld::ContainerStoreIterator weaponSlot = MWMechanics::getActiveWeapon(actorClass.getCreatureStats(actor), actorClass.getInventoryStore(actor), &weaptype); From b3f5ac5dbb227233bb88cd1cc9b7d996abecfc20 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 01:48:34 +0200 Subject: [PATCH 141/419] Include cleanup --- apps/opencs/model/world/refidadapterimp.hpp | 1 - apps/openmw/mwmechanics/aiactivate.cpp | 1 - apps/openmw/mwmechanics/aiavoiddoor.cpp | 3 +-- apps/openmw/mwmechanics/aicombat.cpp | 5 ----- apps/openmw/mwmechanics/aiescort.cpp | 1 - apps/openmw/mwmechanics/aifollow.cpp | 2 -- components/compiler/fileparser.cpp | 2 -- components/esmterrain/storage.cpp | 2 -- components/files/constrainedfilestream.cpp | 1 - components/interpreter/interpreter.cpp | 1 - components/nifbullet/bulletnifloader.cpp | 1 - components/sceneutil/attach.cpp | 1 - components/sceneutil/lightmanager.cpp | 5 ++--- components/terrain/material.cpp | 2 -- 14 files changed, 3 insertions(+), 25 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 869996da5..4066b5646 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -2,7 +2,6 @@ #define CSM_WOLRD_REFIDADAPTERIMP_H #include -#include #include diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index b0621c805..8761ca37f 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -8,7 +8,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/cellstore.hpp" #include "steering.hpp" #include "movement.hpp" diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 457c9a95c..b3aa346ce 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -1,10 +1,9 @@ #include "aiavoiddoor.hpp" -#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/cellstore.hpp" #include "creaturestats.hpp" #include "movement.hpp" diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index f0bb198a0..b2f938b9e 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -5,18 +5,13 @@ #include #include "../mwworld/class.hpp" -#include "../mwworld/timestamp.hpp" -#include "../mwworld/inventorystore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/cellstore.hpp" #include "../mwbase/environment.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" #include "../mwrender/animation.hpp" - #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 593f9f173..f75fc22ad 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -6,7 +6,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwworld/cellstore.hpp" #include "../mwworld/class.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index a92e9eedc..8e111be61 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -1,7 +1,5 @@ #include "aifollow.hpp" -#include - #include #include "../mwbase/world.hpp" diff --git a/components/compiler/fileparser.cpp b/components/compiler/fileparser.cpp index 423841ac3..c8a512340 100644 --- a/components/compiler/fileparser.cpp +++ b/components/compiler/fileparser.cpp @@ -1,7 +1,5 @@ #include "fileparser.hpp" -#include - #include "tokenloc.hpp" #include "scanner.hpp" diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 1811f58e6..10b75bb74 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -5,8 +5,6 @@ #include #include -#include - #include #include diff --git a/components/files/constrainedfilestream.cpp b/components/files/constrainedfilestream.cpp index 3e5d0c245..cd9a3c8f5 100644 --- a/components/files/constrainedfilestream.cpp +++ b/components/files/constrainedfilestream.cpp @@ -1,7 +1,6 @@ #include "constrainedfilestream.hpp" #include -#include #include "lowlevelfile.hpp" diff --git a/components/interpreter/interpreter.cpp b/components/interpreter/interpreter.cpp index ea1e9fc91..f5dee0dba 100644 --- a/components/interpreter/interpreter.cpp +++ b/components/interpreter/interpreter.cpp @@ -2,7 +2,6 @@ #include "interpreter.hpp" #include -#include #include #include diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index adf961dc2..2496c68cd 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 2432b5eb2..d8cfa428a 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -1,7 +1,6 @@ #include "attach.hpp" #include -#include #include #include diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 039d556d1..07ec0aff6 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -1,5 +1,7 @@ #include "lightmanager.hpp" +#include + #include #include @@ -9,9 +11,6 @@ #include -#include -#include - namespace SceneUtil { diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 2034883ed..df45b6ec2 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -1,7 +1,5 @@ #include "material.hpp" -#include - #include #include #include From 3bca3e73d439b3202ce86853ad061c68d25c7fbf Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 02:11:59 +0200 Subject: [PATCH 142/419] Fix GetWeaponDrawn and GetSpellReadied script functions for creatures --- apps/openmw/mwscript/miscextensions.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 8409351aa..9a9127977 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -567,7 +567,8 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - runtime.push(ptr.getClass().getNpcStats (ptr).getDrawState () == MWMechanics::DrawState_Weapon); + runtime.push((ptr.getClass().hasInventoryStore(ptr) || ptr.getClass().isBipedal(ptr)) && + ptr.getClass().getCreatureStats (ptr).getDrawState () == MWMechanics::DrawState_Weapon); } }; @@ -580,7 +581,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - runtime.push(ptr.getClass().getNpcStats (ptr).getDrawState () == MWMechanics::DrawState_Spell); + runtime.push(ptr.getClass().getCreatureStats (ptr).getDrawState () == MWMechanics::DrawState_Spell); } }; From 278076e609573ac4c0367a5f4f9d6693c01a2a73 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 04:14:22 +0200 Subject: [PATCH 143/419] Include cleanup --- apps/openmw/mwmechanics/aifollow.cpp | 1 + apps/openmw/mwmechanics/aipackage.cpp | 5 ++++- apps/openmw/mwmechanics/aipursue.cpp | 2 +- apps/openmw/mwmechanics/aisequence.cpp | 6 ++---- apps/openmw/mwmechanics/aitravel.cpp | 1 + apps/openmw/mwmechanics/obstacle.cpp | 2 ++ apps/openmw/mwrender/localmap.cpp | 1 + apps/openmw/mwrender/water.cpp | 2 ++ apps/openmw/mwworld/cellstore.hpp | 22 +++++++++++++++++++++- 9 files changed, 35 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index 8e111be61..cd67c6058 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -1,6 +1,7 @@ #include "aifollow.hpp" #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 0e68d9d79..77efe62a8 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -1,7 +1,10 @@ - #include "aipackage.hpp" #include + +#include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index ac6b23ef6..e936505c9 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -1,12 +1,12 @@ #include "aipursue.hpp" #include +#include #include "../mwbase/environment.hpp" #include "../mwworld/class.hpp" #include "../mwworld/action.hpp" -#include "../mwworld/cellstore.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index fb6450d16..a750860ca 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -1,6 +1,7 @@ - #include "aisequence.hpp" +#include + #include "aipackage.hpp" #include "aistate.hpp" @@ -14,9 +15,6 @@ #include -#include "../mwworld/class.hpp" -#include "creaturestats.hpp" -#include "npcstats.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index f192bed63..1585a3007 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -1,6 +1,7 @@ #include "aitravel.hpp" #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 3d2ab7d3d..25bd06301 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -1,5 +1,7 @@ #include "obstacle.hpp" +#include + #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 6ce54a4ba..d307e990a 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 7cad745dd..b5f141963 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -17,6 +17,8 @@ #include #include +#include + #include "vismask.hpp" #include "ripplesimulation.hpp" diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index fd3f364e9..f88bf0958 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -5,12 +5,32 @@ #include #include #include +#include + #include #include "livecellref.hpp" #include "cellreflist.hpp" -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld From c088cd4fa9d0286124bf3ad7c553150cdb842bbe Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 25 Jul 2015 17:57:40 +0300 Subject: [PATCH 144/419] Proper index creation for nested data --- apps/opencs/model/world/idtree.cpp | 4 ++-- apps/opencs/model/world/nestedtableproxymodel.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 9dbe7e002..5a7d10c6e 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -171,10 +171,10 @@ QModelIndex CSMWorld::IdTree::index (int row, int column, const QModelIndex& par encodedId = this->foldIndexAddress(parent); } - if (row<0 || row>=idCollection()->getSize()) + if (row < 0 || row >= rowCount(parent)) return QModelIndex(); - if (column<0 || column>=idCollection()->getColumns()) + if (column < 0 || column >= columnCount(parent)) return QModelIndex(); return createIndex(row, column, encodedId); // store internal id diff --git a/apps/opencs/model/world/nestedtableproxymodel.cpp b/apps/opencs/model/world/nestedtableproxymodel.cpp index 052e629aa..edcc7a070 100644 --- a/apps/opencs/model/world/nestedtableproxymodel.cpp +++ b/apps/opencs/model/world/nestedtableproxymodel.cpp @@ -75,10 +75,10 @@ QModelIndex CSMWorld::NestedTableProxyModel::index(int row, int column, const QM { assert (!parent.isValid()); - int rows = mMainModel->rowCount(parent); - int columns = mMainModel->columnCount(parent); + int numRows = rowCount(parent); + int numColumns = columnCount(parent); - if (row < 0 || row >= rows || column < 0 || column >= columns) + if (row < 0 || row >= numRows || column < 0 || column >= numColumns) return QModelIndex(); return createIndex(row, column); From e0ee2fc01b3fb8db478bb88e6211065cc775c8e0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 18:22:48 +0200 Subject: [PATCH 145/419] Adjust the movement animation speed every frame (Fixes #1921) --- apps/openmw/mwmechanics/character.cpp | 43 ++++++++++++++------------- apps/openmw/mwmechanics/character.hpp | 3 +- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 50faaa91b..066489e8e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -408,14 +408,13 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mCurrentMovement = movementAnimName; if(!mCurrentMovement.empty()) { - float vel, speedmult = 1.0f; - bool isrunning = mPtr.getClass().getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run) && !MWBase::Environment::get().getWorld()->isFlying(mPtr); // For non-flying creatures, MW uses the Walk animation to calculate the animation velocity // even if we are running. This must be replicated, otherwise the observed speed would differ drastically. std::string anim = mCurrentMovement; + mAdjustMovementAnimSpeed = true; if (mPtr.getClass().getTypeName() == typeid(ESM::Creature).name() && !(mPtr.get()->mBase->mFlags & ESM::Creature::Flies)) { @@ -423,30 +422,28 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat const StateInfo *stateinfo = std::find_if(sMovementList, sMovementListEnd, FindCharState(walkState)); anim = stateinfo->groupname; - if (mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(anim)) > 1.0f) - speedmult = mMovementSpeed / vel; - else + mMovementAnimSpeed = mAnimation->getVelocity(anim); + if (mMovementAnimSpeed <= 1.0f) + { // Another bug: when using a fallback animation (e.g. RunForward as fallback to SwimRunForward), // then the equivalent Walk animation will not use a fallback, and if that animation doesn't exist // we will play without any scaling. // Makes the speed attribute of most water creatures totally useless. // And again, this can not be fixed without patching game data. - speedmult = 1.f; + mAdjustMovementAnimSpeed = false; + mMovementAnimSpeed = 1.f; + } } else { - if(mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(anim)) > 1.0f) - { - speedmult = mMovementSpeed / vel; - } - else if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight) - speedmult = 1.f; // adjusted each frame - else if (mMovementSpeed > 0.0f) + mMovementAnimSpeed = mAnimation->getVelocity(anim); + + if (mMovementAnimSpeed <= 1.0f) { // The first person anims don't have any velocity to calculate a speed multiplier from. // We use the third person velocities instead. // FIXME: should be pulled from the actual animation, but it is not presently loaded. - speedmult = mMovementSpeed / (isrunning ? 222.857f : 154.064f); + mMovementAnimSpeed = (isrunning ? 222.857f : 154.064f); mMovementAnimationControlled = false; } } @@ -462,7 +459,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } mAnimation->play(mCurrentMovement, priorityMovement, movemask, false, - speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); + 1.f, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); } } @@ -655,7 +652,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mAnimation(anim) , mIdleState(CharState_None) , mMovementState(CharState_None) - , mMovementSpeed(0.0f) , mHasMovedInXY(false) , mMovementAnimationControlled(true) , mDeathState(CharState_None) @@ -1487,6 +1483,7 @@ void CharacterController::update(float duration) MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Class &cls = mPtr.getClass(); osg::Vec3f movement(0.f, 0.f, 0.f); + float speed = 0.f; updateMagicEffects(); @@ -1550,10 +1547,10 @@ void CharacterController::update(float duration) vec = osg::Vec3f(0.f, 0.f, 0.f); osg::Vec3f rot = cls.getRotationVector(mPtr); - mMovementSpeed = cls.getSpeed(mPtr); + speed = cls.getSpeed(mPtr); - vec.x() *= mMovementSpeed; - vec.y() *= mMovementSpeed; + vec.x() *= speed; + vec.y() *= speed; CharacterState movestate = CharState_None; CharacterState idlestate = CharState_SpecialIdle; @@ -1807,6 +1804,11 @@ void CharacterController::update(float duration) if (duration > 0) mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z()) / duration / static_cast(osg::PI))); } + else if (mMovementState != CharState_None && mAdjustMovementAnimSpeed) + { + float speedmult = speed / mMovementAnimSpeed; + mAnimation->adjustSpeedMult(mCurrentMovement, speedmult); + } if (!mSkipAnim) { @@ -1845,7 +1847,7 @@ void CharacterController::update(float duration) moved = osg::Vec3f(0.f, 0.f, 0.f); // Ensure we're moving in generally the right direction... - if(mMovementSpeed > 0.f) + if(speed > 0.f) { float l = moved.length(); @@ -1927,7 +1929,6 @@ void CharacterController::clearAnimQueue() mAnimQueue.clear(); } - void CharacterController::forceStateUpdate() { if(!mAnimation) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index f37afd996..1f9b524e5 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -150,7 +150,8 @@ class CharacterController : public MWRender::Animation::TextKeyListener CharacterState mMovementState; std::string mCurrentMovement; - float mMovementSpeed; + float mMovementAnimSpeed; + bool mAdjustMovementAnimSpeed; bool mHasMovedInXY; bool mMovementAnimationControlled; From 41996b0aad06bd402b69f40b1855bec927c87ba4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 25 Jul 2015 18:59:16 +0200 Subject: [PATCH 146/419] Don't play turning animations in first person mode --- apps/openmw/mwmechanics/character.cpp | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 066489e8e..cf8b0284e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -448,17 +448,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } } - MWRender::Animation::AnimPriority priorityMovement (Priority_Movement); - if ((movement == CharState_TurnLeft || movement == CharState_TurnRight) - && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() - && MWBase::Environment::get().getWorld()->isFirstPerson()) - { - priorityMovement.mPriority[MWRender::Animation::BoneGroup_Torso] = 0; - priorityMovement.mPriority[MWRender::Animation::BoneGroup_LeftArm] = 0; - priorityMovement.mPriority[MWRender::Animation::BoneGroup_RightArm] = 0; - } - - mAnimation->play(mCurrentMovement, priorityMovement, movemask, false, + mAnimation->play(mCurrentMovement, Priority_Movement, movemask, false, 1.f, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); } } @@ -1741,10 +1731,7 @@ void CharacterController::update(float duration) : (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack))); } - // Don't play turning animations during attack. It would break positioning of the arrow bone when releasing a shot. - // Actually, in vanilla the turning animation is not even played when merely having equipped the weapon, - // but I don't think we need to go as far as that. - else if(rot.z() != 0.0f && !inwater && !sneak && mUpperBodyState < UpperCharState_StartToMinAttack) + else if(rot.z() != 0.0f && !inwater && !sneak && !MWBase::Environment::get().getWorld()->isFirstPerson()) { if(rot.z() > 0.0f) movestate = CharState_TurnRight; From aba72258173db213bdccc82682ca1938a88d7559 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 11:15:21 +1200 Subject: [PATCH 147/419] Removed some duplicated operations. --- apps/openmw/mwmechanics/aicombat.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 6a39178ce..bdd09a1a8 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -181,13 +181,15 @@ namespace MWMechanics // get or create temporary storage AiCombatStorage& storage = state.get(); + const MWWorld::Class& actorClass = actor.getClass(); //General description - if(actor.getClass().getCreatureStats(actor).isDead()) + if (actorClass.getCreatureStats(actor).isDead()) return true; - MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); + MWBase::World* world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr target = world->searchPtrViaActorId(mTargetActorId); if (target.isEmpty()) return false; @@ -196,9 +198,6 @@ namespace MWMechanics || target.getClass().getCreatureStats(target).isDead()) return true; - const MWWorld::Class& actorClass = actor.getClass(); - MWBase::World* world = MWBase::Environment::get().getWorld(); - //Update every frame bool& combatMove = storage.mCombatMove; From dff84adf7e254c819943104d870d59a8e55d924d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 26 Jul 2015 01:35:36 +0200 Subject: [PATCH 148/419] Fix weapon animation priority --- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index cf8b0284e..9d5f7137f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1052,7 +1052,7 @@ bool CharacterController::updateWeaponState() } MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon); - priorityWeapon.mPriority[MWRender::Animation::BoneGroup_LowerBody] = 0; + priorityWeapon.mPriority[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody; bool forcestateupdate = false; if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 1f9b524e5..d647cae22 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -28,6 +28,7 @@ class CreatureStats; enum Priority { Priority_Default, + Priority_WeaponLowerBody, Priority_Jump, Priority_Movement, Priority_Hit, From b3d5b47fea3b949d632f9168dd8cd5f273dc8b00 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:23:45 +1200 Subject: [PATCH 149/419] extracted function UpdateActorsMovement(). --- apps/openmw/mwmechanics/aicombat.cpp | 37 ++++++++++++++++++---------- apps/openmw/mwmechanics/aicombat.hpp | 5 ++++ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index bdd09a1a8..1beb0024c 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -214,20 +214,8 @@ namespace MWMechanics } } - actorClass.getMovementSettings(actor) = movement; - actorClass.getMovementSettings(actor).mRotation[0] = 0; - actorClass.getMovementSettings(actor).mRotation[2] = 0; + UpdateActorsMovement(actor, movement); - if(movement.mRotation[2] != 0) - { - if(zTurn(actor, movement.mRotation[2])) movement.mRotation[2] = 0; - } - - if(movement.mRotation[0] != 0) - { - if(smoothTurn(actor, movement.mRotation[0], 0)) movement.mRotation[0] = 0; - } - bool& attack = storage.mAttack; bool& readyToAttack = storage.mReadyToAttack; @@ -579,6 +567,29 @@ namespace MWMechanics return false; } + void AiCombat::UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& desiredMovement) + { + MWMechanics::Movement& actorMovementSettings = actor.getClass().getMovementSettings(actor); + actorMovementSettings = desiredMovement; + RotateActorOnAxis(actor, 2, actorMovementSettings, desiredMovement); + RotateActorOnAxis(actor, 0, actorMovementSettings, desiredMovement); + } + + void AiCombat::RotateActorOnAxis(const MWWorld::Ptr& actor, int axis, + MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement) + { + actorMovementSettings.mRotation[axis] = 0; + float& targetAngleRadians = desiredMovement.mRotation[axis]; + if (targetAngleRadians != 0) + { + if (smoothTurn(actor, targetAngleRadians, axis)) + { + // actor now facing desired direction, no need to turn any more + targetAngleRadians = 0; + } + } + } + bool AiCombat::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell) { if (!mPathFinder.getPath().empty()) diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 083f23384..c81ad0544 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -60,6 +60,11 @@ namespace MWMechanics void buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); + + /// Transfer desired movement (from AiCombatStorage) to Actor + void UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& movement); + void RotateActorOnAxis(const MWWorld::Ptr& actor, int axis, + MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement); }; From 5ec310dfbab45a6952cb8fcb94b64f6f8b364a7f Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:24:33 +1200 Subject: [PATCH 150/419] extract function onIdleStatePerFrameActions(). --- apps/openmw/mwmechanics/aiwander.cpp | 68 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 5c9949a5a..8b05299a4 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -195,18 +195,10 @@ namespace MWMechanics WanderState& wanderState = storage.mState; - // Check if an idle actor is too close to a door - if so start walking - mDoorCheckDuration += duration; - if(mDoorCheckDuration >= DOOR_CHECK_INTERVAL) + + if (wanderState == Wander_IdleNow) { - mDoorCheckDuration = 0; // restart timer - if(mDistance && // actor is not intended to be stationary - (wanderState == Wander_IdleNow) && // but is in idle - proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only - { - wanderState = Wander_MoveNow; - mTrimCurrentNode = false; // just in case - } + onIdleStatePerFrameActions(actor, duration, storage); } // Are we there yet? @@ -229,29 +221,11 @@ namespace MWMechanics evadeObstacles(actor, storage, duration); } - bool& rotate = storage.mTurnActorGivingGreetingToFacePlayer; - if (rotate) - { - // Reduce the turning animation glitch by using a *HUGE* value of - // epsilon... TODO: a proper fix might be in either the physics or the - // animation subsystem - if (zTurn(actor, storage.mTargetAngleRadians, osg::DegreesToRadians(5.f))) - rotate = false; - } - - // Check if idle animation finished - short unsigned& idleAnimation = storage.mIdleAnimation; - GreetingState& greetingState = storage.mSaidGreeting; - if ((wanderState == Wander_IdleNow) && - !checkIdle(actor, idleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None)) - { - wanderState = Wander_ChooseAction; - } - MWBase::World *world = MWBase::Environment::get().getWorld(); if (wanderState == Wander_ChooseAction) { + short unsigned& idleAnimation = storage.mIdleAnimation; idleAnimation = getRandomIdle(); if(!idleAnimation && mDistance) @@ -355,6 +329,40 @@ namespace MWMechanics return false; // AiWander package not yet completed } + void AiWander::onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage) + { + // Check if an idle actor is too close to a door - if so start walking + mDoorCheckDuration += duration; + if (mDoorCheckDuration >= DOOR_CHECK_INTERVAL) + { + mDoorCheckDuration = 0; // restart timer + if (mDistance && // actor is not intended to be stationary + proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only + { + storage.mState = Wander_MoveNow; + mTrimCurrentNode = false; // just in case + return; + } + } + + bool& rotate = storage.mTurnActorGivingGreetingToFacePlayer; + if (rotate) + { + // Reduce the turning animation glitch by using a *HUGE* value of + // epsilon... TODO: a proper fix might be in either the physics or the + // animation subsystem + if (zTurn(actor, storage.mTargetAngleRadians, osg::DegreesToRadians(5.f))) + rotate = false; + } + + // Check if idle animation finished + GreetingState& greetingState = storage.mSaidGreeting; + if (!checkIdle(actor, storage.mIdleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None)) + { + storage.mState = Wander_ChooseAction; + } + } + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) { if (mObstacleCheck.check(actor, duration)) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index d1dab3f50..92af5b717 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -83,6 +83,7 @@ namespace MWMechanics void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); + void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 76f95eafe7c4db0ecb7a223465c5d010d2be0742 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:25:00 +1200 Subject: [PATCH 151/419] extract function onWalkingStatePerFrameActions(). --- apps/openmw/mwmechanics/aiwander.cpp | 40 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 8b05299a4..77cd9e137 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -201,26 +201,11 @@ namespace MWMechanics onIdleStatePerFrameActions(actor, duration, storage); } - // Are we there yet? - if ((wanderState == Wander_Walking) && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) + if (wanderState == Wander_Walking) { - stopWalking(actor, storage); - wanderState = Wander_ChooseAction; - mHasReturnPosition = false; + onWalkingStatePerFrameActions(actor, duration, storage, pos); } - - - if (wanderState == Wander_Walking) // have not yet reached the destination - { - // turn towards the next point in mPath - zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); - actor.getClass().getMovementSettings(actor).mPosition[1] = 1; - - evadeObstacles(actor, storage, duration); - } - MWBase::World *world = MWBase::Environment::get().getWorld(); if (wanderState == Wander_ChooseAction) @@ -363,6 +348,27 @@ namespace MWMechanics } } + void AiWander::onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, + float duration, AiWanderStorage& storage, ESM::Position& pos) + { + // Are we there yet? + if (storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) + { + stopWalking(actor, storage); + storage.mState = Wander_ChooseAction; + mHasReturnPosition = false; + } + else + { + // have not yet reached the destination + //... turn towards the next point in mPath + zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); + actor.getClass().getMovementSettings(actor).mPosition[1] = 1; + + evadeObstacles(actor, storage, duration); + } + } + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) { if (mObstacleCheck.check(actor, duration)) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 92af5b717..4750df1dc 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -84,6 +84,7 @@ namespace MWMechanics void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); + void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 9c0e3d6c28bd66717d8cd385e5e9099a1a01ad56 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:25:44 +1200 Subject: [PATCH 152/419] extracted functions doPerFrameActionsForState() and onChooseActionStatePerFrameActions(). --- apps/openmw/mwmechanics/aiwander.cpp | 85 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 2 + 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 77cd9e137..e6d7d4422 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -193,39 +193,7 @@ namespace MWMechanics ESM::Position pos = actor.getRefData().getPosition(); - - WanderState& wanderState = storage.mState; - - if (wanderState == Wander_IdleNow) - { - onIdleStatePerFrameActions(actor, duration, storage); - } - - if (wanderState == Wander_Walking) - { - onWalkingStatePerFrameActions(actor, duration, storage, pos); - } - - MWBase::World *world = MWBase::Environment::get().getWorld(); - - if (wanderState == Wander_ChooseAction) - { - short unsigned& idleAnimation = storage.mIdleAnimation; - idleAnimation = getRandomIdle(); - - if(!idleAnimation && mDistance) - { - wanderState = Wander_MoveNow; - } - else - { - // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: - MWWorld::TimeStamp currentTime = world->getTimeStamp(); - mStartTime = currentTime; - playIdle(actor, idleAnimation); - wanderState = Wander_IdleNow; - } - } + doPerFrameActionsForState(actor, duration, storage, pos); playIdleDialogueRandomly(actor); @@ -243,7 +211,7 @@ namespace MWMechanics if(mDuration) { // End package if duration is complete or mid-night hits: - MWWorld::TimeStamp currentTime = world->getTimeStamp(); + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); if((currentTime.getHour() >= mStartTime.getHour() + mDuration) || (int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())) { @@ -288,12 +256,13 @@ namespace MWMechanics if(storage.mPathFinder.isPathConstructed()) { - wanderState = Wander_Walking; + storage.mState = Wander_Walking; } } } // Allow interrupting a walking actor to trigger a greeting + WanderState& wanderState = storage.mState; if ((wanderState == Wander_IdleNow) || (wanderState == Wander_Walking)) { playGreetingIfPlayerGetsTooClose(actor, storage); @@ -314,6 +283,32 @@ namespace MWMechanics return false; // AiWander package not yet completed } + void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) + { + switch (storage.mState) + { + case Wander_IdleNow: + onIdleStatePerFrameActions(actor, duration, storage); + break; + + case Wander_Walking: + onWalkingStatePerFrameActions(actor, duration, storage, pos); + break; + + case Wander_ChooseAction: + onChooseActionStatePerFrameActions(actor, storage); + break; + + case Wander_MoveNow: + break; // nothing to do + + default: + // should never get here + assert(false); + break; + } + } + void AiWander::onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage) { // Check if an idle actor is too close to a door - if so start walking @@ -369,6 +364,26 @@ namespace MWMechanics } } + void AiWander::onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage) + { + + short unsigned& idleAnimation = storage.mIdleAnimation; + idleAnimation = getRandomIdle(); + + if (!idleAnimation && mDistance) + { + storage.mState = Wander_MoveNow; + } + 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, idleAnimation); + storage.mState = Wander_IdleNow; + } + } + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) { if (mObstacleCheck.check(actor, duration)) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 4750df1dc..9b21415c4 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -83,8 +83,10 @@ namespace MWMechanics void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); + void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); + void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From ad0d8071037d4fda4e8b5151f5e6c9ec561d9af3 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:28:32 +1200 Subject: [PATCH 153/419] extracted function reactionTimeActions(). --- apps/openmw/mwmechanics/aiwander.cpp | 13 ++++++++----- apps/openmw/mwmechanics/aiwander.hpp | 2 ++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e6d7d4422..228f4b32d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -199,15 +199,18 @@ namespace MWMechanics float& lastReaction = storage.mReaction; lastReaction += duration; - if(lastReaction < REACTION_INTERVAL) + if (REACTION_INTERVAL <= lastReaction) { - return false; + lastReaction = 0; + return reactionTimeActions(actor, storage, currentCell, cellChange, pos); } else - lastReaction = 0; - - // NOTE: everything below get updated every REACTION_INTERVAL seconds + return false; + } + bool AiWander::reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, + const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos) + { if(mDuration) { // End package if duration is complete or mid-night hits: diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 9b21415c4..3468c212d 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -87,6 +87,8 @@ namespace MWMechanics void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage); + bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, + const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 5e519ef550abbceda13d501cccb83d07d1f1dba8 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:29:01 +1200 Subject: [PATCH 154/419] extract function isPackageFinished(). --- apps/openmw/mwmechanics/aiwander.cpp | 40 ++++++++++++++++++---------- apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 228f4b32d..ff26bc116 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -211,21 +211,9 @@ namespace MWMechanics bool AiWander::reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos) { - if(mDuration) + if (isPackageCompleted(actor, storage)) { - // End package if duration is complete or mid-night hits: - MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - if((currentTime.getHour() >= mStartTime.getHour() + mDuration) || - (int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())) - { - if(!mRepeat) - { - stopWalking(actor, storage); - return true; - } - else - mStartTime = currentTime; - } + return true; } // Initialization to discover & store allowed node points for this actor. @@ -286,6 +274,30 @@ namespace MWMechanics return false; // AiWander package not yet completed } + bool AiWander::isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage) + { + 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) || + (int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())) + { + if (!mRepeat) + { + stopWalking(actor, storage); + return true; + } + else + { + mStartTime = currentTime; + } + } + } + // if get here, not yet completed + return false; + } + void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) { switch (storage.mState) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 3468c212d..2364ac543 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -89,6 +89,7 @@ namespace MWMechanics void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage); bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos); + bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From c7aacaee706a9226ff947a038cdbae519920e708 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:29:32 +1200 Subject: [PATCH 155/419] extracted function returnToStartLocation(). --- apps/openmw/mwmechanics/aiwander.cpp | 38 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index ff26bc116..e230998eb 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -233,23 +233,10 @@ namespace MWMechanics // For stationary NPCs, move back to the starting location if another AiPackage moved us elsewhere if (cellChange) mHasReturnPosition = false; - if (mDistance == 0 && mHasReturnPosition && (pos.asVec3() - mReturnPosition).length2() > 20*20) + if (mDistance == 0 && mHasReturnPosition + && (pos.asVec3() - mReturnPosition).length2() > (DESTINATION_TOLERANCE * DESTINATION_TOLERANCE)) { - if (!storage.mPathFinder.isPathConstructed()) - { - ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition)); - - // actor position is already in world co-ordinates - ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); - - // don't take shortcuts for wandering - storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); - - if(storage.mPathFinder.isPathConstructed()) - { - storage.mState = Wander_Walking; - } - } + returnToStartLocation(actor, storage, pos); } // Allow interrupting a walking actor to trigger a greeting @@ -298,6 +285,25 @@ namespace MWMechanics return false; } + void AiWander::returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos) + { + if (!storage.mPathFinder.isPathConstructed()) + { + ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition)); + + // actor position is already in world co-ordinates + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); + + // don't take shortcuts for wandering + storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); + + if (storage.mPathFinder.isPathConstructed()) + { + storage.mState = Wander_Walking; + } + } + } + void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) { switch (storage.mState) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 2364ac543..8a489c783 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -90,6 +90,7 @@ namespace MWMechanics bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos); bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage); + void returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 04aee1fe20a1d742292ac09d0c162dc9a30c3de2 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:32:29 +1200 Subject: [PATCH 156/419] extracted function reactionTimeActions(). --- apps/openmw/mwmechanics/aicombat.cpp | 54 +++++++++++++++------------- apps/openmw/mwmechanics/aicombat.hpp | 5 ++- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 1beb0024c..fc1c31c26 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -45,6 +45,7 @@ namespace return -std::asin(dir.z() / len); } + const float REACTION_INTERVAL = 0.25f; const float PATHFIND_Z_REACH = 50.0f; // distance at which actor pays more attention to decide whether to shortcut or stick to pathgrid @@ -181,15 +182,11 @@ namespace MWMechanics // get or create temporary storage AiCombatStorage& storage = state.get(); - const MWWorld::Class& actorClass = actor.getClass(); - - //General description - if (actorClass.getCreatureStats(actor).isDead()) + if (actor.getClass().getCreatureStats(actor).isDead()) return true; - MWBase::World* world = MWBase::Environment::get().getWorld(); - MWWorld::Ptr target = world->searchPtrViaActorId(mTargetActorId); + MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); if (target.isEmpty()) return false; @@ -217,8 +214,6 @@ namespace MWMechanics UpdateActorsMovement(actor, movement); bool& attack = storage.mAttack; - bool& readyToAttack = storage.mReadyToAttack; - if (attack && (characterController.getAttackStrength() >= storage.mStrength || characterController.readyToPrepareAttack())) attack = false; @@ -228,14 +223,22 @@ namespace MWMechanics actionCooldown -= duration; float& timerReact = storage.mTimerReact; - float tReaction = 0.25f; - if(timerReact < tReaction) + if(timerReact < REACTION_INTERVAL) { timerReact += duration; return false; } + else + { + timerReact = 0; + return reactionTimeActions(actor, characterController, storage, target); + } + } - //Update with period = tReaction + bool AiCombat::reactionTimeActions(const MWWorld::Ptr& actor, CharacterController& characterController, + AiCombatStorage& storage, MWWorld::Ptr target) + { + MWMechanics::Movement& movement = storage.mMovement; // Stop attacking if target is not seen if (target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude() > 0 @@ -245,7 +248,6 @@ namespace MWMechanics return false; // TODO: run away instead of doing nothing } - timerReact = 0; const MWWorld::CellStore*& currentCell = storage.mCell; bool cellChange = currentCell && (actor.getCell() != currentCell); if(!currentCell || cellChange) @@ -253,8 +255,10 @@ namespace MWMechanics currentCell = actor.getCell(); } + const MWWorld::Class& actorClass = actor.getClass(); actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); + float& actionCooldown = storage.mActionCooldown; if (actionCooldown > 0) return false; @@ -276,6 +280,7 @@ namespace MWMechanics float weapRange = 1.0f; // Get weapon characteristics + MWBase::World* world = MWBase::Environment::get().getWorld(); if (actorClass.hasInventoryStore(actor)) { //Get weapon speed and range @@ -326,13 +331,14 @@ namespace MWMechanics float& strength = storage.mStrength; + bool& readyToAttack = storage.mReadyToAttack; // start new attack if(readyToAttack && characterController.readyToStartAttack()) { if (storage.mAttackCooldown <= 0) { - attack = true; // attack starts just now - characterController.setAttackingOrSpell(attack); + storage.mAttack = true; // attack starts just now + characterController.setAttackingOrSpell(true); if (!distantCombat) chooseBestAttack(weapon, movement); @@ -356,7 +362,7 @@ namespace MWMechanics storage.mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(), baseDelay + 0.9); } else - storage.mAttackCooldown -= tReaction; + storage.mAttackCooldown -= REACTION_INTERVAL; } @@ -400,7 +406,7 @@ namespace MWMechanics bool isStuck = false; float speed = 0.0f; - if(movement.mPosition[1] && (lastActorPos - vActorPos).length() < (speed = actorClass.getSpeed(actor)) * tReaction / 2) + if(movement.mPosition[1] && (lastActorPos - vActorPos).length() < (speed = actorClass.getSpeed(actor)) * REACTION_INTERVAL / 2) isStuck = true; lastActorPos = vActorPos; @@ -437,7 +443,7 @@ namespace MWMechanics if (distantCombat) { osg::Vec3f& lastTargetPos = storage.mLastTargetPos; - osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, tReaction, weaptype, strength); + osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, REACTION_INTERVAL, weaptype, strength); lastTargetPos = vTargetPos; movement.mRotation[0] = getXAngleToDir(vAimDir); movement.mRotation[2] = getZAngleToDir(vAimDir); @@ -458,8 +464,8 @@ namespace MWMechanics { if(movement.mPosition[0] || movement.mPosition[1]) { - timerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); - combatMove = true; + storage.mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); + storage.mCombatMove = true; } // only NPCs are smart enough to use dodge movements else if(actorClass.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeAttack/2))) @@ -468,8 +474,8 @@ namespace MWMechanics if (Misc::Rng::rollClosedProbability() < 0.25) { movement.mPosition[0] = Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; - timerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability(); - combatMove = true; + storage.mTimerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability(); + storage.mCombatMove = true; } } @@ -497,7 +503,7 @@ namespace MWMechanics { if(speed == 0.0f) speed = actorClass.getSpeed(actor); // maximum dist before pit/obstacle for actor to avoid them depending on his speed - float maxAvoidDist = tReaction * speed + speed / MAX_VEL_ANGULAR_RADIANS * 2; // *2 - for reliability + float maxAvoidDist = REACTION_INTERVAL * speed + speed / MAX_VEL_ANGULAR_RADIANS * 2; // *2 - for reliability preferShortcut = checkWayIsClear(vActorPos, vTargetPos, osg::Vec3f(vDirToTarget.x(), vDirToTarget.y(), 0).length() > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); } @@ -558,8 +564,8 @@ namespace MWMechanics if (readyToAttack) { // to stop possible sideway moving after target moved out of attack range - combatMove = true; - timerCombatMove = 0; + storage.mCombatMove = true; + storage.mTimerCombatMove = 0; } readyToAttack = false; } diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index c81ad0544..4e4060819 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -26,6 +26,8 @@ namespace MWMechanics { class Action; + struct AiCombatStorage; + /// \brief Causes the actor to fight another actor class AiCombat : public AiPackage { @@ -58,8 +60,9 @@ namespace MWMechanics int mTargetActorId; - void buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); + bool reactionTimeActions(const MWWorld::Ptr& actor, CharacterController& characterController, + AiCombatStorage& storage, MWWorld::Ptr target); /// Transfer desired movement (from AiCombatStorage) to Actor void UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& movement); From 6a1e1a07cbb52250cdd6b0c73c574e3f98b55862 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 26 Jul 2015 11:02:22 +0200 Subject: [PATCH 157/419] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index def0b2b89..291b0d56c 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -88,6 +88,7 @@ Programmers Nolan Poe (nopoe) Paul McElroy (Greendogo) Pieter van der Kloet (pvdk) + pkubik Radu-Marius Popovici (rpopovici) rdimesio riothamus From 37fd733debc8c8d98220a6a920b14328ec5ab038 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 26 Jul 2015 20:06:30 +0300 Subject: [PATCH 158/419] Create a custom signal to inform about a row addition in IdTableProxyModel --- apps/opencs/model/world/idtableproxymodel.cpp | 53 ++++++++++++------- apps/opencs/model/world/idtableproxymodel.hpp | 20 +++++-- 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index ce9d44ed6..8beccd497 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -7,23 +7,23 @@ void CSMWorld::IdTableProxyModel::updateColumnMap() { - mColumnMap.clear(); + Q_ASSERT(mSourceModel != NULL); + mColumnMap.clear(); if (mFilter) { std::vector columns = mFilter->getReferencedColumns(); - - const IdTableBase& table = dynamic_cast (*sourceModel()); - for (std::vector::const_iterator iter (columns.begin()); iter!=columns.end(); ++iter) - mColumnMap.insert (std::make_pair (*iter, - table.searchColumnIndex (static_cast (*iter)))); + mColumnMap.insert (std::make_pair (*iter, + mSourceModel->searchColumnIndex (static_cast (*iter)))); } } bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const { + Q_ASSERT(mSourceModel != NULL); + // It is not possible to use filterAcceptsColumn() and check for // sourceModel()->headerData (sourceColumn, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags) // because the sourceColumn parameter excludes the hidden columns, i.e. wrong columns can @@ -35,34 +35,37 @@ bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelI if (!mFilter) return true; - return mFilter->test ( - dynamic_cast (*sourceModel()), sourceRow, mColumnMap); + return mFilter->test (*mSourceModel, sourceRow, mColumnMap); } CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) -: QSortFilterProxyModel (parent) + : QSortFilterProxyModel (parent), + mSourceModel(NULL) { setSortCaseSensitivity (Qt::CaseInsensitive); } QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const { - return mapFromSource (dynamic_cast (*sourceModel()).getModelIndex (id, column)); + Q_ASSERT(mSourceModel != NULL); + + return mapFromSource(mSourceModel->getModelIndex (id, column)); } void CSMWorld::IdTableProxyModel::setSourceModel(QAbstractItemModel *model) { QSortFilterProxyModel::setSourceModel(model); - connect(sourceModel(), - SIGNAL(rowsRemoved(const QModelIndex &, int, int)), - this, - SLOT(sourceRowsChanged(const QModelIndex &, int, int))); - connect(sourceModel(), + mSourceModel = dynamic_cast(sourceModel()); + connect(mSourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, - SLOT(sourceRowsChanged(const QModelIndex &, int, int))); - connect(sourceModel(), + SLOT(sourceRowsInserted(const QModelIndex &, int, int))); + connect(mSourceModel, + SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, + SLOT(sourceRowsRemoved(const QModelIndex &, int, int))); + connect(mSourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &))); @@ -95,13 +98,27 @@ bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModel return QSortFilterProxyModel::lessThan(left, right); } +QString CSMWorld::IdTableProxyModel::getRecordId(int sourceRow) const +{ + Q_ASSERT(mSourceModel != NULL); + + int idColumn = mSourceModel->findColumnIndex(Columns::ColumnId_Id); + return mSourceModel->data(mSourceModel->index(sourceRow, idColumn)).toString(); +} + void CSMWorld::IdTableProxyModel::refreshFilter() { updateColumnMap(); invalidateFilter(); } -void CSMWorld::IdTableProxyModel::sourceRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) +void CSMWorld::IdTableProxyModel::sourceRowsInserted(const QModelIndex &/*parent*/, int /*start*/, int end) +{ + refreshFilter(); + emit rowAdded(getRecordId(end).toUtf8().constData()); +} + +void CSMWorld::IdTableProxyModel::sourceRowsRemoved(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) { refreshFilter(); } diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp index 17c30361a..cf31b5c11 100644 --- a/apps/opencs/model/world/idtableproxymodel.hpp +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -27,6 +27,10 @@ namespace CSMWorld typedef std::map > EnumColumnCache; mutable EnumColumnCache mEnumColumnCache; + protected: + + IdTableBase *mSourceModel; + private: void updateColumnMap(); @@ -45,15 +49,23 @@ namespace CSMWorld protected: - bool lessThan(const QModelIndex &left, const QModelIndex &right) const; + virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; virtual bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const; - private slots: + QString getRecordId(int sourceRow) const; - void sourceRowsChanged(const QModelIndex &parent, int start, int end); + protected slots: - void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + virtual void sourceRowsInserted(const QModelIndex &parent, int start, int end); + + virtual void sourceRowsRemoved(const QModelIndex &parent, int start, int end); + + virtual void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + + signals: + + void rowAdded(const std::string &id); }; } From 86b7d2a43d2842eaab0938afbab699dcce4684e0 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 26 Jul 2015 20:07:36 +0300 Subject: [PATCH 159/419] Inform about a row addition after re-sorting in InfoTableProxyModel --- .../model/world/infotableproxymodel.cpp | 56 ++++++++++++++----- .../model/world/infotableproxymodel.hpp | 12 ++-- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index 6216291d0..c6216ba5d 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -9,16 +9,17 @@ namespace { QString toLower(const QString &str) { - return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toStdString()).c_str()); + return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toUtf8().constData()).c_str()); } } CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent) : IdTableProxyModel(parent), mType(type), - mSourceModel(NULL), mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic : - Columns::ColumnId_Journal) + Columns::ColumnId_Journal), + mInfoColumnIndex(-1), + mLastAddedSourceRow(-1) { Q_ASSERT(type == UniversalId::Type_TopicInfos || type == UniversalId::Type_JournalInfos); } @@ -26,23 +27,18 @@ CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type t void CSMWorld::InfoTableProxyModel::setSourceModel(QAbstractItemModel *sourceModel) { IdTableProxyModel::setSourceModel(sourceModel); - mSourceModel = dynamic_cast(sourceModel); + if (mSourceModel != NULL) { - connect(mSourceModel, - SIGNAL(rowsInserted(const QModelIndex &, int, int)), - this, - SLOT(modelRowsChanged(const QModelIndex &, int, int))); - connect(mSourceModel, - SIGNAL(rowsRemoved(const QModelIndex &, int, int)), - this, - SLOT(modelRowsChanged(const QModelIndex &, int, int))); + mInfoColumnIndex = mSourceModel->findColumnIndex(mInfoColumnId); mFirstRowCache.clear(); } } bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { + Q_ASSERT(mSourceModel != NULL); + QModelIndex first = mSourceModel->index(getFirstInfoRow(left.row()), left.column()); QModelIndex second = mSourceModel->index(getFirstInfoRow(right.row()), right.column()); @@ -56,8 +52,10 @@ bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QMod int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const { + Q_ASSERT(mSourceModel != NULL); + int row = currentRow; - int column = mSourceModel->findColumnIndex(mInfoColumnId); + int column = mInfoColumnIndex; QString info = toLower(mSourceModel->data(mSourceModel->index(row, column)).toString()); if (mFirstRowCache.contains(info)) @@ -73,7 +71,37 @@ int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const return row; } -void CSMWorld::InfoTableProxyModel::modelRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) +void CSMWorld::InfoTableProxyModel::sourceRowsRemoved(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) { + refreshFilter(); mFirstRowCache.clear(); } + +void CSMWorld::InfoTableProxyModel::sourceRowsInserted(const QModelIndex &/*parent*/, int /*start*/, int end) +{ + refreshFilter(); + mFirstRowCache.clear(); + // We can't re-sort the model here, because the topic of the added row isn't set yet. + // Store the row index for using in the first dataChanged() after this row insertion. + mLastAddedSourceRow = end; +} + +void CSMWorld::InfoTableProxyModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) +{ + refreshFilter(); + + if (mLastAddedSourceRow != -1 && + topLeft.row() <= mLastAddedSourceRow && bottomRight.row() >= mLastAddedSourceRow) + { + // Now the topic of the last added row is set, + // so we can re-sort the model to ensure the corrent position of this row + int column = sortColumn(); + Qt::SortOrder order = sortOrder(); + sort(mInfoColumnIndex); // Restore the correct position of an added row + sort(column, order); // Restore the original sort order + emit rowAdded(getRecordId(mLastAddedSourceRow).toUtf8().constData()); + + // Make sure that we perform a re-sorting only in the first dataChanged() after a row insertion + mLastAddedSourceRow = -1; + } +} diff --git a/apps/opencs/model/world/infotableproxymodel.hpp b/apps/opencs/model/world/infotableproxymodel.hpp index 28d6017b3..51d93f9a1 100644 --- a/apps/opencs/model/world/infotableproxymodel.hpp +++ b/apps/opencs/model/world/infotableproxymodel.hpp @@ -16,25 +16,29 @@ namespace CSMWorld Q_OBJECT UniversalId::Type mType; - IdTableBase *mSourceModel; Columns::ColumnId mInfoColumnId; ///< Contains ID for Topic or Journal ID + int mInfoColumnIndex; + int mLastAddedSourceRow; mutable QHash mFirstRowCache; int getFirstInfoRow(int currentRow) const; ///< Finds the first row with the same topic (journal entry) as in \a currentRow + ///< \a currentRow is a row of the source model. public: InfoTableProxyModel(UniversalId::Type type, QObject *parent = 0); - void setSourceModel(QAbstractItemModel *sourceModel); + virtual void setSourceModel(QAbstractItemModel *sourceModel); protected: virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; - private slots: - void modelRowsChanged(const QModelIndex &parent, int start, int end); + protected slots: + virtual void sourceRowsInserted(const QModelIndex &parent, int start, int end); + virtual void sourceRowsRemoved(const QModelIndex &parent, int start, int end); + virtual void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); }; } From 2471e4d67a343ef8f64eb324feb08c8629f9d673 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 26 Jul 2015 20:09:31 +0300 Subject: [PATCH 160/419] Rework Table to use rowAdded() signal of a proxy model --- apps/opencs/view/world/table.cpp | 11 +++++++---- apps/opencs/view/world/table.hpp | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 5a2a572e2..02a9bb07f 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -371,8 +371,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, connect (mProxyModel, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), this, SLOT (tableSizeUpdate())); - connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)), - this, SLOT (rowsInsertedEvent(const QModelIndex&, int, int))); + //connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)), + // this, SLOT (rowsInsertedEvent(const QModelIndex&, int, int))); + connect (mProxyModel, SIGNAL (rowAdded (const std::string &)), + this, SLOT (rowAdded (const std::string &))); /// \note This signal could instead be connected to a slot that filters out changes not affecting /// the records status column (for permanence reasons) @@ -714,12 +716,13 @@ std::vector< CSMWorld::UniversalId > CSVWorld::Table::getDraggedRecords() const return idToDrag; } -void CSVWorld::Table::rowsInsertedEvent(const QModelIndex& parent, int start, int end) +void CSVWorld::Table::rowAdded(const std::string &id) { tableSizeUpdate(); if(mJumpToAddedRecord) { - selectRow(end); + int idColumn = mModel->findColumnIndex(CSMWorld::Columns::ColumnId_Id); + selectRow(mProxyModel->getModelIndex(id, idColumn).row()); if(mUnselectAfterJump) clearSelection(); diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index adacd3a9d..7ddeff0a5 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -140,7 +140,7 @@ namespace CSVWorld void updateUserSetting (const QString &name, const QStringList &list); - void rowsInsertedEvent(const QModelIndex& parent, int start, int end); + void rowAdded(const std::string &id); }; } From 812fffbadcc4ef8c69cf7382ab0e4c8939a8ef9f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 26 Jul 2015 20:25:46 +0300 Subject: [PATCH 161/419] Don't inform about a nested row addition in proxy models for top-level tables --- apps/opencs/model/world/idtableproxymodel.cpp | 7 +++++-- apps/opencs/model/world/infotableproxymodel.cpp | 14 +++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 8beccd497..10fd92b46 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -112,10 +112,13 @@ void CSMWorld::IdTableProxyModel::refreshFilter() invalidateFilter(); } -void CSMWorld::IdTableProxyModel::sourceRowsInserted(const QModelIndex &/*parent*/, int /*start*/, int end) +void CSMWorld::IdTableProxyModel::sourceRowsInserted(const QModelIndex &parent, int /*start*/, int end) { refreshFilter(); - emit rowAdded(getRecordId(end).toUtf8().constData()); + if (!parent.isValid()) + { + emit rowAdded(getRecordId(end).toUtf8().constData()); + } } void CSMWorld::IdTableProxyModel::sourceRowsRemoved(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index c6216ba5d..f55f775ab 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -77,13 +77,17 @@ void CSMWorld::InfoTableProxyModel::sourceRowsRemoved(const QModelIndex &/*paren mFirstRowCache.clear(); } -void CSMWorld::InfoTableProxyModel::sourceRowsInserted(const QModelIndex &/*parent*/, int /*start*/, int end) +void CSMWorld::InfoTableProxyModel::sourceRowsInserted(const QModelIndex &parent, int /*start*/, int end) { refreshFilter(); - mFirstRowCache.clear(); - // We can't re-sort the model here, because the topic of the added row isn't set yet. - // Store the row index for using in the first dataChanged() after this row insertion. - mLastAddedSourceRow = end; + + if (!parent.isValid()) + { + mFirstRowCache.clear(); + // We can't re-sort the model here, because the topic of the added row isn't set yet. + // Store the row index for using in the first dataChanged() after this row insertion. + mLastAddedSourceRow = end; + } } void CSMWorld::InfoTableProxyModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) From ac1f64b5593f742fe34017dd07077a6c0da71956 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 28 Jul 2015 03:20:18 +0200 Subject: [PATCH 162/419] Fix StencilProperty front face mixup (Fixes #2802) --- components/nifosg/nifloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b5439afee..6824c0afd 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1159,11 +1159,11 @@ namespace NifOsg osg::FrontFace* frontFace = new osg::FrontFace; switch (stencilprop->data.drawMode) { - case 1: + case 2: frontFace->setMode(osg::FrontFace::CLOCKWISE); break; case 0: - case 2: + case 1: default: frontFace->setMode(osg::FrontFace::COUNTER_CLOCKWISE); break; From 26656707dd16a0ffd1be105ce3b34cdb0d55b8c4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 27 Jul 2015 22:59:20 +0200 Subject: [PATCH 163/419] Use marker_error.nif as replacement when a mesh fails to load --- components/resource/scenemanager.cpp | 15 ++++++++++++--- components/resource/scenemanager.hpp | 4 ++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index efaccec13..08fa7bc9b 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -100,11 +100,20 @@ namespace Resource Index::iterator it = mIndex.find(normalized); if (it == mIndex.end()) { - Files::IStreamPtr file = mVFS->get(normalized); - // TODO: add support for non-NIF formats + osg::ref_ptr loaded; + try + { + Files::IStreamPtr file = mVFS->get(normalized); - osg::ref_ptr loaded = NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + loaded = NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + } + catch (std::exception& e) + { + std::cerr << "Failed to load '" << name << "': " << e.what() << ", using marker_error.nif instead" << std::endl; + Files::IStreamPtr file = mVFS->get("meshes/marker_error.nif"); + loaded = NifOsg::Loader::load(Nif::NIFFilePtr(new Nif::NIFFile(file, normalized)), mTextureManager); + } osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get()); // TODO: run SharedStateManager::prune on unload diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 1dabe45e0..168247a15 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -38,12 +38,16 @@ namespace Resource ~SceneManager(); /// Get a read-only copy of this scene "template" + /// @note If the given filename does not exist or fails to load, an error marker mesh will be used instead. + /// If even the error marker mesh can not be found, an exception is thrown. osg::ref_ptr getTemplate(const std::string& name); /// Create an instance of the given scene template + /// @see getTemplate osg::ref_ptr createInstance(const std::string& name); /// Create an instance of the given scene template and immediately attach it to a parent node + /// @see getTemplate osg::ref_ptr createInstance(const std::string& name, osg::Group* parentNode); /// Attach the given scene instance to the given parent node From 7ba399fc92fd676a0c1f896fa9521c4d9acdea8a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 27 Jul 2015 23:19:35 +0200 Subject: [PATCH 164/419] Change a message to upper case spelling More consistent with other loading messages --- apps/openmw/mwworld/scene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 9ffc4071d..48e346c14 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -233,7 +233,7 @@ namespace MWWorld if(result.second) { - std::cout << "loading cell " << cell->getCell()->getDescription() << std::endl; + std::cout << "Loading cell " << cell->getCell()->getDescription() << std::endl; float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; From 2a653e45fd443fa58702f3505115aad713a00018 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Tue, 21 Jul 2015 22:08:37 -0400 Subject: [PATCH 165/419] (Re) Wrote a tool to test NIF files in BSAs and on the filesystem. Just give it a set of files, one file per argument, and it will make sure openmw can read them. --- CMakeLists.txt | 8 ++++ apps/niftest/CMakeLists.txt | 19 ++++++++ apps/niftest/find_bad_nifs.sh | 28 +++++++++++ apps/niftest/niftest.cpp | 87 +++++++++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+) create mode 100644 apps/niftest/CMakeLists.txt create mode 100755 apps/niftest/find_bad_nifs.sh create mode 100644 apps/niftest/niftest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 656602b9e..a14beb423 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,7 @@ option(BUILD_OPENCS "build OpenMW Construction Set" ON) option(BUILD_WIZARD "build Installation Wizard" ON) option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF) +option(BUILD_NIFTEST "build nif file tester" OFF) option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON) # OS X deployment @@ -396,6 +397,9 @@ IF(NOT WIN32 AND NOT APPLE) IF(BUILD_ESMTOOL) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) ENDIF(BUILD_ESMTOOL) + IF(BUILD_NIFTEST) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_NIFTEST) IF(BUILD_MWINIIMPORTER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-iniimporter" DESTINATION "${BINDIR}" ) ENDIF(BUILD_MWINIIMPORTER) @@ -581,6 +585,10 @@ if (BUILD_WIZARD) add_subdirectory(apps/wizard) endif() +if (BUILD_NIFTEST) + add_subdirectory(apps/niftest) +endif(BUILD_NIFTEST) + # UnitTests if (BUILD_UNITTESTS) add_subdirectory( apps/openmw_test_suite ) diff --git a/apps/niftest/CMakeLists.txt b/apps/niftest/CMakeLists.txt new file mode 100644 index 000000000..d7f0200d2 --- /dev/null +++ b/apps/niftest/CMakeLists.txt @@ -0,0 +1,19 @@ +set(NIFTEST + niftest.cpp +) +source_group(components\\nif\\tests FILES ${NIFTEST}) + +# Main executable +add_executable(niftest + ${NIFTEST} +) + +target_link_libraries(niftest + ${Boost_FILESYSTEM_LIBRARY} + components +) + +if (BUILD_WITH_CODE_COVERAGE) + add_definitions (--coverage) + target_link_libraries(niftest gcov) +endif() diff --git a/apps/niftest/find_bad_nifs.sh b/apps/niftest/find_bad_nifs.sh new file mode 100755 index 000000000..4b599f442 --- /dev/null +++ b/apps/niftest/find_bad_nifs.sh @@ -0,0 +1,28 @@ +#!/bin/bash +#Script to test all nif files (both loose, and in BSA archives) in data files directory + +#The user input as an absolute path +DATAFILESDIR="`readlink -m "$1"`" +#Program used to test +TEST_PROG="`pwd`/niftest" + +#Make sure our files don't bother anyone +NIFTEST_TMP_DIR="/tmp/niftest_$RANDOM/" +mkdir "$NIFTEST_TMP_DIR" +cd "$NIFTEST_TMP_DIR" + +find "$DATAFILESDIR" -iname *bsa > nifs.txt +find "$DATAFILESDIR" -iname *nif >> nifs.txt + +sed -e 's/.*/\"&\"/' nifs.txt > quoted_nifs.txt + +xargs --arg-file=quoted_nifs.txt "$TEST_PROG" 2>&1 | tee nif_out.txt +# xargs --arg-file=quoted_nifs.txt "$TEST_PROG" 2> nif_out.txt >/dev/null + +echo "List of bad NIF Files:" +cat nif_out.txt|grep File:|cut -d ' ' -f 2- + +rm nifs.txt +rm quoted_nifs.txt +rm nif_out.txt +rmdir "$NIFTEST_TMP_DIR" diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp new file mode 100644 index 000000000..20c8597f3 --- /dev/null +++ b/apps/niftest/niftest.cpp @@ -0,0 +1,87 @@ +///Program to test .nif files both on the FileSystem and in BSA archives. + +#include +#include + +#include +#include +#include +#include + + +///See if the file has the named extension +bool hasExtension(std::string filename, std::string extensionToFind) +{ + std::string extension = filename.substr(filename.find_last_of(".")+1); + + //Convert strings to lower case for comparison + std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); + std::transform(extensionToFind.begin(), extensionToFind.end(), extensionToFind.begin(), ::tolower); + + if(extension == extensionToFind) + return true; + else + return false; +} + +///See if the file has the "nif" extension. +bool isNIF(std::string filename) +{ + return hasExtension(filename,"nif"); +} +///See if the file has the "bsa" extension. +bool isBSA(std::string filename) +{ + return hasExtension(filename,"bsa"); +} + +///Check all the nif files in the given BSA archive +void readBSA(std::string filename) +{ + VFS::Manager myManager(false); + myManager.addArchive(new VFS::BsaArchive(filename)); + myManager.buildIndex(); + + std::map files=myManager.getIndex(); + for(std::map::const_iterator it=files.begin(); it!=files.end(); ++it) + { + std::string name = it->first; + if(isNIF(name)) + { +// std::cout << "Decoding: " << name << std::endl; + Nif::NIFFile temp_nif(myManager.get(name),name); + } + } +} + +int main(int argc, char **argv) +{ + + std::cout << "Reading Files" << std::endl; + for(int i = 1; i Date: Tue, 28 Jul 2015 23:34:36 +0200 Subject: [PATCH 166/419] Remove a file that isn't in use yet from build --- components/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index cf0c83fbd..946c3af16 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -41,7 +41,9 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry lightcontroller workqueue + clone attach lightmanager visitor util statesetupdater controller skeleton riggeometry lightcontroller + # not used yet + #workqueue ) add_component_dir (nif From d7ad0ee14895c1aba8168fef40494bb0fb0ef61c Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 28 Jul 2015 23:35:10 +0200 Subject: [PATCH 167/419] Print a sensible error message when S3TC support is missing (Fixes #2800) --- components/resource/texturemanager.cpp | 33 +++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 87431ffcd..4bd712ea5 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -1,6 +1,7 @@ #include "texturemanager.hpp" #include +#include #include @@ -73,7 +74,7 @@ namespace Resource { osg::ref_ptr tex = it->second; - // Keep mip-mapping disabled if the texture creator explicitely requested it. + // Keep mip-mapping disabled if the texture creator explicitely requested no mipmapping. osg::Texture::FilterMode oldMin = tex->getFilter(osg::Texture::MIN_FILTER); if (oldMin == osg::Texture::LINEAR || oldMin == osg::Texture::NEAREST) { @@ -108,6 +109,32 @@ namespace Resource } */ + bool checkSupported(osg::Image* image, const std::string& filename) + { + switch(image->getPixelFormat()) + { + case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT): + case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT): + case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): + case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): + { + osg::Texture::Extensions* exts = osg::Texture::getExtensions(0, false); + if (exts && !exts->isTextureCompressionS3TCSupported() + // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. + && !osg::isGLExtensionSupported(0, "GL_S3_s3tc")) + { + std::cerr << "Error loading " << filename << ": no S3TC texture compression support installed" << std::endl; + return false; + } + break; + } + // not bothering with checks for other compression formats right now, we are unlikely to ever use those anyway + default: + return true; + } + return true; + } + osg::ref_ptr TextureManager::getTexture2D(const std::string &filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT) { std::string normalized = filename; @@ -152,6 +179,10 @@ namespace Resource } osg::Image* image = result.getImage(); + if (!checkSupported(image, filename)) + { + return mWarningTexture; + } // We need to flip images, because the Morrowind texture coordinates use the DirectX convention (top-left image origin), // but OpenGL uses bottom left as the image origin. From 2d93a6f6cb906dea5a4207cd65d786a5dcfc8fc0 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Tue, 28 Jul 2015 18:46:11 -0400 Subject: [PATCH 168/419] Be more verbose when dealing with unhandled nif texture properties --- components/nifosg/nifloader.cpp | 35 ++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 6824c0afd..c98008394 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -903,7 +903,7 @@ namespace NifOsg int uvSet = *it; if (uvSet >= (int)data->uvlist.size()) { - std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape " << triShape->name << " in " << mFilename << std::endl; + std::cerr << "Warning: using an undefined UV set " << uvSet << " on TriShape \"" << triShape->name << "\" in " << mFilename << std::endl; continue; } @@ -1264,13 +1264,34 @@ namespace NifOsg { if (texprop->textures[i].inUse) { - if (i != Nif::NiTexturingProperty::BaseTexture - && i != Nif::NiTexturingProperty::GlowTexture - && i != Nif::NiTexturingProperty::DarkTexture - && i != Nif::NiTexturingProperty::DetailTexture) + switch(i) { - std::cerr << "Warning: unhandled texture stage " << i << " in " << mFilename << std::endl; - continue; + //These are handled later on + case Nif::NiTexturingProperty::BaseTexture: + case Nif::NiTexturingProperty::GlowTexture: + case Nif::NiTexturingProperty::DarkTexture: + case Nif::NiTexturingProperty::DetailTexture: + break; + case Nif::NiTexturingProperty::GlossTexture: + { + std::cerr << "NiTexturingProperty::GlossTexture in " << mFilename << " not currently used." << std::endl; + continue; + } + case Nif::NiTexturingProperty::BumpTexture: + { + std::cerr << "NiTexturingProperty::BumpTexture in " << mFilename << " not currently used." << std::endl; + continue; + } + case Nif::NiTexturingProperty::DecalTexture: + { + std::cerr << "NiTexturingProperty::DecalTexture in " << mFilename << " not currently used." << std::endl; + continue; + } + default: + { + std::cerr << "Warning: unhandled texture stage " << i << " in " << mFilename << std::endl; + continue; + } } const Nif::NiTexturingProperty::Texture& tex = texprop->textures[i]; From 20106bb90f4c21ba47d28db0675ad5292107df7f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 29 Jul 2015 14:45:56 +0200 Subject: [PATCH 169/419] allow keywords in quotes (Fixes #2794) --- components/compiler/scanner.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 83d435962..de7f7e1e1 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -281,8 +281,10 @@ namespace Compiler if (name.size()>=2 && name[0]=='"' && name[name.size()-1]=='"') { name = name.substr (1, name.size()-2); - cont = parser.parseName (name, loc, *this); - return true; +// allow keywords enclosed in "" +/// \todo optionally disable +// cont = parser.parseName (name, loc, *this); +// return true; } int i = 0; From 24ba54f4feb65161e306cba91b3270aa6efcdbfb Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 29 Jul 2015 23:57:45 -0500 Subject: [PATCH 170/419] Implement accurate moon settings (fixes #672) --- apps/openmw/mwrender/sky.cpp | 162 ++++++++------------ apps/openmw/mwrender/sky.hpp | 37 +++-- apps/openmw/mwworld/weather.cpp | 264 ++++++++++++++++++++------------ apps/openmw/mwworld/weather.hpp | 35 ++++- 4 files changed, 290 insertions(+), 208 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 49c00c33d..cf20bc4c6 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1,5 +1,8 @@ #include "sky.hpp" +#define _USE_MATH_DEFINES +#include + #include #include #include @@ -383,26 +386,29 @@ public: Moon(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor, Type type) : CelestialBody(parentNode, sceneManager, scaleFactor, 2) , mType(type) - , mPhase(Phase_Unspecified) + , mPhase(MoonState::Phase_Unspecified) { mUpdater = new MoonUpdater; mGeode->addUpdateCallback(mUpdater); - setPhase(Phase_WaxingCrescent); + setPhase(MoonState::Phase_Full); + setVisible(true); } - enum Phase + void setState(const MoonState& state) { - Phase_New = 0, - Phase_WaxingCrescent, - Phase_WaxingHalf, - Phase_WaxingGibbous, - Phase_Full, - Phase_WaningGibbous, - Phase_WaningHalf, - Phase_WaningCrescent, - Phase_Unspecified - }; + float radsX = ((state.mRotationFromHorizon) * M_PI) / 180.0f; + float radsY = 0; + float radsZ = ((state.mRotationFromNorth) * M_PI) / 180.0f; + + osg::Quat rotation(radsX, osg::Vec3f(1.0f, 0.0f, 0.0f), + radsY, osg::Vec3f(0.0f, 1.0f, 0.0f), + radsZ, osg::Vec3f(0.0f, 0.0f, 1.0f)); + setDirection(rotation * osg::Vec3f(0.0f, 1.0f, 0.0f)); + setPhase(state.mPhase); + setTransparency(state.mMoonAlpha); + setShadowBlend(state.mShadowBlend); + } void setTextures(const std::string& phaseTex, const std::string& circleTex) { @@ -415,7 +421,7 @@ public: mUpdater->setTextures(phaseTexPtr, circleTexPtr); } - void setPhase(const Phase& phase) + void setPhase(const MoonState::Phase& phase) { if (mPhase == phase) return; @@ -426,14 +432,14 @@ public: if (mType == Moon::Type_Secunda) textureName += "secunda_"; else textureName += "masser_"; - if (phase == Moon::Phase_New) textureName += "new"; - else if (phase == Moon::Phase_WaxingCrescent) textureName += "one_wax"; - else if (phase == Moon::Phase_WaxingHalf) textureName += "half_wax"; - else if (phase == Moon::Phase_WaxingGibbous) textureName += "three_wax"; - else if (phase == Moon::Phase_WaningCrescent) textureName += "one_wan"; - else if (phase == Moon::Phase_WaningHalf) textureName += "half_wan"; - else if (phase == Moon::Phase_WaningGibbous) textureName += "three_wan"; - else if (phase == Moon::Phase_Full) textureName += "full"; + if (phase == MoonState::Phase_New) textureName += "new"; + else if (phase == MoonState::Phase_WaxingCrescent) textureName += "one_wax"; + else if (phase == MoonState::Phase_FirstQuarter) textureName += "half_wax"; + else if (phase == MoonState::Phase_WaxingGibbous) textureName += "three_wax"; + else if (phase == MoonState::Phase_WaningCrescent) textureName += "one_wan"; + else if (phase == MoonState::Phase_ThirdQuarter) textureName += "half_wan"; + else if (phase == MoonState::Phase_WaningGibbous) textureName += "three_wan"; + else if (phase == MoonState::Phase_Full) textureName += "full"; textureName += ".dds"; @@ -452,7 +458,8 @@ public: { public: MoonUpdater() - : mFade(0.f) + : mTransparency(1.0f) + , mShadowBlend(1.0f) , mMoonColor(1,1,1,1) { } @@ -464,7 +471,7 @@ public: texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); - texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // fade * MoonRedColor + texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // mShadowBlend * mMoonColor stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); @@ -475,7 +482,7 @@ public: texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); - texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // atmospherecolor + texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // mAtmosphereColor.rgb, mTransparency stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); @@ -484,21 +491,20 @@ public: virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) { osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); - texEnv->setConstantColor(mMoonColor * mFade); + texEnv->setConstantColor(mMoonColor * mShadowBlend); osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); - const float backdropFadeThreshold = 0.03; - if (mFade <= backdropFadeThreshold) - { - texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mFade / backdropFadeThreshold)); - } - else - texEnv2->setConstantColor(mAtmosphereColor); + texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency)); } - void setFade (const float fade) + void setTransparency(const float ratio) { - mFade = fade; + mTransparency = ratio; + } + + void setShadowBlend(const float blendFactor) + { + mShadowBlend = blendFactor; } void setAtmosphereColor(const osg::Vec4f& color) @@ -519,7 +525,8 @@ public: } private: - float mFade; + float mTransparency; + float mShadowBlend; osg::Vec4f mAtmosphereColor; osg::Vec4f mMoonColor; osg::ref_ptr mPhaseTex; @@ -537,27 +544,32 @@ public: mUpdater->setMoonColor(color); } - void setFade(const float fade) + void setTransparency(const float ratio) { - mUpdater->setFade(fade); + mUpdater->setTransparency(ratio); + } + + void setShadowBlend(const float blendFactor) + { + mUpdater->setShadowBlend(blendFactor); } unsigned int getPhaseInt() const { - if (mPhase == Moon::Phase_New) return 0; - else if (mPhase == Moon::Phase_WaxingCrescent) return 1; - else if (mPhase == Moon::Phase_WaningCrescent) return 1; - else if (mPhase == Moon::Phase_WaxingHalf) return 2; - else if (mPhase == Moon::Phase_WaningHalf) return 2; - else if (mPhase == Moon::Phase_WaxingGibbous) return 3; - else if (mPhase == Moon::Phase_WaningGibbous) return 3; - else if (mPhase == Moon::Phase_Full) return 4; + if (mPhase == MoonState::Phase_New) return 0; + else if (mPhase == MoonState::Phase_WaxingCrescent) return 1; + else if (mPhase == MoonState::Phase_WaningCrescent) return 1; + else if (mPhase == MoonState::Phase_FirstQuarter) return 2; + else if (mPhase == MoonState::Phase_ThirdQuarter) return 2; + else if (mPhase == MoonState::Phase_WaxingGibbous) return 3; + else if (mPhase == MoonState::Phase_WaningGibbous) return 3; + else if (mPhase == MoonState::Phase_Full) return 4; return 0; } private: Type mType; - Phase mPhase; + MoonState::Phase mPhase; osg::ref_ptr mUpdater; }; @@ -886,10 +898,6 @@ void SkyManager::update(float duration) mCloudUpdater->setAnimationTimer(mCloudAnimationTimer); mCloudUpdater2->setAnimationTimer(mCloudAnimationTimer); - /// \todo improve this - mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); - mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); - if (mSunEnabled) { // take 1/10 sec for fading the glare effect from invisible to full @@ -1128,46 +1136,18 @@ void SkyManager::setSunDirection(const osg::Vec3f& direction) //mSunGlare->setPosition(direction); } -void SkyManager::setMasserDirection(const osg::Vec3f& direction) +void SkyManager::setMasserState(const MoonState& state) { - if (!mCreated) return; + if(!mCreated) return; - mMasser->setDirection(direction); + mMasser->setState(state); } -void SkyManager::setSecundaDirection(const osg::Vec3f& direction) +void SkyManager::setSecundaState(const MoonState& state) { - if (!mCreated) return; + if(!mCreated) return; - mSecunda->setDirection(direction); -} - -void SkyManager::masserEnable() -{ - if (!mCreated) return; - - mMasser->setVisible(true); -} - -void SkyManager::secundaEnable() -{ - if (!mCreated) return; - - mSecunda->setVisible(true); -} - -void SkyManager::masserDisable() -{ - if (!mCreated) return; - - mMasser->setVisible(false); -} - -void SkyManager::secundaDisable() -{ - if (!mCreated) return; - - mSecunda->setVisible(false); + mSecunda->setState(state); } void SkyManager::setLightningStrength(const float factor) @@ -1184,18 +1164,6 @@ void SkyManager::setLightningStrength(const float factor) */ } -void SkyManager::setMasserFade(const float fade) -{ - if (!mCreated) return; - mMasser->setFade(fade); -} - -void SkyManager::setSecundaFade(const float fade) -{ - if (!mCreated) return; - mSecunda->setFade(fade); -} - void SkyManager::setDate(int day, int month) { mDay = day; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 4d1c73e44..eb953d128 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -33,6 +33,28 @@ namespace MWRender class RainFader; class AlphaFader; + struct MoonState + { + enum Phase + { + Phase_Full = 0, + Phase_WaningGibbous, + Phase_ThirdQuarter, + Phase_WaningCrescent, + Phase_New, + Phase_WaxingCrescent, + Phase_FirstQuarter, + Phase_WaxingGibbous, + Phase_Unspecified + }; + + float mRotationFromHorizon; + float mRotationFromNorth; + Phase mPhase; + float mShadowBlend; + float mMoonAlpha; + }; + class SkyManager { public: @@ -72,19 +94,8 @@ namespace MWRender void setSunDirection(const osg::Vec3f& direction); - void setMasserDirection(const osg::Vec3f& direction); - - void setSecundaDirection(const osg::Vec3f& direction); - - void setMasserFade(const float fade); - - void setSecundaFade(const float fade); - - void masserEnable(); - void masserDisable(); - - void secundaEnable(); - void secundaDisable(); + void setMasserState(const MoonState& state); + void setSecundaState(const MoonState& state); void setLightningStrength(const float factor); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 970e8b455..f98aa24c1 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -37,6 +37,170 @@ namespace } } +MoonModel::MoonModel(const std::string& name, MWWorld::Fallback& fallback) + : mFadeInStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Start")) + , mFadeInFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Finish")) + , mFadeOutStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_Out_Start")) + , mFadeOutFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_Out_Finish")) + , mAxisOffset(fallback.getFallbackFloat("Moons_" + name + "_Axis_Offset")) + , mSpeed(fallback.getFallbackFloat("Moons_" + name + "_Speed")) + , mDailyIncrement(fallback.getFallbackFloat("Moons_" + name + "_Daily_Increment")) + , mFadeStartAngle(fallback.getFallbackFloat("Moons_" + name + "_Fade_Start_Angle")) + , mFadeEndAngle(fallback.getFallbackFloat("Moons_" + name + "_Fade_End_Angle")) + , mMoonShadowEarlyFadeAngle(fallback.getFallbackFloat("Moons_" + name + "_Moon_Shadow_Early_Fade_Angle")) +{ + // Morrowind appears to have a minimum speed in order to avoid situations where the moon couldn't conceivably + // complete a rotation in a single 24 hour period. The value of 180/23 was deduced from reverse engineering. + mSpeed = std::min(mSpeed, 180.0f / 23.0f); +} + +MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gameHour) +{ + float rotationFromHorizon = angle(daysPassed, gameHour); + MWRender::MoonState state = + { + rotationFromHorizon, + mAxisOffset, // Reverse engineered from Morrowind's scene graph rotation matrices. + static_cast(phase(daysPassed)), + shadowBlend(rotationFromHorizon), + earlyMoonShadowAlpha(rotationFromHorizon) * hourlyAlpha(gameHour) + }; + + return state; +} + +inline float MoonModel::angle(unsigned int daysPassed, float gameHour) +{ + // Morrowind's moons start travel on one side of the horizon (let's call it H-rise) and travel 180 degrees to the + // opposite horizon (let's call it H-set). Upon reaching H-set, they reset to H-rise until the next moon rise. + + // When calculating the angle of the moon, several cases have to be taken into account: + // 1. Moon rises and then sets in one day. + // 2. Moon sets and doesn't rise in one day (occurs when the moon rise hour is >= 24). + // 3. Moon sets and then rises in one day. + float moonRiseHourToday = moonRiseHour(daysPassed); + float moonRiseAngleToday = 0; + + if(gameHour < moonRiseHourToday) + { + float moonRiseHourYesterday = moonRiseHour(daysPassed - 1); + if(moonRiseHourYesterday < 24) + { + float moonRiseAngleYesterday = rotation(24 - moonRiseHourYesterday); + if(moonRiseAngleYesterday < 180) + { + // The moon rose but did not set yesterday, so accumulate yesterday's angle with how much we've travelled today. + moonRiseAngleToday = rotation(gameHour) + moonRiseAngleYesterday; + } + } + } + else + { + moonRiseAngleToday = rotation(gameHour - moonRiseHourToday); + } + + if(moonRiseAngleToday >= 180) + { + // The moon set today, reset the angle to the horizon. + moonRiseAngleToday = 0; + } + + return moonRiseAngleToday; +} + +inline float MoonModel::moonRiseHour(unsigned int daysPassed) +{ + // This arises from the start date of 16 Last Seed, 427 + // TODO: Find an alternate formula that doesn't rely on this day being fixed. + static const unsigned int startDay = 16; + + // This odd formula arises from the fact that on 16 Last Seed, 17 increments have occurred, meaning + // that upon starting a new game, it must only calculate the moon phase as far back as 1 Last Seed. + // Note that we don't modulo after adding the latest daily increment because other calculations need to + // know if doing so would cause the moon rise to be postponed until the next day (which happens when + // the moon rise hour is >= 24 in Morrowind). + return mDailyIncrement + std::fmod((daysPassed - 1 + startDay) * mDailyIncrement, 24.0f); +} + +inline float MoonModel::rotation(float hours) +{ + // 15 degrees per hour was reverse engineered from the rotation matrices of the Morrowind scene graph. + // Note that this correlates to 360 / 24, which is a full rotation every 24 hours, so speed is a measure + // of whole rotations that could be completed in a day. + return 15.0f * mSpeed * hours; +} + +inline unsigned int MoonModel::phase(unsigned int daysPassed) +{ + // Morrowind starts with a full moon on 16 Last Seed and then begins to wane 17 Last Seed, working on 3 day phase cycle. + // Note: this is an internal helper, and as such we don't want to return MWRender::MoonState::Phase since we can't + // forward declare it (C++11 strongly typed enums solve this). + return ((daysPassed + 1) / 3) % 8; +} + +inline float MoonModel::shadowBlend(float angle) +{ + // The Fade End Angle and Fade Start Angle describe a region where the moon transitions from a solid disk + // that is roughly the color of the sky, to a textured surface. + // Depending on the current angle, the following values describe the ratio between the textured moon + // and the solid disk: + // 1. From Fade End Angle 1 to Fade Start Angle 1 (during moon rise): 0..1 + // 2. From Fade Start Angle 1 to Fade Start Angle 2 (between moon rise and moon set): 1 (textured) + // 3. From Fade Start Angle 2 to Fade End Angle 2 (during moon set): 1..0 + // 4. From Fade End Angle 2 to Fade End Angle 1 (between moon set and moon rise): 0 (solid disk) + float fadeAngle = mFadeStartAngle - mFadeEndAngle; + float fadeEndAngle2 = 180.0f - mFadeEndAngle; + float fadeStartAngle2 = 180.0f - mFadeStartAngle; + if((angle >= mFadeEndAngle) && (angle < mFadeStartAngle)) + return (angle - mFadeEndAngle) / fadeAngle; + else if((angle >= mFadeStartAngle) && (angle < fadeStartAngle2)) + return 1.0f; + else if((angle >= fadeStartAngle2) && (angle < fadeEndAngle2)) + return (fadeEndAngle2 - angle) / fadeAngle; + else + return 0.0f; +} + +inline float MoonModel::hourlyAlpha(float gameHour) +{ + // The Fade Out Start / Finish and Fade In Start / Finish describe the hours at which the moon + // appears and disappears. + // Depending on the current hour, the following values describe how transparent the moon is. + // 1. From Fade Out Start to Fade Out Finish: 1..0 + // 2. From Fade Out Finish to Fade In Start: 0 (transparent) + // 3. From Fade In Start to Fade In Finish: 0..1 + // 4. From Fade In Finish to Fade Out Start: 1 (solid) + if((gameHour >= mFadeOutStart) && (gameHour < mFadeOutFinish)) + return (mFadeOutFinish - gameHour) / (mFadeOutFinish - mFadeOutStart); + else if((gameHour >= mFadeOutFinish) && (gameHour < mFadeInStart)) + return 0.0f; + else if((gameHour >= mFadeInStart) && (gameHour < mFadeInFinish)) + return (gameHour - mFadeInStart) / (mFadeInFinish - mFadeInStart); + else + return 1.0f; +} + +inline float MoonModel::earlyMoonShadowAlpha(float angle) +{ + // The Moon Shadow Early Fade Angle describes an arc relative to Fade End Angle. + // Depending on the current angle, the following values describe how transparent the moon is. + // 1. From Moon Shadow Early Fade Angle 1 to Fade End Angle 1 (during moon rise): 0..1 + // 2. From Fade End Angle 1 to Fade End Angle 2 (between moon rise and moon set): 1 (solid) + // 3. From Fade End Angle 2 to Moon Shadow Early Fade Angle 2 (during moon set): 1..0 + // 4. From Moon Shadow Early Fade Angle 2 to Moon Shadow Early Fade Angle 1: 0 (transparent) + float moonShadowEarlyFadeAngle1 = mFadeEndAngle - mMoonShadowEarlyFadeAngle; + float fadeEndAngle2 = 180.0f - mFadeEndAngle; + float moonShadowEarlyFadeAngle2 = fadeEndAngle2 + mMoonShadowEarlyFadeAngle; + if((angle >= moonShadowEarlyFadeAngle1) && (angle < mFadeEndAngle)) + return (angle - moonShadowEarlyFadeAngle1) / mMoonShadowEarlyFadeAngle; + else if((angle >= mFadeEndAngle) && (angle < fadeEndAngle2)) + return 1.0f; + else if((angle >= fadeEndAngle2) && (angle < moonShadowEarlyFadeAngle2)) + return (moonShadowEarlyFadeAngle2 - angle) / mMoonShadowEarlyFadeAngle; + else + return 0.0f; +} + void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name) { std::string upper=name; @@ -88,39 +252,12 @@ Max Raindrops=650 ? mWeatherSettings[name] = weather; } - -float WeatherManager::calculateHourFade (const std::string& moonName) const -{ - float fadeOutStart=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_Out_Start"); - float fadeOutFinish=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_Out_Finish"); - float fadeInStart=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_In_Start"); - float fadeInFinish=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_In_Finish"); - - if (mHour >= fadeOutStart && mHour <= fadeOutFinish) - return (1 - ((mHour - fadeOutStart) / (fadeOutFinish - fadeOutStart))); - if (mHour >= fadeInStart && mHour <= fadeInFinish) - return (1 - ((mHour - fadeInStart) / (fadeInFinish - fadeInStart))); - else - return 1; -} - -float WeatherManager::calculateAngleFade (const std::string& moonName, float angle) const -{ - float endAngle=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_End_Angle"); - float startAngle=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_Start_Angle"); - if (angle <= startAngle && angle >= endAngle) - return (1 - ((angle - endAngle)/(startAngle-endAngle))); - else if (angle > startAngle) - return 0.f; - else - return 1.f; -} - WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::Fallback* fallback, MWWorld::ESMStore* store) : mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mFallback(fallback), mStore(store), mRendering(rendering), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true), mRemainingTransitionTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), - mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0) + mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0), + mMasser("Masser", *fallback), mSecunda("Secunda", *fallback) { //Globals mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); @@ -465,72 +602,9 @@ void WeatherManager::update(float duration, bool paused) mRendering->setSunDirection( final * -1 ); } - /* - * TODO: import separated fadeInStart/Finish, fadeOutStart/Finish - * for masser and secunda - */ - - float fadeOutFinish=mFallback->getFallbackFloat("Moons_Masser_Fade_Out_Finish"); - float fadeInStart=mFallback->getFallbackFloat("Moons_Masser_Fade_In_Start"); - - //moon calculations - float moonHeight; - if (mHour >= fadeInStart) - moonHeight = mHour - fadeInStart; - else if (mHour <= fadeOutFinish) - moonHeight = mHour + fadeOutFinish; - else - moonHeight = 0; - - moonHeight /= (24.f - (fadeInStart - fadeOutFinish)); - - if (moonHeight != 0) - { - int facing = (moonHeight <= 1) ? 1 : -1; - osg::Vec3f masser( - (moonHeight - 1) * facing, - (1 - moonHeight) * facing, - moonHeight); - - osg::Vec3f secunda( - (moonHeight - 1) * facing * 1.25f, - (1 - moonHeight) * facing * 0.8f, - moonHeight); - - mRendering->getSkyManager()->setMasserDirection(masser); - mRendering->getSkyManager()->setSecundaDirection(secunda); - - float angle = (1-moonHeight) * 90.f * facing; - float masserHourFade = calculateHourFade("Masser"); - float secundaHourFade = calculateHourFade("Secunda"); - float masserAngleFade = calculateAngleFade("Masser", angle); - float secundaAngleFade = calculateAngleFade("Secunda", angle); - - masserAngleFade *= masserHourFade; - secundaAngleFade *= secundaHourFade; - - if (masserAngleFade > 0) - { - mRendering->getSkyManager()->setMasserFade(masserAngleFade); - mRendering->getSkyManager()->masserEnable(); - } - else - mRendering->getSkyManager()->masserDisable(); - - if (secundaAngleFade > 0) - { - mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); - mRendering->getSkyManager()->secundaEnable(); - } - else - mRendering->getSkyManager()->secundaDisable(); - - } - else - { - mRendering->getSkyManager()->masserDisable(); - mRendering->getSkyManager()->secundaDisable(); - } + TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp(); + mRendering->getSkyManager()->setMasserState(mMasser.calculateState(time.getDay(), time.getHour())); + mRendering->getSkyManager()->setSecundaState(mSecunda.calculateState(time.getDay(), time.getHour())); if (!paused) { diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index efe69f17c..93cfed68b 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -19,6 +19,7 @@ namespace ESM namespace MWRender { class RenderingManager; + class MoonState; } namespace Loading @@ -150,6 +151,35 @@ namespace MWWorld // is broken in the vanilla game and was disabled. }; + class MoonModel + { + public: + MoonModel(const std::string& name, MWWorld::Fallback& fallback); + + MWRender::MoonState calculateState(unsigned int daysPassed, float gameHour); + + private: + float mSize; + float mFadeInStart; + float mFadeInFinish; + float mFadeOutStart; + float mFadeOutFinish; + float mAxisOffset; + float mSpeed; + float mDailyIncrement; + float mFadeStartAngle; + float mFadeEndAngle; + float mMoonShadowEarlyFadeAngle; + + float angle(unsigned int daysPassed, float gameHour); + float moonRiseHour(unsigned int daysPassed); + float rotation(float hours); + unsigned int phase(unsigned int daysPassed); + float shadowBlend(float angle); + float hourlyAlpha(float gameHour); + float earlyMoonShadowAlpha(float angle); + }; + /// /// Interface for weather settings /// @@ -237,9 +267,6 @@ namespace MWWorld void transition(const float factor); void setResult(const std::string& weatherType); - float calculateHourFade (const std::string& moonName) const; - float calculateAngleFade (const std::string& moonName, float angle) const; - void setWeather(const std::string& weatherType, bool instant=false); std::string nextWeather(const ESM::Region* region) const; WeatherResult mResult; @@ -265,6 +292,8 @@ namespace MWWorld std::string mThunderSoundID1; std::string mThunderSoundID2; std::string mThunderSoundID3; + MoonModel mMasser; + MoonModel mSecunda; }; } From 8dc7e158c675832a9cc4a3948a470d8dbb96f4a4 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 30 Jul 2015 00:18:56 -0500 Subject: [PATCH 171/419] Fix forward declaration of MoonState --- apps/openmw/mwworld/weather.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 93cfed68b..4290b21aa 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -19,7 +19,7 @@ namespace ESM namespace MWRender { class RenderingManager; - class MoonState; + struct MoonState; } namespace Loading From a4e1630ec249ce15dbfa71f12cee801d38031bf7 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 30 Jul 2015 00:41:30 -0500 Subject: [PATCH 172/419] Remove unreferenced member in MoonModel --- apps/openmw/mwworld/weather.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 4290b21aa..faa6355ce 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -159,7 +159,6 @@ namespace MWWorld MWRender::MoonState calculateState(unsigned int daysPassed, float gameHour); private: - float mSize; float mFadeInStart; float mFadeInFinish; float mFadeOutStart; From e9ffbcc1b0aa771ca627a26acb6565b6b5e85555 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 30 Jul 2015 11:45:10 +0200 Subject: [PATCH 173/419] OSG 3.3.3 moves GL extensions out of osg::Texture --- components/resource/texturemanager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 4bd712ea5..252456fb1 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -118,10 +118,17 @@ namespace Resource case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): { +#if OSG_MIN_VERSION_REQUIRED(3, 3, 3) + osg::GLExtensions* exts = osg::GLExtensions::Get(0, false); + if (exts && !exts->isTextureCompressionS3TCSupported + // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. + && !osg::isGLExtensionSupported(0, "GL_S3_s3tc")) +#else osg::Texture::Extensions* exts = osg::Texture::getExtensions(0, false); if (exts && !exts->isTextureCompressionS3TCSupported() // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. && !osg::isGLExtensionSupported(0, "GL_S3_s3tc")) +#endif { std::cerr << "Error loading " << filename << ": no S3TC texture compression support installed" << std::endl; return false; From 6a9218ee07a81c9ca56faf8661c9d38e84ba3028 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 30 Jul 2015 11:49:24 +0200 Subject: [PATCH 174/419] replaced State_Compiling (not requried anymore) with State_Merging --- apps/opencs/model/doc/state.hpp | 2 +- apps/opencs/view/doc/operation.cpp | 3 ++- apps/opencs/view/doc/view.cpp | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/state.hpp b/apps/opencs/model/doc/state.hpp index 78f468101..7352b4b99 100644 --- a/apps/opencs/model/doc/state.hpp +++ b/apps/opencs/model/doc/state.hpp @@ -12,7 +12,7 @@ namespace CSMDoc State_Saving = 16, State_Verifying = 32, - State_Compiling = 64, // not implemented yet + State_Merging = 64, State_Searching = 128, State_Loading = 256 // pseudo-state; can not be encountered in a loaded document }; diff --git a/apps/opencs/view/doc/operation.cpp b/apps/opencs/view/doc/operation.cpp index 95cbf012d..e5c1e7b89 100644 --- a/apps/opencs/view/doc/operation.cpp +++ b/apps/opencs/view/doc/operation.cpp @@ -19,6 +19,7 @@ void CSVDoc::Operation::updateLabel (int threads) case CSMDoc::State_Saving: name = "saving"; break; case CSMDoc::State_Verifying: name = "verifying"; break; case CSMDoc::State_Searching: name = "searching"; break; + case CSMDoc::State_Merging: name = "merging"; break; } std::ostringstream stream; @@ -122,7 +123,7 @@ void CSVDoc::Operation::setBarColor (int type) bottomColor = "#9ECB2D"; //green gloss break; - case CSMDoc::State_Compiling: + case CSMDoc::State_Merging: topColor = "#F3E2C7"; midTopColor = "#C19E67"; diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index c4abb2622..05c98b11f 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -471,6 +471,7 @@ void CSVDoc::View::updateDocumentState() static const int operations[] = { CSMDoc::State_Saving, CSMDoc::State_Verifying, CSMDoc::State_Searching, + CSMDoc::State_Merging, -1 // end marker }; From 77a3a52b4e5d154d55c50c728410c809aa137a8c Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 30 Jul 2015 12:16:15 +0200 Subject: [PATCH 175/419] What's wrong with this statement? --- components/resource/texturemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 252456fb1..750dfaab7 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -118,7 +118,7 @@ namespace Resource case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): { -#if OSG_MIN_VERSION_REQUIRED(3, 3, 3) +#if OSG_MIN_VERSION_REQUIRED(3,3,3) osg::GLExtensions* exts = osg::GLExtensions::Get(0, false); if (exts && !exts->isTextureCompressionS3TCSupported // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. From 1f78ebd3c98bf9759f5573a76279e44eab8cec61 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 30 Jul 2015 12:22:51 +0200 Subject: [PATCH 176/419] Oops? --- components/resource/texturemanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index 750dfaab7..d29aa2812 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -2,6 +2,7 @@ #include #include +#include #include From 5e6fcc2aefbf2eccf5e16deeb2f064c66efcb497 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Wed, 29 Jul 2015 14:15:06 -0400 Subject: [PATCH 177/419] Alert the user if attempting to play an animation fails This is mostly propogating the error up the stack so the game can do something about it. Working on avoiding log spam from calling an animation that doesn't exist every frame. --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 ++- apps/openmw/mwmechanics/actors.cpp | 12 ++++++++++-- apps/openmw/mwmechanics/actors.hpp | 2 +- apps/openmw/mwmechanics/character.cpp | 6 +++++- apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 6 +++--- apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 4 +++- apps/openmw/mwmechanics/objects.cpp | 13 +++++++++++-- apps/openmw/mwmechanics/objects.hpp | 2 +- 9 files changed, 37 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 2c4a22c07..63ad1d32f 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -160,12 +160,13 @@ namespace MWBase virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0; ///< Forces an object to refresh its animation state. - virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0; + virtual bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0; ///< Run animation for a MW-reference. Calls to this function for references that are currently not /// in the scene should be ignored. /// /// \param mode 0 normal, 1 immediate start, 2 immediate loop /// \param count How many times the animation should be run + /// \return Success or error virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0; ///< Skip the animation for the given MW-reference for one frame. Calls to this function for diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c135811dd..dd2fe3cad 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1,6 +1,7 @@ #include "actors.hpp" #include +#include #include @@ -1241,11 +1242,18 @@ namespace MWMechanics iter->second->getCharacterController()->forceStateUpdate(); } - void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) + bool Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { PtrActorMap::iterator iter = mActors.find(ptr); if(iter != mActors.end()) - iter->second->getCharacterController()->playGroup(groupName, mode, number); + { + return iter->second->getCharacterController()->playGroup(groupName, mode, number); + } + else + { + std::cerr<< "Error in Actors::playAnimationGroup: Unable to find " << ptr.getTypeName() << std::endl; + return false; + } } void Actors::skipAnimation(const MWWorld::Ptr& ptr) { diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 4baaea28d..a16b80884 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -105,7 +105,7 @@ namespace MWMechanics void forceStateUpdate(const MWWorld::Ptr &ptr); - void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + bool 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); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9d5f7137f..1bd12b53f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1866,10 +1866,13 @@ void CharacterController::update(float duration) } -void CharacterController::playGroup(const std::string &groupname, int mode, int count) +bool CharacterController::playGroup(const std::string &groupname, int mode, int count) { if(!mAnimation || !mAnimation->hasAnimation(groupname)) + { std::cerr<< "Animation "< + #include "movement.hpp" #include "../mwbase/environment.hpp" @@ -77,11 +79,18 @@ void Objects::update(float duration, bool paused) } } -void Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) +bool Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { PtrControllerMap::iterator iter = mObjects.find(ptr); if(iter != mObjects.end()) - iter->second->playGroup(groupName, mode, number); + { + return iter->second->playGroup(groupName, mode, number); + } + else + { + std::cerr<< "Error in Objects::playAnimationGroup: Unable to find " << ptr.getTypeName() << std::endl; + return false; + } } void Objects::skipAnimation(const MWWorld::Ptr& ptr) { diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 6e22c0582..07e00675c 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -38,7 +38,7 @@ namespace MWMechanics void update(float duration, bool paused); ///< Update object animations - void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); void skipAnimation(const MWWorld::Ptr& ptr); void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& out); From f69de1f2636f6627a25e1c026e7d176cf7e6108e Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Thu, 30 Jul 2015 08:08:58 -0400 Subject: [PATCH 178/419] Alert the user if trying to play a non-idle animation Continue to propagate success/failure up the call stack. --- apps/openmw/mwmechanics/aiwander.cpp | 10 ++++++++-- apps/openmw/mwmechanics/aiwander.hpp | 5 ++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e230998eb..e3ce4ae2a 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -1,6 +1,7 @@ #include "aiwander.hpp" #include +#include #include @@ -621,12 +622,17 @@ namespace MWMechanics actor.getClass().getMovementSettings(actor).mPosition[1] = 0; } - void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) + bool AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) { if ((GroupIndex_MinIdle <= idleSelect) && (idleSelect <= GroupIndex_MaxIdle)) { const std::string& groupName = sIdleSelectToGroupName[idleSelect - GroupIndex_MinIdle]; - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, groupName, 0, 1); + return MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, groupName, 0, 1); + } + else + { + std::cerr<< "Attempted to play out of range idle animation \""< Date: Thu, 30 Jul 2015 08:15:45 -0400 Subject: [PATCH 179/419] Refactor onChooseActionStatePerFrameActions This prevents playIdle errors from tyring to play idleAnimation 0 --- apps/openmw/mwmechanics/aiwander.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e3ce4ae2a..f05040b66 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -392,18 +392,24 @@ namespace MWMechanics short unsigned& idleAnimation = storage.mIdleAnimation; idleAnimation = getRandomIdle(); + //If we should be moving if (!idleAnimation && mDistance) { storage.mState = Wander_MoveNow; } else { - // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: + //Recreate vanilla (broken?) behavior of resetting start time of AIWander: MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); mStartTime = currentTime; - playIdle(actor, idleAnimation); storage.mState = Wander_IdleNow; } + + //If we aren't going to just stand + if(idleAnimation) + { + playIdle(actor, idleAnimation); + } } void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) From 67a63cc6622c5b2d2f24fc8fdc8dc5f40aa22222 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 30 Jul 2015 14:00:08 -0500 Subject: [PATCH 180/419] Add some const correctness to MoonModel --- apps/openmw/mwworld/weather.cpp | 18 +++++++++--------- apps/openmw/mwworld/weather.hpp | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index f98aa24c1..0e78edce7 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -37,7 +37,7 @@ namespace } } -MoonModel::MoonModel(const std::string& name, MWWorld::Fallback& fallback) +MoonModel::MoonModel(const std::string& name, const MWWorld::Fallback& fallback) : mFadeInStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Start")) , mFadeInFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Finish")) , mFadeOutStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_Out_Start")) @@ -54,7 +54,7 @@ MoonModel::MoonModel(const std::string& name, MWWorld::Fallback& fallback) mSpeed = std::min(mSpeed, 180.0f / 23.0f); } -MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gameHour) +MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gameHour) const { float rotationFromHorizon = angle(daysPassed, gameHour); MWRender::MoonState state = @@ -69,7 +69,7 @@ MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gam return state; } -inline float MoonModel::angle(unsigned int daysPassed, float gameHour) +inline float MoonModel::angle(unsigned int daysPassed, float gameHour) const { // Morrowind's moons start travel on one side of the horizon (let's call it H-rise) and travel 180 degrees to the // opposite horizon (let's call it H-set). Upon reaching H-set, they reset to H-rise until the next moon rise. @@ -108,7 +108,7 @@ inline float MoonModel::angle(unsigned int daysPassed, float gameHour) return moonRiseAngleToday; } -inline float MoonModel::moonRiseHour(unsigned int daysPassed) +inline float MoonModel::moonRiseHour(unsigned int daysPassed) const { // This arises from the start date of 16 Last Seed, 427 // TODO: Find an alternate formula that doesn't rely on this day being fixed. @@ -122,7 +122,7 @@ inline float MoonModel::moonRiseHour(unsigned int daysPassed) return mDailyIncrement + std::fmod((daysPassed - 1 + startDay) * mDailyIncrement, 24.0f); } -inline float MoonModel::rotation(float hours) +inline float MoonModel::rotation(float hours) const { // 15 degrees per hour was reverse engineered from the rotation matrices of the Morrowind scene graph. // Note that this correlates to 360 / 24, which is a full rotation every 24 hours, so speed is a measure @@ -130,7 +130,7 @@ inline float MoonModel::rotation(float hours) return 15.0f * mSpeed * hours; } -inline unsigned int MoonModel::phase(unsigned int daysPassed) +inline unsigned int MoonModel::phase(unsigned int daysPassed) const { // Morrowind starts with a full moon on 16 Last Seed and then begins to wane 17 Last Seed, working on 3 day phase cycle. // Note: this is an internal helper, and as such we don't want to return MWRender::MoonState::Phase since we can't @@ -138,7 +138,7 @@ inline unsigned int MoonModel::phase(unsigned int daysPassed) return ((daysPassed + 1) / 3) % 8; } -inline float MoonModel::shadowBlend(float angle) +inline float MoonModel::shadowBlend(float angle) const { // The Fade End Angle and Fade Start Angle describe a region where the moon transitions from a solid disk // that is roughly the color of the sky, to a textured surface. @@ -161,7 +161,7 @@ inline float MoonModel::shadowBlend(float angle) return 0.0f; } -inline float MoonModel::hourlyAlpha(float gameHour) +inline float MoonModel::hourlyAlpha(float gameHour) const { // The Fade Out Start / Finish and Fade In Start / Finish describe the hours at which the moon // appears and disappears. @@ -180,7 +180,7 @@ inline float MoonModel::hourlyAlpha(float gameHour) return 1.0f; } -inline float MoonModel::earlyMoonShadowAlpha(float angle) +inline float MoonModel::earlyMoonShadowAlpha(float angle) const { // The Moon Shadow Early Fade Angle describes an arc relative to Fade End Angle. // Depending on the current angle, the following values describe how transparent the moon is. diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index faa6355ce..8f7634fbb 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -154,9 +154,9 @@ namespace MWWorld class MoonModel { public: - MoonModel(const std::string& name, MWWorld::Fallback& fallback); + MoonModel(const std::string& name, const MWWorld::Fallback& fallback); - MWRender::MoonState calculateState(unsigned int daysPassed, float gameHour); + MWRender::MoonState calculateState(unsigned int daysPassed, float gameHour) const; private: float mFadeInStart; @@ -170,13 +170,13 @@ namespace MWWorld float mFadeEndAngle; float mMoonShadowEarlyFadeAngle; - float angle(unsigned int daysPassed, float gameHour); - float moonRiseHour(unsigned int daysPassed); - float rotation(float hours); - unsigned int phase(unsigned int daysPassed); - float shadowBlend(float angle); - float hourlyAlpha(float gameHour); - float earlyMoonShadowAlpha(float angle); + float angle(unsigned int daysPassed, float gameHour) const; + float moonRiseHour(unsigned int daysPassed) const; + float rotation(float hours) const; + unsigned int phase(unsigned int daysPassed) const; + float shadowBlend(float angle) const; + float hourlyAlpha(float gameHour) const; + float earlyMoonShadowAlpha(float angle) const; }; /// From de479e35c8e39f6097148d17b5631630333cd1b4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 30 Jul 2015 23:51:37 +0200 Subject: [PATCH 181/419] Fix AlphaController affecting all instances of the StateSet --- components/nifosg/controller.cpp | 7 +++++++ components/nifosg/controller.hpp | 2 ++ 2 files changed, 9 insertions(+) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 83ecc0fa9..e66713c17 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -353,6 +353,13 @@ AlphaController::AlphaController(const AlphaController ©, const osg::CopyOp { } +void AlphaController::setDefaults(osg::StateSet *stateset) +{ + // need to create a deep copy of StateAttributes we will modify + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + stateset->setAttribute(osg::clone(mat, osg::CopyOp::DEEP_COPY_ALL), osg::StateAttribute::ON); +} + void AlphaController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { if (hasInput()) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 4877c83db..500a5cc17 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -189,6 +189,8 @@ namespace NifOsg AlphaController(); AlphaController(const AlphaController& copy, const osg::CopyOp& copyop); + virtual void setDefaults(osg::StateSet* stateset); + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv); META_Object(NifOsg, AlphaController) From 16b8ef3164c28f829bbe76b3ac1a21a3bb53715c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 00:01:55 +0200 Subject: [PATCH 182/419] Don't use a shared Material in MaterialColorController --- components/nifosg/controller.cpp | 7 +++++++ components/nifosg/controller.hpp | 2 ++ 2 files changed, 9 insertions(+) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index e66713c17..bb698ed63 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -387,6 +387,13 @@ MaterialColorController::MaterialColorController(const MaterialColorController & { } +void MaterialColorController::setDefaults(osg::StateSet *stateset) +{ + // need to create a deep copy of StateAttributes we will modify + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + stateset->setAttribute(osg::clone(mat, osg::CopyOp::DEEP_COPY_ALL), osg::StateAttribute::ON); +} + void MaterialColorController::apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { if (hasInput()) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 500a5cc17..58870317e 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -208,6 +208,8 @@ namespace NifOsg META_Object(NifOsg, MaterialColorController) + virtual void setDefaults(osg::StateSet* stateset); + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv); }; From 1f755a2bc0d99f1ad5e3fe1a32e645a6a4d77694 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 00:03:01 +0200 Subject: [PATCH 183/419] Don't use a shared Material in AlphaFader --- apps/openmw/mwrender/sky.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 49c00c33d..2009232c5 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -705,6 +705,13 @@ public: mAlpha = alpha; } + virtual void setDefaults(osg::StateSet* stateset) + { + // need to create a deep copy of StateAttributes we will modify + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + stateset->setAttribute(osg::clone(mat, osg::CopyOp::DEEP_COPY_ALL), osg::StateAttribute::ON); + } + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) { osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); From e8cbdcfb1e98956b86df8d80eb268882d951864b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 00:35:17 +0200 Subject: [PATCH 184/419] Play swimming animation fallback on the upper body when possible --- apps/openmw/mwmechanics/character.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9d5f7137f..ae4412dbf 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -390,7 +390,8 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } else { - movemask = MWRender::Animation::BlendMask_LowerBody; + if (weap != sWeaponTypeListEnd) + movemask = MWRender::Animation::BlendMask_LowerBody; movementAnimName.erase(swimpos, 4); if(!mAnimation->hasAnimation(movementAnimName)) movementAnimName.clear(); From f326b8e5d28e5a8a68098bdb60a96fc382d0a3fc Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 00:52:34 +0200 Subject: [PATCH 185/419] Fix weapon animations playing on the lowerbody when swimming --- apps/openmw/mwmechanics/character.cpp | 6 +++++- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ae4412dbf..44fcf1c57 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -468,10 +468,14 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mIdleState = idle; std::string idle; + MWRender::Animation::AnimPriority idlePriority (Priority_Default); // Only play "idleswim" or "idlesneak" if they exist. Otherwise, fallback to // "idle"+weapon or "idle". if(mIdleState == CharState_IdleSwim && mAnimation->hasAnimation("idleswim")) + { idle = "idleswim"; + idlePriority = Priority_SwimIdle; + } else if(mIdleState == CharState_IdleSneak && mAnimation->hasAnimation("idlesneak")) idle = "idlesneak"; else if(mIdleState != CharState_None) @@ -488,7 +492,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mAnimation->disable(mCurrentIdle); mCurrentIdle = idle; if(!mCurrentIdle.empty()) - mAnimation->play(mCurrentIdle, Priority_Default, MWRender::Animation::BlendMask_All, false, + mAnimation->play(mCurrentIdle, idlePriority, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, ~0ul, true); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index d647cae22..3ada5e65e 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -29,6 +29,7 @@ class CreatureStats; enum Priority { Priority_Default, Priority_WeaponLowerBody, + Priority_SwimIdle, Priority_Jump, Priority_Movement, Priority_Hit, From 7644a46deddc25367dfa6d50f6c51a74a32566f4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 01:26:26 +0200 Subject: [PATCH 186/419] Creatures with no movement should not attempt to start combat (Fixes #2786) --- apps/openmw/mwmechanics/actors.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c135811dd..75d501ff1 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -291,6 +291,10 @@ namespace MWMechanics return; } + // no combat for totally static creatures (they have no movement or attack animations anyway) + if (!actor1.getClass().isMobile(actor1)) + return; + bool aggressive; if (againstPlayer) From 61c38356378fb4ab0de5bf4a23cd828b40ab7a29 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Thu, 30 Jul 2015 08:20:16 -0400 Subject: [PATCH 187/419] Don't try to play animations we know are bad Prevents log spam --- apps/openmw/mwmechanics/aiwander.cpp | 34 +++++++++++++++++----------- apps/openmw/mwmechanics/aiwander.hpp | 4 ++-- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index f05040b66..331ec8b9d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -58,7 +58,6 @@ namespace MWMechanics bool mTurnActorGivingGreetingToFacePlayer; float mReaction; // update some actions infrequently - AiWander::GreetingState mSaidGreeting; int mGreetingTimer; @@ -68,6 +67,7 @@ namespace MWMechanics AiWander::WanderState mState; unsigned short mIdleAnimation; + std::vector mBadIdles; //Idle animations that when called cause errors PathFinder mPathFinder; @@ -79,7 +79,8 @@ namespace MWMechanics mGreetingTimer(0), mCell(NULL), mState(AiWander::Wander_ChooseAction), - mIdleAnimation(0) + mIdleAnimation(0), + mBadIdles() {}; }; @@ -392,24 +393,31 @@ namespace MWMechanics short unsigned& idleAnimation = storage.mIdleAnimation; idleAnimation = getRandomIdle(); - //If we should be moving + // If we should be moving if (!idleAnimation && mDistance) { storage.mState = Wander_MoveNow; + return; } - else - { - //Recreate vanilla (broken?) behavior of resetting start time of AIWander: - MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - mStartTime = currentTime; - storage.mState = Wander_IdleNow; - } - - //If we aren't going to just stand + // If we aren't going to just stand if(idleAnimation) { - playIdle(actor, idleAnimation); + // If the idle animation actually exists + if(std::find(storage.mBadIdles.begin(), storage.mBadIdles.end(), idleAnimation)==storage.mBadIdles.end()) + { + if(!playIdle(actor, idleAnimation)) + { + std::cerr<< "Unable to play idle animation "<getTimeStamp(); + storage.mState = Wander_IdleNow; + return; } void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index c03cdfaa2..27e6fe9fb 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -76,8 +76,8 @@ namespace MWMechanics void stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage); - ///Have the given actor play an idle animation - ///@return Success or error + /// Have the given actor play an idle animation + /// @return Success or error bool playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); short unsigned getRandomIdle(); From 6fce49bfb5e6a32127852193dc9413bec59488c5 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 31 Jul 2015 18:00:17 -0400 Subject: [PATCH 188/419] Don't warn twice when unable to play an idle animation --- apps/openmw/mwmechanics/aiwander.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 331ec8b9d..b356c6e7d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -407,7 +407,6 @@ namespace MWMechanics { if(!playIdle(actor, idleAnimation)) { - std::cerr<< "Unable to play idle animation "< Date: Fri, 31 Jul 2015 18:23:07 -0400 Subject: [PATCH 189/419] Remove more comments --- apps/openmw/mwmechanics/aiwander.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b356c6e7d..440814fb7 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -67,7 +67,7 @@ namespace MWMechanics AiWander::WanderState mState; unsigned short mIdleAnimation; - std::vector mBadIdles; //Idle animations that when called cause errors + std::vector mBadIdles; // Idle animations that when called cause errors PathFinder mPathFinder; @@ -393,16 +393,13 @@ namespace MWMechanics short unsigned& idleAnimation = storage.mIdleAnimation; idleAnimation = getRandomIdle(); - // If we should be moving if (!idleAnimation && mDistance) { storage.mState = Wander_MoveNow; return; } - // If we aren't going to just stand if(idleAnimation) { - // If the idle animation actually exists if(std::find(storage.mBadIdles.begin(), storage.mBadIdles.end(), idleAnimation)==storage.mBadIdles.end()) { if(!playIdle(actor, idleAnimation)) @@ -416,7 +413,6 @@ namespace MWMechanics // Recreate vanilla (broken?) behavior of resetting start time of AIWander: mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp(); storage.mState = Wander_IdleNow; - return; } void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) From 0244a9b32950c8a2caa777a21f6ec73894146e80 Mon Sep 17 00:00:00 2001 From: slothlife Date: Sat, 1 Aug 2015 07:57:05 -0500 Subject: [PATCH 190/419] Correct moon texture with respect to trajectory --- apps/openmw/mwrender/sky.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index cf20bc4c6..ea3f8e8bf 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -398,13 +398,19 @@ public: void setState(const MoonState& state) { float radsX = ((state.mRotationFromHorizon) * M_PI) / 180.0f; - float radsY = 0; float radsZ = ((state.mRotationFromNorth) * M_PI) / 180.0f; - osg::Quat rotation(radsX, osg::Vec3f(1.0f, 0.0f, 0.0f), - radsY, osg::Vec3f(0.0f, 1.0f, 0.0f), - radsZ, osg::Vec3f(0.0f, 0.0f, 1.0f)); - setDirection(rotation * osg::Vec3f(0.0f, 1.0f, 0.0f)); + osg::Quat rotX(radsX, osg::Vec3f(1.0f, 0.0f, 0.0f)); + osg::Quat rotZ(radsZ, osg::Vec3f(0.0f, 0.0f, 1.0f)); + + osg::Vec3f direction = rotX * rotZ * osg::Vec3f(0.0f, 1.0f, 0.0f); + mTransform->setPosition(direction * 1000.0f); + + // The moon quad is initially oriented facing down, so we need to offset its X-axis + // rotation to rotate it to face the camera when sitting at the horizon. + osg::Quat attX((-M_PI / 2.0f) + radsX, osg::Vec3f(1,0,0)); + mTransform->setAttitude(attX * rotZ); + setPhase(state.mPhase); setTransparency(state.mMoonAlpha); setShadowBlend(state.mShadowBlend); From afb36b73eb3edc81947a8b409197d8afc2cfa857 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 2 Aug 2015 15:03:27 +0300 Subject: [PATCH 191/419] Proper index for Modified column in ModifyCommand --- apps/opencs/model/world/commands.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 5e0cc8f88..019ffe7b2 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -33,7 +33,14 @@ CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelI { mHasRecordState = true; int stateColumnIndex = table->findColumnIndex(Columns::ColumnId_Modification); - mRecordStateIndex = table->index(mIndex.row(), stateColumnIndex); + + int rowIndex = mIndex.row(); + if (mIndex.parent().isValid()) + { + rowIndex = mIndex.parent().row(); + } + + mRecordStateIndex = table->index(rowIndex, stateColumnIndex); mOldRecordState = static_cast(table->data(mRecordStateIndex).toInt()); } } From 25b653e316ddfe92754aa22cb6cf468edda44e66 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 2 Aug 2015 15:06:56 +0300 Subject: [PATCH 192/419] Inform about Modified status change when modifying a value of a model --- apps/opencs/model/world/idtable.cpp | 6 +++++- apps/opencs/model/world/idtree.cpp | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 8ca19f7e9..bdbc5e0c4 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -77,7 +77,11 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value { mIdCollection->setData (index.row(), index.column(), value); - emit dataChanged (index, index); + // Modifying a value can also change the Modified status of a record. + // To track this, we inform about the change of a whole row. + QModelIndex rowStart = this->index(index.row(), 0); + QModelIndex rowEnd = this->index(index.row(), columnCount(index.parent()) - 1); + emit dataChanged(rowStart, rowEnd); return true; } diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 5a7d10c6e..0b027cdab 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -96,7 +96,13 @@ bool CSMWorld::IdTree::setData (const QModelIndex &index, const QVariant &value, mNestedCollection->setNestedData(parentAddress.first, parentAddress.second, value, index.row(), index.column()); - emit dataChanged (index, index); + emit dataChanged(index, index); + + // Modifying a value can also change the Modified status of a record (located in the parent row). + // To track this, we inform about the change of a whole parent row. + QModelIndex parentRowStart = this->index(index.parent().row(), 0); + QModelIndex parentRowEnd = this->index(index.parent().row(), columnCount(index.parent()) - 1); + emit dataChanged(parentRowStart, parentRowEnd); return true; } From 88c61ed2b6dabb11ae2760cf3095fd2004a4e031 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 2 Aug 2015 17:57:50 +0200 Subject: [PATCH 193/419] Fix NotifyDrawCompletedCallback in single threaded mode --- apps/openmw/mwrender/renderingmanager.cpp | 29 ++++++++++++++++++----- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c861119b5..54c6315fc 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -437,12 +437,31 @@ namespace MWRender class NotifyDrawCompletedCallback : public osg::Camera::DrawCallback { public: + NotifyDrawCompletedCallback() + : mDone(false) + { + } + virtual void operator () (osg::RenderInfo& renderInfo) const { + mMutex.lock(); + mDone = true; + mMutex.unlock(); mCondition.signal(); } + void waitTillDone() + { + mMutex.lock(); + if (mDone) + return; + mCondition.wait(&mMutex); + mMutex.unlock(); + } + mutable OpenThreads::Condition mCondition; + mutable OpenThreads::Mutex mMutex; + mutable bool mDone; }; void RenderingManager::screenshot(osg::Image *image, int w, int h) @@ -476,15 +495,13 @@ namespace MWRender mRootNode->addChild(rttCamera); - mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); - // The draw needs to complete before we can copy back our image. osg::ref_ptr callback (new NotifyDrawCompletedCallback); rttCamera->setFinalDrawCallback(callback); - OpenThreads::Mutex m; - m.lock(); - callback->mCondition.wait(&m); - m.unlock(); + + mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); + + callback->waitTillDone(); rttCamera->removeChildren(0, rttCamera->getNumChildren()); rttCamera->setGraphicsContext(NULL); From 664ae079db5db64e91ed152c0d69651a03ca066d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 2 Aug 2015 18:05:15 +0200 Subject: [PATCH 194/419] Improve setting of culling mask for the savegame screenshot camera --- apps/openmw/mwrender/renderingmanager.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 54c6315fc..b01095f12 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -466,9 +466,6 @@ namespace MWRender void RenderingManager::screenshot(osg::Image *image, int w, int h) { - int oldCullMask = mViewer->getCamera()->getCullMask(); - mViewer->getCamera()->setCullMask(oldCullMask & (~Mask_GUI)); - osg::ref_ptr rttCamera (new osg::Camera); rttCamera->setNodeMask(Mask_RenderToTexture); rttCamera->attach(osg::Camera::COLOR_BUFFER, image); @@ -492,6 +489,7 @@ namespace MWRender image->setPixelFormat(texture->getInternalFormat()); rttCamera->addChild(mLightRoot); + rttCamera->setCullMask(mViewer->getCamera()->getCullMask() & (~Mask_GUI)); mRootNode->addChild(rttCamera); @@ -506,8 +504,6 @@ namespace MWRender rttCamera->removeChildren(0, rttCamera->getNumChildren()); rttCamera->setGraphicsContext(NULL); mRootNode->removeChild(rttCamera); - - mViewer->getCamera()->setCullMask(oldCullMask); } osg::Vec4f RenderingManager::getScreenBounds(const MWWorld::Ptr& ptr) From 33042c14644532ae53f18fa2c60bd7aacd42357a Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 2 Aug 2015 17:16:06 +0300 Subject: [PATCH 195/419] Restore Modified status of a record when adding/removing nested rows --- apps/opencs/model/world/columnbase.hpp | 6 ++++++ apps/opencs/model/world/commands.cpp | 22 ++++++++++++++-------- apps/opencs/model/world/commands.hpp | 6 ++++++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 59f2836c2..c4789ed22 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -192,6 +192,12 @@ namespace CSMWorld ColumnBase::Display_NestedHeader, flags) {} + virtual void set (Record& record, const QVariant& data) + { + // There is nothing to do here. + // This prevents exceptions from parent's implementation + } + virtual QVariant get (const Record& record) const { return true; // required by IdTree::hasChildren() diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 019ffe7b2..7673e6bc9 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -289,21 +289,24 @@ CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTree& model, std::string title = model.headerData(parentColumn, Qt::Horizontal, Qt::DisplayRole).toString().toUtf8().constData(); setText (("Delete row in " + title + " sub-table of " + mId).c_str()); + + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); + mModifyParentCommand = new ModifyCommand(mModel, parentIndex, parentIndex.data(Qt::EditRole), this); } void CSMWorld::DeleteNestedCommand::redo() { - const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); mModel.removeRows (mNestedRow, 1, parentIndex); + mModifyParentCommand->redo(); } void CSMWorld::DeleteNestedCommand::undo() { - const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); mModel.setNestedTable(parentIndex, getOld()); + mModifyParentCommand->undo(); } CSMWorld::AddNestedCommand::AddNestedCommand(IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent) @@ -317,20 +320,23 @@ CSMWorld::AddNestedCommand::AddNestedCommand(IdTree& model, const std::string& i std::string title = model.headerData(parentColumn, Qt::Horizontal, Qt::DisplayRole).toString().toUtf8().constData(); setText (("Add row in " + title + " sub-table of " + mId).c_str()); + + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); + mModifyParentCommand = new ModifyCommand(mModel, parentIndex, parentIndex.data(Qt::EditRole), this); } void CSMWorld::AddNestedCommand::redo() { - const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); mModel.addNestedRow (parentIndex, mNewRow); + mModifyParentCommand->redo(); } void CSMWorld::AddNestedCommand::undo() { - const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - + QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn); mModel.setNestedTable(parentIndex, getOld()); + mModifyParentCommand->undo(); } CSMWorld::NestedTableStoring::NestedTableStoring(const IdTree& model, const std::string& id, int parentColumn) diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 81c40d0ab..23ffccbd7 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -200,6 +200,9 @@ namespace CSMWorld int mNestedRow; + // The command to redo/undo the Modified status of a record + ModifyCommand *mModifyParentCommand; + public: DeleteNestedCommand (IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); @@ -219,6 +222,9 @@ namespace CSMWorld int mParentColumn; + // The command to redo/undo the Modified status of a record + ModifyCommand *mModifyParentCommand; + public: AddNestedCommand(IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); From 1590a04d03a8385e7c4e496f32613e76ec339f7f Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 2 Aug 2015 22:39:41 +0300 Subject: [PATCH 196/419] Close EditWidget when a proper row removed --- apps/opencs/view/world/dialoguesubview.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 5a44708c1..d537f2eb1 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -811,8 +811,13 @@ void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); + + if (!currentIndex.isValid()) + { + return; + } - if (currentIndex.isValid() && currentIndex.row() >= start && currentIndex.row() <= end) + if (currentIndex.parent() == parent && currentIndex.row() >= start && currentIndex.row() <= end) { if(mEditWidget) { From 6b3de5c72025140868e763f81204728e49156ed3 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 2 Aug 2015 22:53:40 +0300 Subject: [PATCH 197/419] Activate editing of nested table cells by a double click --- apps/opencs/view/world/dialoguesubview.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index d537f2eb1..5ad2f76e2 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -570,8 +570,6 @@ void CSVWorld::EditWidget::remake(int row) table->setEditTriggers(QAbstractItemView::NoEditTriggers); table->setEnabled(false); } - else - table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged); int rows = mTable->rowCount(mTable->index(row, i)); int rowHeight = (rows == 0) ? table->horizontalHeader()->height() : table->rowHeight(0); From 0ea4d1981a6c01cf780948dbad8e9f1840004efc Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 3 Aug 2015 19:08:01 +0300 Subject: [PATCH 198/419] Add magic effect verifier --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/magiceffectcheck.cpp | 137 +++++++++++++++++++ apps/opencs/model/tools/magiceffectcheck.hpp | 50 +++++++ apps/opencs/model/tools/tools.cpp | 7 + 4 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/magiceffectcheck.cpp create mode 100644 apps/opencs/model/tools/magiceffectcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1a51d2d8d..e6dd045e1 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -41,7 +41,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck - startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck + startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck magiceffectcheck ) diff --git a/apps/opencs/model/tools/magiceffectcheck.cpp b/apps/opencs/model/tools/magiceffectcheck.cpp new file mode 100644 index 000000000..22620929c --- /dev/null +++ b/apps/opencs/model/tools/magiceffectcheck.cpp @@ -0,0 +1,137 @@ +#include "magiceffectcheck.hpp" + +#include + +#include "../world/resources.hpp" +#include "../world/data.hpp" + +namespace +{ + void addMessageIfNotEmpty(CSMDoc::Messages &messages, const CSMWorld::UniversalId &id, const std::string text) + { + if (!text.empty()) + { + messages.push_back(std::make_pair(id, text)); + } + } +} + +bool CSMTools::MagicEffectCheckStage::isTextureExists(const std::string &texture, bool isIcon) const +{ + const CSMWorld::Resources &textures = isIcon ? mIcons : mTextures; + bool exists = false; + + if (textures.searchId(texture) != -1) + { + exists = true; + } + else + { + std::string ddsTexture = texture; + if (Misc::ResourceHelpers::changeExtensionToDds(ddsTexture) && textures.searchId(ddsTexture) != -1) + { + exists = true; + } + } + + return exists; +} + +std::string CSMTools::MagicEffectCheckStage::checkReferenceable(const std::string &id, + const CSMWorld::UniversalId &type, + const std::string &column) const +{ + std::string error; + if (!id.empty()) + { + CSMWorld::RefIdData::LocalIndex index = mReferenceables.getDataSet().searchId(id); + if (index.first == -1) + { + error = "No such " + column + " '" + id + "'"; + } + else if (index.second != type.getType()) + { + error = column + " is not of type " + type.getTypeName(); + } + } + return error; +} + +std::string CSMTools::MagicEffectCheckStage::checkSound(const std::string &id, const std::string &column) const +{ + std::string error; + if (!id.empty() && mSounds.searchId(id) == -1) + { + error = "No such " + column + " '" + id + "'"; + } + return error; +} + +CSMTools::MagicEffectCheckStage::MagicEffectCheckStage(const CSMWorld::IdCollection &effects, + const CSMWorld::IdCollection &sounds, + const CSMWorld::RefIdCollection &referenceables, + const CSMWorld::Resources &icons, + const CSMWorld::Resources &textures) + : mMagicEffects(effects), + mSounds(sounds), + mReferenceables(referenceables), + mIcons(icons), + mTextures(textures) +{} + +int CSMTools::MagicEffectCheckStage::setup() +{ + return mMagicEffects.getSize(); +} + +void CSMTools::MagicEffectCheckStage::perform(int stage, CSMDoc::Messages &messages) +{ + ESM::MagicEffect effect = mMagicEffects.getRecord(stage).get(); + CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_MagicEffect, effect.mId); + + if (effect.mData.mBaseCost < 0.0f) + { + messages.push_back(std::make_pair(id, "Base Cost is negative")); + } + + if (effect.mIcon.empty()) + { + messages.push_back(std::make_pair(id, "Icon is not specified")); + } + else if (!isTextureExists(effect.mIcon, true)) + { + messages.push_back(std::make_pair(id, "No such Icon '" + effect.mIcon + "'")); + } + + if (effect.mParticle.empty()) + { + messages.push_back(std::make_pair(id, "Particle is not specified")); + } + else if (!isTextureExists(effect.mParticle, false)) + { + messages.push_back(std::make_pair(id, "No such Particle '" + effect.mParticle + "'")); + } + + addMessageIfNotEmpty(messages, + id, + checkReferenceable(effect.mCasting, CSMWorld::UniversalId::Type_Static, "Casting Object")); + addMessageIfNotEmpty(messages, + id, + checkReferenceable(effect.mHit, CSMWorld::UniversalId::Type_Static, "Hit Object")); + addMessageIfNotEmpty(messages, + id, + checkReferenceable(effect.mArea, CSMWorld::UniversalId::Type_Static, "Area Object")); + addMessageIfNotEmpty(messages, + id, + checkReferenceable(effect.mBolt, CSMWorld::UniversalId::Type_Weapon, "Bolt Object")); + + addMessageIfNotEmpty(messages, id, checkSound(effect.mCastSound, "Casting Sound")); + addMessageIfNotEmpty(messages, id, checkSound(effect.mHitSound, "Hit Sound")); + addMessageIfNotEmpty(messages, id, checkSound(effect.mAreaSound, "Area Sound")); + addMessageIfNotEmpty(messages, id, checkSound(effect.mBoltSound, "Bolt Sound")); + + if (effect.mDescription.empty()) + { + messages.push_back(std::make_pair(id, "Description is empty")); + } +} diff --git a/apps/opencs/model/tools/magiceffectcheck.hpp b/apps/opencs/model/tools/magiceffectcheck.hpp new file mode 100644 index 000000000..0ad6760d3 --- /dev/null +++ b/apps/opencs/model/tools/magiceffectcheck.hpp @@ -0,0 +1,50 @@ +#ifndef CSM_TOOLS_MAGICEFFECTCHECK_HPP +#define CSM_TOOLS_MAGICEFFECTCHECK_HPP + +#include +#include + +#include "../world/idcollection.hpp" +#include "../world/refidcollection.hpp" + +#include "../doc/stage.hpp" + +namespace CSMWorld +{ + class Resources; +} + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that magic effect records are internally consistent + class MagicEffectCheckStage : public CSMDoc::Stage + { + const CSMWorld::IdCollection &mMagicEffects; + const CSMWorld::IdCollection &mSounds; + const CSMWorld::RefIdCollection &mReferenceables; + const CSMWorld::Resources &mIcons; + const CSMWorld::Resources &mTextures; + + private: + bool isTextureExists(const std::string &texture, bool isIcon) const; + + std::string checkReferenceable(const std::string &id, + const CSMWorld::UniversalId &type, + const std::string &column) const; + std::string checkSound(const std::string &id, const std::string &column) const; + + public: + MagicEffectCheckStage(const CSMWorld::IdCollection &effects, + const CSMWorld::IdCollection &sounds, + const CSMWorld::RefIdCollection &referenceables, + const CSMWorld::Resources &icons, + const CSMWorld::Resources &textures); + + virtual int setup(); + ///< \return number of steps + virtual void perform (int stage, CSMDoc::Messages &messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index c9c116091..97943b1fb 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -28,6 +28,7 @@ #include "searchoperation.hpp" #include "pathgridcheck.hpp" #include "soundgencheck.hpp" +#include "magiceffectcheck.hpp" CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { @@ -108,6 +109,12 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() mData.getSounds(), mData.getReferenceables())); + mVerifierOperation->appendStage (new MagicEffectCheckStage (mData.getMagicEffects(), + mData.getSounds(), + mData.getReferenceables(), + mData.getResources (CSMWorld::UniversalId::Type_Icons), + mData.getResources (CSMWorld::UniversalId::Type_Textures))); + mVerifier.setOperation (mVerifierOperation); } From 8da9eecea755e19b8d1719e0183243a517a36591 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 3 Aug 2015 19:24:00 +0300 Subject: [PATCH 199/419] Correct comparison of enum values in IdTableProxyModel --- apps/opencs/model/world/idtableproxymodel.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 10fd92b46..757285412 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -5,6 +5,18 @@ #include "idtablebase.hpp" +namespace +{ + std::string getEnumValue(const std::vector &values, int index) + { + if (index < 0 || index >= static_cast(values.size())) + { + return ""; + } + return values[index]; + } +} + void CSMWorld::IdTableProxyModel::updateColumnMap() { Q_ASSERT(mSourceModel != NULL); @@ -93,7 +105,9 @@ bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModel if (valuesIt != mEnumColumnCache.end()) { - return valuesIt->second[left.data().toInt()] < valuesIt->second[right.data().toInt()]; + std::string first = getEnumValue(valuesIt->second, left.data().toInt()); + std::string second = getEnumValue(valuesIt->second, right.data().toInt()); + return first < second; } return QSortFilterProxyModel::lessThan(left, right); } From 21e249cb9234b6b40a9e5e15ceb92ab7e3d3c0b4 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 4 Aug 2015 18:14:36 +1200 Subject: [PATCH 200/419] pass parameters as const & --- apps/openmw/mwmechanics/pathfinding.cpp | 8 ++++---- apps/openmw/mwmechanics/pathfinding.hpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 79cee9f32..c7d71e13e 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -87,14 +87,14 @@ namespace namespace MWMechanics { - float sqrDistanceIgnoreZ(ESM::Pathgrid::Point point, float x, float y) + float sqrDistanceIgnoreZ(const ESM::Pathgrid::Point& point, float x, float y) { x -= point.mX; y -= point.mY; return (x * x + y * y); } - float distance(ESM::Pathgrid::Point point, float x, float y, float z) + float distance(const ESM::Pathgrid::Point& point, float x, float y, float z) { x -= point.mX; y -= point.mY; @@ -102,7 +102,7 @@ namespace MWMechanics return sqrt(x * x + y * y + z * z); } - float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b) + float distance(const ESM::Pathgrid::Point& a, const ESM::Pathgrid::Point& b) { float x = static_cast(a.mX - b.mX); float y = static_cast(a.mY - b.mY); @@ -272,7 +272,7 @@ namespace MWMechanics if(mPath.empty()) return true; - ESM::Pathgrid::Point nextPoint = *mPath.begin(); + const ESM::Pathgrid::Point& nextPoint = *mPath.begin(); if (sqrDistanceIgnoreZ(nextPoint, x, y) < tolerance*tolerance) { mPath.pop_front(); diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 4000f5d80..1765a5cc5 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -12,8 +12,8 @@ namespace MWWorld namespace MWMechanics { - float distance(ESM::Pathgrid::Point point, float x, float y, float); - float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b); + float distance(const ESM::Pathgrid::Point& point, float x, float y, float); + float distance(const ESM::Pathgrid::Point& a, const ESM::Pathgrid::Point& b); class PathFinder { public: From 4256e151b131453ca045fae270565e6a71e656b9 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 4 Aug 2015 18:15:58 +1200 Subject: [PATCH 201/419] Fixed error in deciding type of attack --- apps/openmw/mwmechanics/aicombat.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index dd843b9a3..776641e60 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -689,16 +689,14 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: int chop = (weapon->mData.mChop[0] + weapon->mData.mChop[1])/2; int thrust = (weapon->mData.mThrust[0] + weapon->mData.mThrust[1])/2; - float total = static_cast(slash + chop + thrust); - - float roll = Misc::Rng::rollClosedProbability(); - if(roll <= (slash/total)) + float roll = Misc::Rng::rollClosedProbability() * (slash + chop + thrust); + if(roll <= slash) { movement.mPosition[0] = (Misc::Rng::rollClosedProbability() < 0.5f) ? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } - else if(roll <= (slash + (thrust/total))) + else if(roll <= (slash + thrust)) { movement.mPosition[1] = 1; attackType = ESM::Weapon::AT_Thrust; From ad9bab0b68f91a59d93f4b538d7575481149c466 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 4 Aug 2015 18:17:08 +1200 Subject: [PATCH 202/419] Removed redundant if. --- apps/openmw/mwmechanics/aicombat.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 776641e60..560be888c 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -503,12 +503,14 @@ namespace MWMechanics } // don't use pathgrid when actor can move in 3 dimensions - if(canMoveByZ) preferShortcut = true; + if (canMoveByZ) + { + preferShortcut = true; + movement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); + } if(preferShortcut) { - if (canMoveByZ) - movement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); movement.mRotation[2] = getZAngleToDir(vDirToTarget); forceNoShortcut = false; shortcutFailPos.pos[0] = shortcutFailPos.pos[1] = shortcutFailPos.pos[2] = 0; From 58f732ebc9f1cd88f04814caa8b7af66ce5a86fe Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 4 Aug 2015 18:20:05 +1200 Subject: [PATCH 203/419] Update path following checks each frame in AiCombat. --- apps/openmw/mwmechanics/aicombat.cpp | 38 ++++++++++++++++++---------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 560be888c..f386ec81b 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -429,6 +429,7 @@ namespace MWMechanics // (within attack dist) || (not quite attack dist while following) if(inLOS && (distToTarget < rangeAttack || (distToTarget <= rangeFollow && followTarget && !isStuck))) { + mPathFinder.clearPath(); //Melee and Close-up combat // getXAngleToDir determines vertical angle to target: @@ -528,9 +529,7 @@ namespace MWMechanics buildNewPath(actor, target); //may fail to build a path, check before use - //delete visited path node - mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1]); - + // if current actor pos is closer to target then last point of path (excluding target itself) then go straight on target // This works on the borders between the path grid and areas with no waypoints. if(inLOS && mPathFinder.getPath().size() > 1) { @@ -539,21 +538,16 @@ namespace MWMechanics --pntIter; osg::Vec3f vBeforeTarget(PathFinder::MakeOsgVec3(*pntIter)); - // if current actor pos is closer to target then last point of path (excluding target itself) then go straight on target if(distToTarget <= (vTargetPos - vBeforeTarget).length()) { - movement.mRotation[2] = getZAngleToDir(vDirToTarget); - preferShortcut = true; + mPathFinder.clearPath(); } } // if there is no new path, then go straight on target - if(!preferShortcut) + if (!mPathFinder.isPathConstructed()) { - if(!mPathFinder.getPath().empty()) - movement.mRotation[2] = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); - else - movement.mRotation[2] = getZAngleToDir(vDirToTarget); + movement.mRotation[2] = getZAngleToDir(vDirToTarget); } } @@ -573,9 +567,25 @@ namespace MWMechanics void AiCombat::UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& desiredMovement) { MWMechanics::Movement& actorMovementSettings = actor.getClass().getMovementSettings(actor); - actorMovementSettings = desiredMovement; - RotateActorOnAxis(actor, 2, actorMovementSettings, desiredMovement); - RotateActorOnAxis(actor, 0, actorMovementSettings, desiredMovement); + if (mPathFinder.isPathConstructed()) + { + const ESM::Position& pos = actor.getRefData().getPosition(); + if (mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1])) + { + actorMovementSettings.mPosition[1] = 0; + } + else + { + zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); + actorMovementSettings.mPosition[1] = 1; + } + } + else + { + actorMovementSettings = desiredMovement; + RotateActorOnAxis(actor, 2, actorMovementSettings, desiredMovement); + RotateActorOnAxis(actor, 0, actorMovementSettings, desiredMovement); + } } void AiCombat::RotateActorOnAxis(const MWWorld::Ptr& actor, int axis, From 581ea2660522dbefedd197753dac380298e001d2 Mon Sep 17 00:00:00 2001 From: Alexandre Moine Date: Tue, 4 Aug 2015 13:05:29 +0200 Subject: [PATCH 204/419] Add appdata file for openmw and install it --- CMakeLists.txt | 3 +++ files/openmw.appdata.xml | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 files/openmw.appdata.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index a14beb423..99fb56fbe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -334,6 +334,8 @@ configure_file(${OpenMW_SOURCE_DIR}/files/gamecontrollerdb.txt if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop "${OpenMW_BINARY_DIR}/openmw.desktop") + configure_file(${OpenMW_SOURCE_DIR}/files/openmw.appdata.xml + "${OpenMW_BINARY_DIR}/openmw.appdata.xml") configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.desktop "${OpenMW_BINARY_DIR}/openmw-cs.desktop") endif() @@ -422,6 +424,7 @@ IF(NOT WIN32 AND NOT APPLE) # Install icon and desktop file INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.appdata.xml" DESTINATION "${DATAROOTDIR}/appdata" COMPONENT "openmw") IF(BUILD_OPENCS) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "opencs") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" COMPONENT "opencs") diff --git a/files/openmw.appdata.xml b/files/openmw.appdata.xml new file mode 100644 index 000000000..150eea984 --- /dev/null +++ b/files/openmw.appdata.xml @@ -0,0 +1,39 @@ + + + + openmw.desktop + CC0-1.0 + GPL-3.0 and MIT and zlib + OpenMW + Unofficial open source engine re-implementation of the game Morrowind + +

    + OpenMW is a recreation of 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. +

    +

    + The main quests in Morrowind, Tribunal and Bloodmoon are all completable. Some issues with side quests are to be expected (but rare). +

    +

    + Pre-existing modifications created for the original Morrowind engine can be hit-and-miss, but a mod created for Morrowind may not necessarily run in OpenMW. +

    +
    + + + + http://wiki.openmw.org/images/b/b2/Openmw_0.11.1_launcher_1.png + The OpenMW launcher + + + http://wiki.openmw.org/images/f/f1/Screenshot_mournhold_plaza_0.35.png + The Mournhold's plaza on OpenMW + + + http://wiki.openmw.org/images/5/5b/Screenshot_Vivec_seen_from_Ebonheart_0.35.png + Vivec seen from Ebonheart on OpenMW + + +nobrakal@gmail.com + https://openmw.org + https://bugs.openmw.org/ + https://openmw.org/faq/ +
    From cbc8309289c9f4dc9fe4603cb04565e878b6addc Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 4 Aug 2015 16:19:00 +0300 Subject: [PATCH 205/419] Don't allow empty value of School field in Magic Effects table --- apps/opencs/view/doc/viewmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 7aec001cf..0db51dfd2 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -97,7 +97,7 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_MeshType, CSMWorld::Columns::ColumnId_MeshType, false }, { CSMWorld::ColumnBase::Display_Gender, CSMWorld::Columns::ColumnId_Gender, true }, { CSMWorld::ColumnBase::Display_SoundGeneratorType, CSMWorld::Columns::ColumnId_SoundGeneratorType, false }, - { CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, true }, + { CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, false }, { CSMWorld::ColumnBase::Display_SkillImpact, CSMWorld::Columns::ColumnId_SkillImpact, true }, { CSMWorld::ColumnBase::Display_EffectRange, CSMWorld::Columns::ColumnId_EffectRange, false }, { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false }, From 8ae7c63c456985cea6198e9085023c5d7ce03c4b Mon Sep 17 00:00:00 2001 From: "taras.kudryavtsev" Date: Tue, 4 Aug 2015 16:56:05 +0300 Subject: [PATCH 206/419] #2730 and #2725 --- apps/opencs/model/world/columnbase.cpp | 1 - apps/opencs/model/world/columnbase.hpp | 1 - apps/opencs/model/world/refidcollection.cpp | 2 +- apps/opencs/view/doc/viewmanager.cpp | 2 +- apps/opencs/view/world/dialoguesubview.cpp | 24 ++++++++++++++------- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index f209e48c6..2143ec730 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -82,7 +82,6 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_EffectId, Display_PartRefType, Display_AiPackageType, - Display_YesNo, Display_InfoCondFunc, Display_InfoCondVar, Display_InfoCondComp, diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index c4789ed22..400e31333 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -118,7 +118,6 @@ namespace CSMWorld Display_EffectId, Display_PartRefType, Display_AiPackageType, - Display_YesNo, Display_InfoCondFunc, Display_InfoCondVar, Display_InfoCondComp, diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 5495926b4..947454d77 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -198,7 +198,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiWanderIdle, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_YesNo)); + new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_Boolean)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_AiActivateName, CSMWorld::ColumnBase::Display_String)); mColumns.back().addColumn( diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 7aec001cf..cc91a5d72 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -103,7 +103,7 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false }, { CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false }, { CSMWorld::ColumnBase::Display_AiPackageType, CSMWorld::Columns::ColumnId_AiPackageType, false }, - { CSMWorld::ColumnBase::Display_YesNo, CSMWorld::Columns::ColumnId_AiWanderRepeat, false }, + { CSMWorld::ColumnBase::Display_Boolean, CSMWorld::Columns::ColumnId_AiWanderRepeat, false }, { CSMWorld::ColumnBase::Display_InfoCondFunc, CSMWorld::Columns::ColumnId_InfoCondFunc, false }, { CSMWorld::ColumnBase::Display_InfoCondComp, CSMWorld::Columns::ColumnId_InfoCondComp, false }, { CSMWorld::ColumnBase::Display_RaceSkill, CSMWorld::Columns::ColumnId_RaceSkill, true }, diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 5ad2f76e2..2bfde4b22 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -740,13 +740,15 @@ CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::Universa mMainLayout = new QVBoxLayout(mainWidget); setWidget (mainWidget); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + mEditWidget = new EditWidget(mainWidget, - mTable->getModelIndex(getUniversalId().getId(), 0).row(), mTable, mCommandDispatcher, document, false); + mTable->getModelIndex(getUniversalId().getId(), idColumn).row(), mTable, mCommandDispatcher, document, false); mMainLayout->addWidget(mEditWidget); mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - dataChanged(mTable->getModelIndex (getUniversalId().getId(), 0)); + dataChanged(mTable->getModelIndex (getUniversalId().getId(), idColumn)); connect(mEditWidget, SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)), @@ -759,8 +761,9 @@ void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked) if (!mEditWidget) // hack to indicate that getUniversalId().getId() is no longer valid return; + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); mLocked = locked; - QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); + QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), idColumn)); if (currentIndex.isValid()) { @@ -775,7 +778,8 @@ void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked) void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) { - QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), idColumn)); if (currentIndex.isValid() && (index.parent().isValid() ? index.parent().row() : index.row()) == currentIndex.row()) @@ -808,7 +812,8 @@ void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { - QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), idColumn)); if (!currentIndex.isValid()) { @@ -906,7 +911,8 @@ void CSVWorld::DialogueSubView::updateUserSetting (const QString& name, const QS void CSVWorld::DialogueSubView::showPreview () { - QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), 0)); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), idColumn)); if (currentIndex.isValid() && getTable().getFeatures() & CSMWorld::IdTable::Feature_Preview && @@ -918,7 +924,8 @@ void CSVWorld::DialogueSubView::showPreview () void CSVWorld::DialogueSubView::viewRecord () { - QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), 0)); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), idColumn)); if (currentIndex.isValid() && currentIndex.row() < getTable().rowCount()) @@ -953,7 +960,8 @@ void CSVWorld::DialogueSubView::switchToRow (int row) void CSVWorld::DialogueSubView::requestFocus (const std::string& id) { - QModelIndex index = getTable().getModelIndex (id, 0); + int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id); + QModelIndex index = getTable().getModelIndex (id, idColumn); if (index.isValid()) switchToRow (index.row()); From 8c8c5328dc8f8c96a70ebe0eb765fae573f1922a Mon Sep 17 00:00:00 2001 From: Alexandre Moine Date: Tue, 4 Aug 2015 22:50:53 +0200 Subject: [PATCH 207/419] Rewrite of the description --- files/openmw.appdata.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/openmw.appdata.xml b/files/openmw.appdata.xml index 150eea984..1c16cb9a4 100644 --- a/files/openmw.appdata.xml +++ b/files/openmw.appdata.xml @@ -8,13 +8,13 @@ Unofficial open source engine re-implementation of the game Morrowind

    - OpenMW is a recreation of 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. + OpenMW is a new engine for 2002's Game of the Year, The Elder Scrolls 3: Morrowind.

    - The main quests in Morrowind, Tribunal and Bloodmoon are all completable. Some issues with side quests are to be expected (but rare). + It aims to be a fully playable (and improved!), open source implementation of the game's engine and functionality (including mods).

    - Pre-existing modifications created for the original Morrowind engine can be hit-and-miss, but a mod created for Morrowind may not necessarily run in OpenMW. + You will still need the original game data to play OpenMW.

    From ea2f88a355f7c1aeaad26fced87a70863f72ad6a Mon Sep 17 00:00:00 2001 From: slothlife Date: Tue, 4 Aug 2015 21:07:42 -0500 Subject: [PATCH 208/419] Fix several sky rendering bugs, maybe also #639 Added code to hide the moons, sun, and stars for certain weather effects. Lightly refactored CelestialBody and derived classes. Fixed moons switching phase at 24:00. --- apps/openmw/mwrender/sky.cpp | 318 ++++++++++++++++---------------- apps/openmw/mwrender/sky.hpp | 58 +++++- apps/openmw/mwworld/weather.cpp | 37 +++- apps/openmw/mwworld/weather.hpp | 54 +----- 4 files changed, 248 insertions(+), 219 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 8330835a6..3a2da230f 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -322,11 +321,12 @@ private: int mMeshType; }; -class CelestialBody +// A base class for the sun and moons. Must be stored in an osg::ref_ptr due to being +// derived from osg::Referenced. +class CelestialBody : public SceneUtil::StateSetUpdater { public: - CelestialBody(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor = 1.f, int numUvSets=1) - : mSceneManager(sceneManager) + CelestialBody(osg::Group* parentNode, float scaleFactor = 1.f, int numUvSets=1) { mGeode = new osg::Geode; osg::ref_ptr geom = createTexturedQuad(numUvSets); @@ -336,42 +336,85 @@ public: mTransform->addChild(mGeode); parentNode->addChild(mTransform); + + mGeode->addUpdateCallback(this); } - void setDirection(const osg::Vec3f& direction) + virtual ~CelestialBody() { - osg::Vec3f normalizedDirection = direction / direction.length(); - mTransform->setPosition(normalizedDirection*1000.f); - - osg::Quat quat; - quat.makeRotate(osg::Vec3f(0,0,1), normalizedDirection); - mTransform->setAttitude(quat); + mGeode->removeUpdateCallback(this); } + virtual void adjustTransparency(const float ratio) = 0; + void setVisible(bool visible) { mTransform->setNodeMask(visible ? ~0 : 0); } protected: + static const float mDistance; osg::ref_ptr mTransform; osg::ref_ptr mGeode; - Resource::SceneManager* mSceneManager; - }; +const float CelestialBody::mDistance = 1000.0f; + class Sun : public CelestialBody { public: - Sun(osg::Group* parentNode, Resource::SceneManager* sceneManager) - : CelestialBody(parentNode, sceneManager, 1.f, 1) + Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) + : CelestialBody(parentNode, 1.0f, 1) + , mColor(1.0f, 1.0f, 1.0f, 1.0f) + , mDummyTexture(textureManager.getWarningTexture()) { - osg::ref_ptr tex = mSceneManager->getTextureManager()->getTexture2D("textures/tx_sun_05.dds", - osg::Texture::CLAMP, osg::Texture::CLAMP); + osg::ref_ptr tex = textureManager.getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, + osg::Texture::CLAMP); mTransform->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); mTransform->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); } + + virtual void setDefaults(osg::StateSet* stateset) + { + osg::ref_ptr texEnv(new osg::TexEnvCombine); + texEnv->setCombine_Alpha(osg::TexEnvCombine::MODULATE); + texEnv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); + texEnv->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); + texEnv->setCombine_RGB(osg::TexEnvCombine::REPLACE); + texEnv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + texEnv->setConstantColor(osg::Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); + + stateset->setTextureAttributeAndModes(1, mDummyTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + stateset->setTextureAttributeAndModes(1, texEnv, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) + { + osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); + texEnv->setConstantColor(mColor); + } + + virtual void adjustTransparency(const float ratio) + { + mColor.a() = ratio; + } + + void setDirection(const osg::Vec3f& direction) + { + osg::Vec3f normalizedDirection = direction / direction.length(); + mTransform->setPosition(normalizedDirection * mDistance); + + osg::Quat quat; + quat.makeRotate(osg::Vec3f(0.0f, 0.0f, 1.0f), normalizedDirection); + mTransform->setAttitude(quat); + } + +private: + + osg::Vec4f mColor; + osg::ref_ptr mDummyTexture; }; class Moon : public CelestialBody @@ -383,18 +426,57 @@ public: Type_Secunda }; - Moon(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor, Type type) - : CelestialBody(parentNode, sceneManager, scaleFactor, 2) + Moon(osg::Group* parentNode, Resource::TextureManager& textureManager, float scaleFactor, Type type) + : CelestialBody(parentNode, scaleFactor, 2) + , mTextureManager(textureManager) , mType(type) , mPhase(MoonState::Phase_Unspecified) + , mTransparency(1.0f) + , mShadowBlend(1.0f) + , mMoonColor(1.0f, 1.0f, 1.0f, 1.0f) { - mUpdater = new MoonUpdater; - mGeode->addUpdateCallback(mUpdater); - setPhase(MoonState::Phase_Full); setVisible(true); } + virtual void setDefaults(osg::StateSet *stateset) + { + stateset->setTextureAttributeAndModes(0, mPhaseTex, osg::StateAttribute::ON); + osg::ref_ptr texEnv = new osg::TexEnvCombine; + texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); + texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); + texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); + texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // mShadowBlend * mMoonColor + stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); + + stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); + osg::ref_ptr texEnv2 = new osg::TexEnvCombine; + texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD); + texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); + texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE); + texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); + texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); + texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // mAtmosphereColor.rgb, mTransparency + stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); + + stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) + { + osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); + texEnv->setConstantColor(mMoonColor * mShadowBlend); + + osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); + texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency)); + } + + virtual void adjustTransparency(const float ratio) + { + mTransparency *= ratio; + } + void setState(const MoonState& state) { float radsX = ((state.mRotationFromHorizon) * M_PI) / 180.0f; @@ -404,27 +486,59 @@ public: osg::Quat rotZ(radsZ, osg::Vec3f(0.0f, 0.0f, 1.0f)); osg::Vec3f direction = rotX * rotZ * osg::Vec3f(0.0f, 1.0f, 0.0f); - mTransform->setPosition(direction * 1000.0f); + mTransform->setPosition(direction * mDistance); // The moon quad is initially oriented facing down, so we need to offset its X-axis // rotation to rotate it to face the camera when sitting at the horizon. - osg::Quat attX((-M_PI / 2.0f) + radsX, osg::Vec3f(1,0,0)); + osg::Quat attX((-M_PI / 2.0f) + radsX, osg::Vec3f(1.0f, 0.0f, 0.0f)); mTransform->setAttitude(attX * rotZ); setPhase(state.mPhase); - setTransparency(state.mMoonAlpha); - setShadowBlend(state.mShadowBlend); + mTransparency = state.mMoonAlpha; + mShadowBlend = state.mShadowBlend; } + void setAtmosphereColor(const osg::Vec4f& color) + { + mAtmosphereColor = color; + } + + void setColor(const osg::Vec4f& color) + { + mMoonColor = color; + } + + unsigned int getPhaseInt() const + { + if (mPhase == MoonState::Phase_New) return 0; + else if (mPhase == MoonState::Phase_WaxingCrescent) return 1; + else if (mPhase == MoonState::Phase_WaningCrescent) return 1; + else if (mPhase == MoonState::Phase_FirstQuarter) return 2; + else if (mPhase == MoonState::Phase_ThirdQuarter) return 2; + else if (mPhase == MoonState::Phase_WaxingGibbous) return 3; + else if (mPhase == MoonState::Phase_WaningGibbous) return 3; + else if (mPhase == MoonState::Phase_Full) return 4; + return 0; + } + +private: + + Resource::TextureManager& mTextureManager; + Type mType; + MoonState::Phase mPhase; + float mTransparency; + float mShadowBlend; + osg::Vec4f mAtmosphereColor; + osg::Vec4f mMoonColor; + osg::ref_ptr mPhaseTex; + osg::ref_ptr mCircleTex; + void setTextures(const std::string& phaseTex, const std::string& circleTex) { - osg::ref_ptr phaseTexPtr = mSceneManager->getTextureManager()->getTexture2D(phaseTex, - osg::Texture::CLAMP, osg::Texture::CLAMP); + mPhaseTex = mTextureManager.getTexture2D(phaseTex, osg::Texture::CLAMP, osg::Texture::CLAMP); + mCircleTex = mTextureManager.getTexture2D(circleTex, osg::Texture::CLAMP, osg::Texture::CLAMP); - osg::ref_ptr circleTexPtr = mSceneManager->getTextureManager()->getTexture2D(circleTex, - osg::Texture::CLAMP, osg::Texture::CLAMP); - - mUpdater->setTextures(phaseTexPtr, circleTexPtr); + reset(); } void setPhase(const MoonState::Phase& phase) @@ -454,129 +568,6 @@ public: else setTextures(textureName, "textures/tx_mooncircle_full_m.dds"); } - - void setType(const Type& type) - { - mType = type; - } - - class MoonUpdater : public SceneUtil::StateSetUpdater - { - public: - MoonUpdater() - : mTransparency(1.0f) - , mShadowBlend(1.0f) - , mMoonColor(1,1,1,1) - { - } - - virtual void setDefaults(osg::StateSet *stateset) - { - stateset->setTextureAttributeAndModes(0, mPhaseTex, osg::StateAttribute::ON); - osg::ref_ptr texEnv = new osg::TexEnvCombine; - texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); - texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); - texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); - texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // mShadowBlend * mMoonColor - stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); - - stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); - osg::ref_ptr texEnv2 = new osg::TexEnvCombine; - texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD); - texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); - texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE); - texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); - texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); - texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); - texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // mAtmosphereColor.rgb, mTransparency - stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); - - stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - } - - virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) - { - osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); - texEnv->setConstantColor(mMoonColor * mShadowBlend); - - osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); - texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency)); - } - - void setTransparency(const float ratio) - { - mTransparency = ratio; - } - - void setShadowBlend(const float blendFactor) - { - mShadowBlend = blendFactor; - } - - void setAtmosphereColor(const osg::Vec4f& color) - { - mAtmosphereColor = color; - } - - void setMoonColor(const osg::Vec4f& color) - { - mMoonColor = color; - } - - void setTextures(osg::ref_ptr phaseTex, osg::ref_ptr circleTex) - { - mPhaseTex = phaseTex; - mCircleTex = circleTex; - reset(); - } - - private: - float mTransparency; - float mShadowBlend; - osg::Vec4f mAtmosphereColor; - osg::Vec4f mMoonColor; - osg::ref_ptr mPhaseTex; - osg::ref_ptr mCircleTex; - }; - - - void setAtmosphereColor(const osg::Vec4f& color) - { - mUpdater->setAtmosphereColor(color); - } - - void setColor(const osg::Vec4f& color) - { - mUpdater->setMoonColor(color); - } - - void setTransparency(const float ratio) - { - mUpdater->setTransparency(ratio); - } - - void setShadowBlend(const float blendFactor) - { - mUpdater->setShadowBlend(blendFactor); - } - - unsigned int getPhaseInt() const - { - if (mPhase == MoonState::Phase_New) return 0; - else if (mPhase == MoonState::Phase_WaxingCrescent) return 1; - else if (mPhase == MoonState::Phase_WaningCrescent) return 1; - else if (mPhase == MoonState::Phase_FirstQuarter) return 2; - else if (mPhase == MoonState::Phase_ThirdQuarter) return 2; - else if (mPhase == MoonState::Phase_WaxingGibbous) return 3; - else if (mPhase == MoonState::Phase_WaningGibbous) return 3; - else if (mPhase == MoonState::Phase_Full) return 4; - return 0; - } - -private: - Type mType; - MoonState::Phase mPhase; - osg::ref_ptr mUpdater; }; SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) @@ -641,11 +632,11 @@ void SkyManager::create() mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getTextureManager()); atmosphereNight->addUpdateCallback(mAtmosphereNightUpdater); - mSun.reset(new Sun(mRootNode, mSceneManager)); + mSun = new Sun(mRootNode, *mSceneManager->getTextureManager()); const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mMasser.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser)); - mSecunda.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda)); + mMasser = new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser); + mSecunda = new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda); mCloudNode = new osg::PositionAttitudeTransform; mRootNode->addChild(mCloudNode); @@ -970,7 +961,7 @@ void SkyManager::updateRainParameters() } } -void SkyManager::setWeather(const MWWorld::WeatherResult& weather) +void SkyManager::setWeather(const WeatherResult& weather) { if (!mCreated) return; @@ -1087,9 +1078,14 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) mCloudSpeed = weather.mCloudSpeed; - if (weather.mNight && mStarsOpacity != weather.mNightFade) + mMasser->adjustTransparency(weather.mCelestialBodyTransparency); + mSecunda->adjustTransparency(weather.mCelestialBodyTransparency); + mSun->adjustTransparency(weather.mCelestialBodyTransparency); + + float nextStarsOpacity = weather.mNightFade * weather.mCelestialBodyTransparency; + if(weather.mNight && mStarsOpacity != nextStarsOpacity) { - mStarsOpacity = weather.mNightFade; + mStarsOpacity = nextStarsOpacity; mAtmosphereNightUpdater->setFade(mStarsOpacity); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index eb953d128..16509ef32 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -1,9 +1,11 @@ #ifndef OPENMW_MWRENDER_SKY_H #define OPENMW_MWRENDER_SKY_H -#include +#include -#include "../mwworld/weather.hpp" +#include +#include +#include namespace osg { @@ -33,6 +35,50 @@ namespace MWRender class RainFader; class AlphaFader; + struct WeatherResult + { + std::string mCloudTexture; + std::string mNextCloudTexture; + float mCloudBlendFactor; + + osg::Vec4f mFogColor; + + osg::Vec4f mAmbientColor; + + osg::Vec4f mSkyColor; + + osg::Vec4f mSunColor; + + osg::Vec4f mSunDiscColor; + + float mFogDepth; + + float mWindSpeed; + + float mCloudSpeed; + + float mCloudOpacity; + + float mGlareView; + + bool mNight; // use night skybox + float mNightFade; // fading factor for night skybox + + bool mIsStorm; + + std::string mAmbientLoopSoundID; + float mAmbientSoundVolume; + + std::string mParticleEffect; + std::string mRainEffect; + float mEffectFade; + + float mRainSpeed; + float mRainFrequency; + + float mCelestialBodyTransparency; + }; + struct MoonState { enum Phase @@ -82,7 +128,7 @@ namespace MWRender void setMoonColour (bool red); ///< change Secunda colour to red - void setWeather(const MWWorld::WeatherResult& weather); + void setWeather(const WeatherResult& weather); void sunEnable(); @@ -133,9 +179,9 @@ namespace MWRender osg::ref_ptr mAtmosphereUpdater; - std::auto_ptr mSun; - std::auto_ptr mMasser; - std::auto_ptr mSecunda; + osg::ref_ptr mSun; + osg::ref_ptr mMasser; + osg::ref_ptr mSecunda; osg::ref_ptr mRainNode; osg::ref_ptr mRainParticleSystem; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 0e78edce7..679565e45 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -61,7 +61,7 @@ MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gam { rotationFromHorizon, mAxisOffset, // Reverse engineered from Morrowind's scene graph rotation matrices. - static_cast(phase(daysPassed)), + static_cast(phase(daysPassed, gameHour)), shadowBlend(rotationFromHorizon), earlyMoonShadowAlpha(rotationFromHorizon) * hourlyAlpha(gameHour) }; @@ -130,12 +130,17 @@ inline float MoonModel::rotation(float hours) const return 15.0f * mSpeed * hours; } -inline unsigned int MoonModel::phase(unsigned int daysPassed) const +inline unsigned int MoonModel::phase(unsigned int daysPassed, float gameHour) const { // Morrowind starts with a full moon on 16 Last Seed and then begins to wane 17 Last Seed, working on 3 day phase cycle. // Note: this is an internal helper, and as such we don't want to return MWRender::MoonState::Phase since we can't // forward declare it (C++11 strongly typed enums solve this). - return ((daysPassed + 1) / 3) % 8; + + // If the moon didn't rise yet today, use yesterday's moon phase. + if(gameHour < moonRiseHour(daysPassed)) + return (daysPassed / 3) % 8; + else + return ((daysPassed + 1) / 3) % 8; } inline float MoonModel::shadowBlend(float angle) const @@ -289,44 +294,54 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::F //Weather Weather clear; + clear.mObstructsCelestialBodies = false; setFallbackWeather(clear,"clear"); Weather cloudy; + cloudy.mObstructsCelestialBodies = false; setFallbackWeather(cloudy,"cloudy"); Weather foggy; + foggy.mObstructsCelestialBodies = false; setFallbackWeather(foggy,"foggy"); Weather thunderstorm; thunderstorm.mAmbientLoopSoundID = "rain heavy"; thunderstorm.mRainEffect = "meshes\\raindrop.nif"; + thunderstorm.mObstructsCelestialBodies = true; setFallbackWeather(thunderstorm,"thunderstorm"); Weather rain; rain.mAmbientLoopSoundID = "rain"; rain.mRainEffect = "meshes\\raindrop.nif"; + rain.mObstructsCelestialBodies = true; setFallbackWeather(rain,"rain"); Weather overcast; + overcast.mObstructsCelestialBodies = true; setFallbackWeather(overcast,"overcast"); Weather ashstorm; ashstorm.mAmbientLoopSoundID = "ashstorm"; ashstorm.mParticleEffect = "meshes\\ashcloud.nif"; + ashstorm.mObstructsCelestialBodies = true; setFallbackWeather(ashstorm,"ashstorm"); Weather blight; blight.mAmbientLoopSoundID = "blight"; blight.mParticleEffect = "meshes\\blightcloud.nif"; + blight.mObstructsCelestialBodies = true; setFallbackWeather(blight,"blight"); Weather snow; snow.mParticleEffect = "meshes\\snow.nif"; + snow.mObstructsCelestialBodies = true; setFallbackWeather(snow, "snow"); Weather blizzard; blizzard.mAmbientLoopSoundID = "BM Blizzard"; blizzard.mParticleEffect = "meshes\\blizzard.nif"; + blizzard.mObstructsCelestialBodies = true; setFallbackWeather(blizzard,"blizzard"); } @@ -460,14 +475,16 @@ void WeatherManager::setResult(const std::string& weatherType) mResult.mNightFade = factor; } } + + mResult.mCelestialBodyTransparency = current.mObstructsCelestialBodies ? 0.0f : 1.0f; } void WeatherManager::transition(float factor) { setResult(mCurrentWeather); - const WeatherResult current = mResult; + const MWRender::WeatherResult current = mResult; setResult(mNextWeather); - const WeatherResult other = mResult; + const MWRender::WeatherResult other = mResult; mResult.mCloudTexture = current.mCloudTexture; mResult.mNextCloudTexture = other.mCloudTexture; @@ -513,6 +530,16 @@ void WeatherManager::transition(float factor) mResult.mEffectFade = mResult.mAmbientSoundVolume; mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; } + + const Weather& currentSettings = mWeatherSettings[mCurrentWeather]; + const Weather& nextSettings = mWeatherSettings[mNextWeather]; + + if(currentSettings.mObstructsCelestialBodies && !nextSettings.mObstructsCelestialBodies) + mResult.mCelestialBodyTransparency = factor; + else if(!currentSettings.mObstructsCelestialBodies && nextSettings.mObstructsCelestialBodies) + mResult.mCelestialBodyTransparency = 1 - factor; + else + mResult.mCelestialBodyTransparency = current.mCelestialBodyTransparency; } void WeatherManager::update(float duration, bool paused) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 8f7634fbb..1bc3bc357 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -9,6 +9,8 @@ #include "../mwbase/soundmanager.hpp" +#include "../mwrender/sky.hpp" + namespace ESM { struct Region; @@ -19,7 +21,6 @@ namespace ESM namespace MWRender { class RenderingManager; - struct MoonState; } namespace Loading @@ -31,50 +32,6 @@ namespace MWWorld { class Fallback; - /// Defines the actual weather that results from weather setting (see below), time of day and weather transition - struct WeatherResult - { - std::string mCloudTexture; - std::string mNextCloudTexture; - float mCloudBlendFactor; - - osg::Vec4f mFogColor; - - osg::Vec4f mAmbientColor; - - osg::Vec4f mSkyColor; - - osg::Vec4f mSunColor; - - osg::Vec4f mSunDiscColor; - - float mFogDepth; - - float mWindSpeed; - - float mCloudSpeed; - - float mCloudOpacity; - - float mGlareView; - - bool mNight; // use night skybox - float mNightFade; // fading factor for night skybox - - bool mIsStorm; - - std::string mAmbientLoopSoundID; - float mAmbientSoundVolume; - - std::string mParticleEffect; - std::string mRainEffect; - float mEffectFade; - - float mRainSpeed; - float mRainFrequency; - }; - - /// Defines a single weather setting (according to INI) struct Weather { @@ -149,6 +106,9 @@ namespace MWWorld // Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature // is broken in the vanilla game and was disabled. + + // Some weather patterns will obstruct the moons, sun, and stars. + bool mObstructsCelestialBodies; }; class MoonModel @@ -173,7 +133,7 @@ namespace MWWorld float angle(unsigned int daysPassed, float gameHour) const; float moonRiseHour(unsigned int daysPassed) const; float rotation(float hours) const; - unsigned int phase(unsigned int daysPassed) const; + unsigned int phase(unsigned int daysPassed, float gameHour) const; float shadowBlend(float angle) const; float hourlyAlpha(float gameHour) const; float earlyMoonShadowAlpha(float angle) const; @@ -268,7 +228,7 @@ namespace MWWorld void setWeather(const std::string& weatherType, bool instant=false); std::string nextWeather(const ESM::Region* region) const; - WeatherResult mResult; + MWRender::WeatherResult mResult; typedef std::map > RegionModMap; RegionModMap mRegionMods; From 46ce04a65b00e4efe2f344e104373063a49f7742 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 5 Aug 2015 17:10:35 +0200 Subject: [PATCH 209/419] Don't package duplicate version for Windows The real version file is in the resources folder, and that's where it's read from. So the extra file is unused, and redundant. --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 99fb56fbe..84fd16e33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -449,7 +449,6 @@ if(WIN32) FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll") INSTALL(FILES ${dll_files} DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") - INSTALL(FILES "${OpenMW_BINARY_DIR}/resources/version" DESTINATION ".") INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt") INSTALL(FILES From cbf9f83b855e382375c17c2fc64eec582e31714a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 5 Aug 2015 17:20:01 +0200 Subject: [PATCH 210/419] allow use of IDs as function arguments, even if the ID matches a keyword (Fixes #2830) --- components/compiler/exprparser.cpp | 5 ++++- components/compiler/lineparser.cpp | 17 +++++++++++++++++ components/compiler/stringparser.cpp | 24 +++++++++++++++++++++++- components/compiler/stringparser.hpp | 4 ++++ 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index dc36b58d8..1818d04df 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -353,7 +353,10 @@ namespace Compiler if (extensions->isInstruction (keyword, argumentType, hasExplicit)) { // pretend this is not a keyword - return parseName (loc.mLiteral, loc, scanner); + std::string name = loc.mLiteral; + if (name.size()>=2 && name[0]=='"' && name[name.size()-1]=='"') + name = name.substr (1, name.size()-2); + return parseName (name, loc, scanner); } } diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index a71672916..4d6e147fc 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -222,6 +222,23 @@ namespace Compiler bool LineParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { + if (mState==MessageState || mState==MessageCommaState) + { + if (const Extensions *extensions = getContext().getExtensions()) + { + std::string argumentType; // ignored + bool hasExplicit = false; // ignored + if (extensions->isInstruction (keyword, argumentType, hasExplicit)) + { + // pretend this is not a keyword + std::string name = loc.mLiteral; + if (name.size()>=2 && name[0]=='"' && name[name.size()-1]=='"') + name = name.substr (1, name.size()-2); + return parseName (name, loc, scanner); + } + } + } + if (mState==SetMemberVarState) { mMemberName = loc.mLiteral; diff --git a/components/compiler/stringparser.cpp b/components/compiler/stringparser.cpp index a86c15794..7a2098fb3 100644 --- a/components/compiler/stringparser.cpp +++ b/components/compiler/stringparser.cpp @@ -4,9 +4,12 @@ #include #include +#include + #include "scanner.hpp" #include "generator.hpp" -#include +#include "context.hpp" +#include "extensions.hpp" namespace Compiler { @@ -33,6 +36,25 @@ namespace Compiler return Parser::parseName (name, loc, scanner); } + bool StringParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) + { + if (const Extensions *extensions = getContext().getExtensions()) + { + std::string argumentType; // ignored + bool hasExplicit = false; // ignored + if (extensions->isInstruction (keyword, argumentType, hasExplicit)) + { + // pretend this is not a keyword + std::string name = loc.mLiteral; + if (name.size()>=2 && name[0]=='"' && name[name.size()-1]=='"') + name = name.substr (1, name.size()-2); + return parseName (name, loc, scanner); + } + } + + return Parser::parseKeyword (keyword, loc, scanner); + } + bool StringParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner) { if (code==Scanner::S_comma && mState==StartState) diff --git a/components/compiler/stringparser.hpp b/components/compiler/stringparser.hpp index 3859a2496..52469128f 100644 --- a/components/compiler/stringparser.hpp +++ b/components/compiler/stringparser.hpp @@ -32,6 +32,10 @@ namespace Compiler ///< Handle a name token. /// \return fetch another token? + virtual bool parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner); + ///< Handle a keyword token. + /// \return fetch another token? + virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner); ///< Handle a special character token. /// \return fetch another token? From 5602cd9b7b6f954d953ed90ed1131aac8a3df32b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 6 Aug 2015 02:54:47 +0200 Subject: [PATCH 211/419] Fix the launcher's version label for builds with no git commit info --- apps/launcher/maindialog.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index c18c26cdd..9a6f91a0f 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -175,20 +175,16 @@ void Launcher::MainDialog::setVersionLabel() QString tag(QString::fromUtf8(v.mTagHash.c_str())); versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); - if (!revision.isEmpty() && !tag.isEmpty()) - { - if (revision == tag) { - versionLabel->setText(tr("OpenMW %1 release").arg(QString::fromUtf8(v.mVersion.c_str()))); - } else { - versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10))); - } + if (!v.mVersion.empty() && (revision.isEmpty() || revision == tag)) + versionLabel->setText(tr("OpenMW %1 release").arg(QString::fromUtf8(v.mVersion.c_str()))); + else + versionLabel->setText(tr("OpenMW development (%1)").arg(revision.left(10))); - // Add the compile date and time - versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(), - QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate), - QLocale(QLocale::C).toTime(QString(__TIME__).simplified(), - QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate))); - } + // Add the compile date and time + versionLabel->setToolTip(tr("Compiled on %1 %2").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(), + QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate), + QLocale(QLocale::C).toTime(QString(__TIME__).simplified(), + QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate))); } bool Launcher::MainDialog::setup() From f2e51b0579fb44ea391ed439ca4c9010cd098953 Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 5 Aug 2015 21:03:21 -0500 Subject: [PATCH 212/419] Use diffuse alpha to fade Sun --- apps/openmw/mwrender/sky.cpp | 39 +++++++++++++----------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 3a2da230f..38b6b9193 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -321,12 +321,12 @@ private: int mMeshType; }; -// A base class for the sun and moons. Must be stored in an osg::ref_ptr due to being -// derived from osg::Referenced. +/// A base class for the sun and moons. +/// \note Must be stored in an osg::ref_ptr due to being derived from osg::Referenced. class CelestialBody : public SceneUtil::StateSetUpdater { public: - CelestialBody(osg::Group* parentNode, float scaleFactor = 1.f, int numUvSets=1) + CelestialBody(osg::Group* parentNode, float scaleFactor, int numUvSets) { mGeode = new osg::Geode; osg::ref_ptr geom = createTexturedQuad(numUvSets); @@ -365,35 +365,26 @@ class Sun : public CelestialBody public: Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) : CelestialBody(parentNode, 1.0f, 1) - , mColor(1.0f, 1.0f, 1.0f, 1.0f) - , mDummyTexture(textureManager.getWarningTexture()) + , mTextureManager(textureManager) + , mColor(0.0f, 0.0f, 0.0f, 1.0f) { - osg::ref_ptr tex = textureManager.getTexture2D("textures/tx_sun_05.dds", - osg::Texture::CLAMP, - osg::Texture::CLAMP); - - mTransform->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); - mTransform->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); } virtual void setDefaults(osg::StateSet* stateset) { - osg::ref_ptr texEnv(new osg::TexEnvCombine); - texEnv->setCombine_Alpha(osg::TexEnvCombine::MODULATE); - texEnv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); - texEnv->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); - texEnv->setCombine_RGB(osg::TexEnvCombine::REPLACE); - texEnv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); - texEnv->setConstantColor(osg::Vec4f(1.0f, 1.0f, 1.0f, 1.0f)); + osg::ref_ptr tex = mTextureManager.getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, + osg::Texture::CLAMP); - stateset->setTextureAttributeAndModes(1, mDummyTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - stateset->setTextureAttributeAndModes(1, texEnv, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); + stateset->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), + osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); } virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) { - osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); - texEnv->setConstantColor(mColor); + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, mColor); } virtual void adjustTransparency(const float ratio) @@ -412,9 +403,8 @@ public: } private: - + Resource::TextureManager& mTextureManager; osg::Vec4f mColor; - osg::ref_ptr mDummyTexture; }; class Moon : public CelestialBody @@ -522,7 +512,6 @@ public: } private: - Resource::TextureManager& mTextureManager; Type mType; MoonState::Phase mPhase; From 238ae419a363ef263ffbba13307671a5d30e73f9 Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 5 Aug 2015 22:02:54 -0500 Subject: [PATCH 213/419] Fix use of incorrect material for Sun --- apps/openmw/mwrender/sky.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 38b6b9193..f16f97bc2 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -377,7 +377,7 @@ public: osg::Texture::CLAMP); stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); - stateset->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), + stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); } From 469a896ca16cf59a29ea6cb33b9e9b7d42241871 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 6 Aug 2015 08:45:38 +0200 Subject: [PATCH 214/419] make non-editable fields in dialogue sub view selectable (Fixes #2818) --- apps/opencs/view/world/dialoguesubview.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 5ad2f76e2..b2f2355ef 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -104,7 +104,9 @@ QWidget* CSVWorld::NotEditableSubDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { - return new QLabel(parent); + QLabel *label = new QLabel(parent); + label->setTextInteractionFlags (Qt::TextSelectableByMouse); + return label; } /* @@ -809,7 +811,7 @@ void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index) void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0)); - + if (!currentIndex.isValid()) { return; From b83f9445a96fda4dc14e43a2db363a748344227f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 6 Aug 2015 12:52:10 +0200 Subject: [PATCH 215/419] added UI for merge tool (merge tool itself is still missing) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/editor.cpp | 16 +++ apps/opencs/editor.hpp | 12 +++ apps/opencs/model/doc/documentmanager.cpp | 2 + apps/opencs/model/doc/documentmanager.hpp | 2 + apps/opencs/view/doc/filewidget.cpp | 8 ++ apps/opencs/view/doc/filewidget.hpp | 4 + apps/opencs/view/doc/view.cpp | 11 ++ apps/opencs/view/doc/view.hpp | 5 + apps/opencs/view/doc/viewmanager.cpp | 1 + apps/opencs/view/doc/viewmanager.hpp | 2 + apps/opencs/view/tools/merge.cpp | 123 ++++++++++++++++++++++ apps/opencs/view/tools/merge.hpp | 60 +++++++++++ 13 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/view/tools/merge.cpp create mode 100644 apps/opencs/view/tools/merge.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1a51d2d8d..91c778c06 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -94,7 +94,7 @@ opencs_hdrs_noqt (view/render opencs_units (view/tools - reportsubview reporttable searchsubview searchbox + reportsubview reporttable searchsubview searchbox merge ) opencs_units_noqt (view/tools diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 9450aa4bf..170e88320 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -40,9 +40,12 @@ CS::Editor::Editor () mNewGame.setLocalData (mLocal); mFileDialog.setLocalData (mLocal); + mMerge.setLocalData (mLocal); connect (&mDocumentManager, SIGNAL (documentAdded (CSMDoc::Document *)), this, SLOT (documentAdded (CSMDoc::Document *))); + connect (&mDocumentManager, SIGNAL (documentAboutToBeRemoved (CSMDoc::Document *)), + this, SLOT (documentAboutToBeRemoved (CSMDoc::Document *))); connect (&mDocumentManager, SIGNAL (lastDocumentDeleted()), this, SLOT (lastDocumentDeleted())); @@ -50,6 +53,7 @@ CS::Editor::Editor () connect (&mViewManager, SIGNAL (newAddonRequest ()), this, SLOT (createAddon ())); connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ())); connect (&mViewManager, SIGNAL (editSettingsRequest()), this, SLOT (showSettings ())); + connect (&mViewManager, SIGNAL (mergeDocument (CSMDoc::Document *)), this, SLOT (mergeDocument (CSMDoc::Document *))); connect (&mStartup, SIGNAL (createGame()), this, SLOT (createGame ())); connect (&mStartup, SIGNAL (createAddon()), this, SLOT (createAddon ())); @@ -360,7 +364,19 @@ void CS::Editor::documentAdded (CSMDoc::Document *document) mViewManager.addView (document); } +void CS::Editor::documentAboutToBeRemoved (CSMDoc::Document *document) +{ + if (mMerge.getDocument()==document) + mMerge.cancel(); +} + void CS::Editor::lastDocumentDeleted() { QApplication::quit(); } + +void CS::Editor::mergeDocument (CSMDoc::Document *document) +{ + mMerge.configure (document); + mMerge.show(); +} diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 0464fb7eb..ac403b1ee 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -27,11 +27,18 @@ #include "view/settings/dialog.hpp" +#include "view/tools/merge.hpp" + namespace VFS { class Manager; } +namespace CSMDoc +{ + class Document; +} + namespace CS { class Editor : public QObject @@ -55,6 +62,7 @@ namespace CS boost::interprocess::file_lock mLock; boost::filesystem::ofstream mPidFile; bool mFsStrict; + CSVTools::Merge mMerge; void setupDataFiles (const Files::PathContainer& dataDirs); @@ -94,8 +102,12 @@ namespace CS void documentAdded (CSMDoc::Document *document); + void documentAboutToBeRemoved (CSMDoc::Document *document); + void lastDocumentDeleted(); + void mergeDocument (CSMDoc::Document *document); + private: QString mIpcServerName; diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 5a5f50159..02d4ab5c0 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -73,6 +73,8 @@ void CSMDoc::DocumentManager::removeDocument (CSMDoc::Document *document) if (iter==mDocuments.end()) throw std::runtime_error ("removing invalid document"); + emit documentAboutToBeRemoved (document); + mDocuments.erase (iter); document->deleteLater(); diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index b61656d4b..f9b18bfe6 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -88,6 +88,8 @@ namespace CSMDoc void documentAdded (CSMDoc::Document *document); + void documentAboutToBeRemoved (CSMDoc::Document *document); + void loadRequest (CSMDoc::Document *document); void lastDocumentDeleted(); diff --git a/apps/opencs/view/doc/filewidget.cpp b/apps/opencs/view/doc/filewidget.cpp index f18fe695a..3e5c08788 100644 --- a/apps/opencs/view/doc/filewidget.cpp +++ b/apps/opencs/view/doc/filewidget.cpp @@ -56,3 +56,11 @@ void CSVDoc::FileWidget::extensionLabelIsVisible(bool visible) { mType->setVisible(visible); } + +void CSVDoc::FileWidget::setName (const std::string& text) +{ + QString text2 = QString::fromUtf8 (text.c_str()); + + mInput->setText (text2); + textChanged (text2); +} diff --git a/apps/opencs/view/doc/filewidget.hpp b/apps/opencs/view/doc/filewidget.hpp index ff09d71a3..ab06f37f1 100644 --- a/apps/opencs/view/doc/filewidget.hpp +++ b/apps/opencs/view/doc/filewidget.hpp @@ -3,6 +3,8 @@ #include +#include + class QLabel; class QString; class QLineEdit; @@ -29,6 +31,8 @@ namespace CSVDoc void extensionLabelIsVisible(bool visible); + void setName (const std::string& text); + private slots: void textChanged (const QString& text); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 05c98b11f..df7421a14 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -66,6 +66,10 @@ void CSVDoc::View::setupFileMenu() connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); file->addAction (mVerify); + mMerge = new QAction (tr ("Merge"), this); + connect (mMerge, SIGNAL (triggered()), this, SLOT (merge())); + file->addAction (mMerge); + QAction *loadErrors = new QAction (tr ("Load Error Log"), this); connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog())); file->addAction (loadErrors); @@ -393,6 +397,8 @@ void CSVDoc::View::updateActions() mGlobalDebugProfileMenu->updateActions (running); mStopDebug->setEnabled (running); + + mMerge->setEnabled (mDocument->getContentFiles().size()>1); } CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) @@ -969,3 +975,8 @@ void CSVDoc::View::updateScrollbar() else mSubViewWindow.setMinimumWidth(0); } + +void CSVDoc::View::merge() +{ + emit mergeDocument (mDocument); +} diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 7f4255f8f..adda73526 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -43,6 +43,7 @@ namespace CSVDoc QAction *mVerify; QAction *mShowStatusBar; QAction *mStopDebug; + QAction *mMerge; std::vector mEditingActions; Operations *mOperations; SubViewFactoryManager mSubViewFactory; @@ -129,6 +130,8 @@ namespace CSVDoc void editSettingsRequest(); + void mergeDocument (CSMDoc::Document *document); + public slots: void addSubView (const CSMWorld::UniversalId& id, const std::string& hint = ""); @@ -237,6 +240,8 @@ namespace CSVDoc void closeRequest (SubView *subView); void moveScrollBarToEnd(int min, int max); + + void merge(); }; } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 7aec001cf..265c1f832 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -175,6 +175,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) connect (view, SIGNAL (newAddonRequest ()), this, SIGNAL (newAddonRequest())); connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest())); connect (view, SIGNAL (editSettingsRequest()), this, SIGNAL (editSettingsRequest())); + connect (view, SIGNAL (mergeDocument (CSMDoc::Document *)), this, SIGNAL (mergeDocument (CSMDoc::Document *))); connect (&CSMSettings::UserSettings::instance(), SIGNAL (userSettingUpdated(const QString &, const QStringList &)), diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index cdd5ac768..70431107f 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -77,6 +77,8 @@ namespace CSVDoc void editSettingsRequest(); + void mergeDocument (CSMDoc::Document *document); + public slots: void exitApplication (CSVDoc::View *view); diff --git a/apps/opencs/view/tools/merge.cpp b/apps/opencs/view/tools/merge.cpp new file mode 100644 index 000000000..baadd9179 --- /dev/null +++ b/apps/opencs/view/tools/merge.cpp @@ -0,0 +1,123 @@ + +#include "merge.hpp" + +#include +#include +#include +#include +#include +#include + +#include "../../model/doc/document.hpp" + +#include "../doc/filewidget.hpp" +#include "../doc/adjusterwidget.hpp" + +CSVTools::Merge::Merge (QWidget *parent) +: QDialog (parent), mDocument (0) +{ + setWindowTitle ("Merge Content Files into a new Game File"); + + QVBoxLayout *mainLayout = new QVBoxLayout; + setLayout (mainLayout); + + QSplitter *splitter = new QSplitter (Qt::Horizontal, this); + + mainLayout->addWidget (splitter, 1); + + // left panel (files to be merged) + QWidget *left = new QWidget (this); + left->setContentsMargins (0, 0, 0, 0); + splitter->addWidget (left); + + QVBoxLayout *leftLayout = new QVBoxLayout; + left->setLayout (leftLayout); + + leftLayout->addWidget (new QLabel ("Files to be merged", this)); + + mFiles = new QListWidget (this); + leftLayout->addWidget (mFiles, 1); + + // right panel (new game file) + QWidget *right = new QWidget (this); + right->setContentsMargins (0, 0, 0, 0); + splitter->addWidget (right); + + QVBoxLayout *rightLayout = new QVBoxLayout; + rightLayout->setAlignment (Qt::AlignTop); + right->setLayout (rightLayout); + + rightLayout->addWidget (new QLabel ("New game file", this)); + + mNewFile = new CSVDoc::FileWidget (this); + mNewFile->setType (false); + mNewFile->extensionLabelIsVisible (true); + rightLayout->addWidget (mNewFile); + + mAdjuster = new CSVDoc::AdjusterWidget (this); + + rightLayout->addWidget (mAdjuster); + + connect (mNewFile, SIGNAL (nameChanged (const QString&, bool)), + mAdjuster, SLOT (setName (const QString&, bool))); + connect (mAdjuster, SIGNAL (stateChanged (bool)), this, SLOT (stateChanged (bool))); + + // buttons + QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Cancel, Qt::Horizontal, this); + + connect (buttons->button (QDialogButtonBox::Cancel), SIGNAL (clicked()), this, SLOT (reject())); + mOkay = new QPushButton ("Merge", this); + mOkay->setDefault (true); + buttons->addButton (mOkay, QDialogButtonBox::AcceptRole); + + mainLayout->addWidget (buttons); +} + +void CSVTools::Merge::configure (CSMDoc::Document *document) +{ + mDocument = document; + + mNewFile->setName (""); + + // content files + while (mFiles->count()) + delete mFiles->takeItem (0); + + std::vector files = document->getContentFiles(); + + for (std::vector::const_iterator iter (files.begin()); + iter!=files.end(); ++iter) + mFiles->addItem (QString::fromUtf8 (iter->filename().string().c_str())); +} + +void CSVTools::Merge::setLocalData (const boost::filesystem::path& localData) +{ + mAdjuster->setLocalData (localData); +} + +CSMDoc::Document *CSVTools::Merge::getDocument() const +{ + return mDocument; +} + +void CSVTools::Merge::cancel() +{ + mDocument = 0; + hide(); +} + +void CSVTools::Merge::accept() +{ + QDialog::accept(); +} + +void CSVTools::Merge::reject() +{ + QDialog::reject(); + cancel(); +} + +void CSVTools::Merge::stateChanged (bool valid) +{ + mOkay->setEnabled (valid); +} diff --git a/apps/opencs/view/tools/merge.hpp b/apps/opencs/view/tools/merge.hpp new file mode 100644 index 000000000..4538baebe --- /dev/null +++ b/apps/opencs/view/tools/merge.hpp @@ -0,0 +1,60 @@ +#ifndef CSV_TOOLS_REPORTTABLE_H +#define CSV_TOOLS_REPORTTABLE_H + +#include + +#include + +class QPushButton; +class QListWidget; + +namespace CSMDoc +{ + class Document; +} + +namespace CSVDoc +{ + class FileWidget; + class AdjusterWidget; +} + +namespace CSVTools +{ + class Merge : public QDialog + { + Q_OBJECT + + CSMDoc::Document *mDocument; + QPushButton *mOkay; + QListWidget *mFiles; + CSVDoc::FileWidget *mNewFile; + CSVDoc::AdjusterWidget *mAdjuster; + + public: + + Merge (QWidget *parent = 0); + + /// Configure dialogue for a new merge + void configure (CSMDoc::Document *document); + + void setLocalData (const boost::filesystem::path& localData); + + CSMDoc::Document *getDocument() const; + + void cancel(); + + public slots: + + virtual void accept(); + + virtual void reject(); + + private slots: + + void stateChanged (bool valid); + + }; +} + +#endif From 4fd3097c1cf2329cef071aee7a1b149e280e4974 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 6 Aug 2015 12:58:52 +0200 Subject: [PATCH 216/419] improved adjuster widget problem reporting --- apps/opencs/view/doc/adjusterwidget.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 6571ad7c8..6dc95a338 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -64,6 +64,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) QString message; mValid = (!name.isEmpty()); + bool warning = false; if (!mValid) { @@ -106,13 +107,14 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) { /// \todo add an user setting to make this an error. message += "

    A file with the same name already exists. If you continue, it will be overwritten."; + warning = true; } } } mMessage->setText (message); mIcon->setPixmap (style()->standardIcon ( - mValid ? QStyle::SP_MessageBoxInformation : QStyle::SP_MessageBoxWarning). + mValid ? (warning ? QStyle::SP_MessageBoxWarning : QStyle::SP_MessageBoxInformation) : QStyle::SP_MessageBoxCritical). pixmap (QSize (16, 16))); emit stateChanged (mValid); From ff2dab8d5657331b824b017908ca490ad8aa8216 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 6 Aug 2015 14:17:42 +0300 Subject: [PATCH 217/419] Remove check for an empty Particle from Magic effects verifier --- apps/opencs/model/tools/magiceffectcheck.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/opencs/model/tools/magiceffectcheck.cpp b/apps/opencs/model/tools/magiceffectcheck.cpp index 22620929c..5435881b3 100644 --- a/apps/opencs/model/tools/magiceffectcheck.cpp +++ b/apps/opencs/model/tools/magiceffectcheck.cpp @@ -103,11 +103,7 @@ void CSMTools::MagicEffectCheckStage::perform(int stage, CSMDoc::Messages &messa messages.push_back(std::make_pair(id, "No such Icon '" + effect.mIcon + "'")); } - if (effect.mParticle.empty()) - { - messages.push_back(std::make_pair(id, "Particle is not specified")); - } - else if (!isTextureExists(effect.mParticle, false)) + if (!effect.mParticle.empty() && !isTextureExists(effect.mParticle, false)) { messages.push_back(std::make_pair(id, "No such Particle '" + effect.mParticle + "'")); } From 3235cecddfe11a1bbe70b231b7e1fa8fb716b1db Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 7 Aug 2015 00:08:18 -0500 Subject: [PATCH 218/419] Use Glare View for visibility of celestial bodies Fixed memory leak from Sun and Moon objects by pulling Updaters back out into separate objects. Removed code related to mCelestialBodyTransparency. --- apps/openmw/mwrender/sky.cpp | 235 ++++++++++++++++++-------------- apps/openmw/mwrender/sky.hpp | 9 +- apps/openmw/mwworld/weather.cpp | 22 --- apps/openmw/mwworld/weather.hpp | 6 +- 4 files changed, 140 insertions(+), 132 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index f16f97bc2..788848cc4 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -322,8 +322,7 @@ private: }; /// A base class for the sun and moons. -/// \note Must be stored in an osg::ref_ptr due to being derived from osg::Referenced. -class CelestialBody : public SceneUtil::StateSetUpdater +class CelestialBody { public: CelestialBody(osg::Group* parentNode, float scaleFactor, int numUvSets) @@ -336,14 +335,9 @@ public: mTransform->addChild(mGeode); parentNode->addChild(mTransform); - - mGeode->addUpdateCallback(this); } - virtual ~CelestialBody() - { - mGeode->removeUpdateCallback(this); - } + virtual ~CelestialBody() {} virtual void adjustTransparency(const float ratio) = 0; @@ -365,31 +359,19 @@ class Sun : public CelestialBody public: Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) : CelestialBody(parentNode, 1.0f, 1) - , mTextureManager(textureManager) - , mColor(0.0f, 0.0f, 0.0f, 1.0f) + , mUpdater(new Updater(textureManager)) { + mGeode->addUpdateCallback(mUpdater); } - virtual void setDefaults(osg::StateSet* stateset) + ~Sun() { - osg::ref_ptr tex = mTextureManager.getTexture2D("textures/tx_sun_05.dds", - osg::Texture::CLAMP, - osg::Texture::CLAMP); - - stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); - stateset->setAttributeAndModes(createUnlitMaterial(), - osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); - } - - virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) - { - osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, mColor); + mGeode->removeUpdateCallback(mUpdater); } virtual void adjustTransparency(const float ratio) { - mColor.a() = ratio; + mUpdater->mColor.a() = ratio; } void setDirection(const osg::Vec3f& direction) @@ -403,8 +385,36 @@ public: } private: - Resource::TextureManager& mTextureManager; - osg::Vec4f mColor; + struct Updater : public SceneUtil::StateSetUpdater + { + Resource::TextureManager& mTextureManager; + osg::Vec4f mColor; + + Updater(Resource::TextureManager& textureManager) + : mTextureManager(textureManager) + , mColor(0.0f, 0.0f, 0.0f, 1.0f) + { + } + + virtual void setDefaults(osg::StateSet* stateset) + { + osg::ref_ptr tex = mTextureManager.getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, + osg::Texture::CLAMP); + + stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); + stateset->setAttributeAndModes(createUnlitMaterial(), + osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) + { + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, mColor); + } + }; + + osg::ref_ptr mUpdater; }; class Moon : public CelestialBody @@ -418,53 +428,24 @@ public: Moon(osg::Group* parentNode, Resource::TextureManager& textureManager, float scaleFactor, Type type) : CelestialBody(parentNode, scaleFactor, 2) - , mTextureManager(textureManager) , mType(type) , mPhase(MoonState::Phase_Unspecified) - , mTransparency(1.0f) - , mShadowBlend(1.0f) - , mMoonColor(1.0f, 1.0f, 1.0f, 1.0f) + , mUpdater(new Updater(textureManager)) { setPhase(MoonState::Phase_Full); setVisible(true); + + mGeode->addUpdateCallback(mUpdater); } - virtual void setDefaults(osg::StateSet *stateset) + ~Moon() { - stateset->setTextureAttributeAndModes(0, mPhaseTex, osg::StateAttribute::ON); - osg::ref_ptr texEnv = new osg::TexEnvCombine; - texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); - texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); - texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); - texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // mShadowBlend * mMoonColor - stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); - - stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); - osg::ref_ptr texEnv2 = new osg::TexEnvCombine; - texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD); - texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); - texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE); - texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); - texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); - texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); - texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // mAtmosphereColor.rgb, mTransparency - stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); - - stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - } - - virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) - { - osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); - texEnv->setConstantColor(mMoonColor * mShadowBlend); - - osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); - texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency)); + mGeode->removeUpdateCallback(mUpdater); } virtual void adjustTransparency(const float ratio) { - mTransparency *= ratio; + mUpdater->mTransparency *= ratio; } void setState(const MoonState& state) @@ -484,18 +465,18 @@ public: mTransform->setAttitude(attX * rotZ); setPhase(state.mPhase); - mTransparency = state.mMoonAlpha; - mShadowBlend = state.mShadowBlend; + mUpdater->mTransparency = state.mMoonAlpha; + mUpdater->mShadowBlend = state.mShadowBlend; } void setAtmosphereColor(const osg::Vec4f& color) { - mAtmosphereColor = color; + mUpdater->mAtmosphereColor = color; } void setColor(const osg::Vec4f& color) { - mMoonColor = color; + mUpdater->mMoonColor = color; } unsigned int getPhaseInt() const @@ -512,50 +493,102 @@ public: } private: - Resource::TextureManager& mTextureManager; + struct Updater : public SceneUtil::StateSetUpdater + { + Resource::TextureManager& mTextureManager; + osg::ref_ptr mPhaseTex; + osg::ref_ptr mCircleTex; + float mTransparency; + float mShadowBlend; + osg::Vec4f mAtmosphereColor; + osg::Vec4f mMoonColor; + + Updater(Resource::TextureManager& textureManager) + : mTextureManager(textureManager) + , mPhaseTex() + , mCircleTex() + , mTransparency(1.0f) + , mShadowBlend(1.0f) + , mAtmosphereColor(1.0f, 1.0f, 1.0f, 1.0f) + , mMoonColor(1.0f, 1.0f, 1.0f, 1.0f) + { + } + + virtual void setDefaults(osg::StateSet* stateset) + { + stateset->setTextureAttributeAndModes(0, mPhaseTex, osg::StateAttribute::ON); + osg::ref_ptr texEnv = new osg::TexEnvCombine; + texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); + texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); + texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); + texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // mShadowBlend * mMoonColor + stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); + + stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); + osg::ref_ptr texEnv2 = new osg::TexEnvCombine; + texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD); + texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); + texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE); + texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); + texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); + texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // mAtmosphereColor.rgb, mTransparency + stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); + + stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) + { + osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); + texEnv->setConstantColor(mMoonColor * mShadowBlend); + + osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); + texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency)); + } + + void setTextures(const std::string& phaseTex, const std::string& circleTex) + { + mPhaseTex = mTextureManager.getTexture2D(phaseTex, osg::Texture::CLAMP, osg::Texture::CLAMP); + mCircleTex = mTextureManager.getTexture2D(circleTex, osg::Texture::CLAMP, osg::Texture::CLAMP); + + reset(); + } + }; + Type mType; MoonState::Phase mPhase; - float mTransparency; - float mShadowBlend; - osg::Vec4f mAtmosphereColor; - osg::Vec4f mMoonColor; - osg::ref_ptr mPhaseTex; - osg::ref_ptr mCircleTex; - - void setTextures(const std::string& phaseTex, const std::string& circleTex) - { - mPhaseTex = mTextureManager.getTexture2D(phaseTex, osg::Texture::CLAMP, osg::Texture::CLAMP); - mCircleTex = mTextureManager.getTexture2D(circleTex, osg::Texture::CLAMP, osg::Texture::CLAMP); - - reset(); - } + osg::ref_ptr mUpdater; void setPhase(const MoonState::Phase& phase) { - if (mPhase == phase) + if(mPhase == phase) return; + mPhase = phase; std::string textureName = "textures/tx_"; - if (mType == Moon::Type_Secunda) textureName += "secunda_"; - else textureName += "masser_"; + if (mType == Moon::Type_Secunda) + textureName += "secunda_"; + else + textureName += "masser_"; - if (phase == MoonState::Phase_New) textureName += "new"; - else if (phase == MoonState::Phase_WaxingCrescent) textureName += "one_wax"; - else if (phase == MoonState::Phase_FirstQuarter) textureName += "half_wax"; - else if (phase == MoonState::Phase_WaxingGibbous) textureName += "three_wax"; - else if (phase == MoonState::Phase_WaningCrescent) textureName += "one_wan"; - else if (phase == MoonState::Phase_ThirdQuarter) textureName += "half_wan"; - else if (phase == MoonState::Phase_WaningGibbous) textureName += "three_wan"; - else if (phase == MoonState::Phase_Full) textureName += "full"; + if (phase == MoonState::Phase_New) textureName += "new"; + else if(phase == MoonState::Phase_WaxingCrescent) textureName += "one_wax"; + else if(phase == MoonState::Phase_FirstQuarter) textureName += "half_wax"; + else if(phase == MoonState::Phase_WaxingGibbous) textureName += "three_wax"; + else if(phase == MoonState::Phase_WaningCrescent) textureName += "one_wan"; + else if(phase == MoonState::Phase_ThirdQuarter) textureName += "half_wan"; + else if(phase == MoonState::Phase_WaningGibbous) textureName += "three_wan"; + else if(phase == MoonState::Phase_Full) textureName += "full"; textureName += ".dds"; if (mType == Moon::Type_Secunda) - setTextures(textureName, "textures/tx_mooncircle_full_s.dds"); + mUpdater->setTextures(textureName, "textures/tx_mooncircle_full_s.dds"); else - setTextures(textureName, "textures/tx_mooncircle_full_m.dds"); + mUpdater->setTextures(textureName, "textures/tx_mooncircle_full_m.dds"); } }; @@ -621,11 +654,11 @@ void SkyManager::create() mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getTextureManager()); atmosphereNight->addUpdateCallback(mAtmosphereNightUpdater); - mSun = new Sun(mRootNode, *mSceneManager->getTextureManager()); + mSun.reset(new Sun(mRootNode, *mSceneManager->getTextureManager())); const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mMasser = new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser); - mSecunda = new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda); + mMasser.reset(new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser)); + mSecunda.reset(new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda)); mCloudNode = new osg::PositionAttitudeTransform; mRootNode->addChild(mCloudNode); @@ -1067,11 +1100,11 @@ void SkyManager::setWeather(const WeatherResult& weather) mCloudSpeed = weather.mCloudSpeed; - mMasser->adjustTransparency(weather.mCelestialBodyTransparency); - mSecunda->adjustTransparency(weather.mCelestialBodyTransparency); - mSun->adjustTransparency(weather.mCelestialBodyTransparency); + mMasser->adjustTransparency(weather.mGlareView); + mSecunda->adjustTransparency(weather.mGlareView); + mSun->adjustTransparency(weather.mGlareView); - float nextStarsOpacity = weather.mNightFade * weather.mCelestialBodyTransparency; + float nextStarsOpacity = weather.mNightFade * weather.mGlareView; if(weather.mNight && mStarsOpacity != nextStarsOpacity) { mStarsOpacity = nextStarsOpacity; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 16509ef32..4b1acadc3 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -2,6 +2,7 @@ #define OPENMW_MWRENDER_SKY_H #include +#include #include #include @@ -75,8 +76,6 @@ namespace MWRender float mRainSpeed; float mRainFrequency; - - float mCelestialBodyTransparency; }; struct MoonState @@ -179,9 +178,9 @@ namespace MWRender osg::ref_ptr mAtmosphereUpdater; - osg::ref_ptr mSun; - osg::ref_ptr mMasser; - osg::ref_ptr mSecunda; + std::auto_ptr mSun; + std::auto_ptr mMasser; + std::auto_ptr mSecunda; osg::ref_ptr mRainNode; osg::ref_ptr mRainParticleSystem; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 679565e45..c571b1d1d 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -294,54 +294,44 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::F //Weather Weather clear; - clear.mObstructsCelestialBodies = false; setFallbackWeather(clear,"clear"); Weather cloudy; - cloudy.mObstructsCelestialBodies = false; setFallbackWeather(cloudy,"cloudy"); Weather foggy; - foggy.mObstructsCelestialBodies = false; setFallbackWeather(foggy,"foggy"); Weather thunderstorm; thunderstorm.mAmbientLoopSoundID = "rain heavy"; thunderstorm.mRainEffect = "meshes\\raindrop.nif"; - thunderstorm.mObstructsCelestialBodies = true; setFallbackWeather(thunderstorm,"thunderstorm"); Weather rain; rain.mAmbientLoopSoundID = "rain"; rain.mRainEffect = "meshes\\raindrop.nif"; - rain.mObstructsCelestialBodies = true; setFallbackWeather(rain,"rain"); Weather overcast; - overcast.mObstructsCelestialBodies = true; setFallbackWeather(overcast,"overcast"); Weather ashstorm; ashstorm.mAmbientLoopSoundID = "ashstorm"; ashstorm.mParticleEffect = "meshes\\ashcloud.nif"; - ashstorm.mObstructsCelestialBodies = true; setFallbackWeather(ashstorm,"ashstorm"); Weather blight; blight.mAmbientLoopSoundID = "blight"; blight.mParticleEffect = "meshes\\blightcloud.nif"; - blight.mObstructsCelestialBodies = true; setFallbackWeather(blight,"blight"); Weather snow; snow.mParticleEffect = "meshes\\snow.nif"; - snow.mObstructsCelestialBodies = true; setFallbackWeather(snow, "snow"); Weather blizzard; blizzard.mAmbientLoopSoundID = "BM Blizzard"; blizzard.mParticleEffect = "meshes\\blizzard.nif"; - blizzard.mObstructsCelestialBodies = true; setFallbackWeather(blizzard,"blizzard"); } @@ -475,8 +465,6 @@ void WeatherManager::setResult(const std::string& weatherType) mResult.mNightFade = factor; } } - - mResult.mCelestialBodyTransparency = current.mObstructsCelestialBodies ? 0.0f : 1.0f; } void WeatherManager::transition(float factor) @@ -530,16 +518,6 @@ void WeatherManager::transition(float factor) mResult.mEffectFade = mResult.mAmbientSoundVolume; mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; } - - const Weather& currentSettings = mWeatherSettings[mCurrentWeather]; - const Weather& nextSettings = mWeatherSettings[mNextWeather]; - - if(currentSettings.mObstructsCelestialBodies && !nextSettings.mObstructsCelestialBodies) - mResult.mCelestialBodyTransparency = factor; - else if(!currentSettings.mObstructsCelestialBodies && nextSettings.mObstructsCelestialBodies) - mResult.mCelestialBodyTransparency = 1 - factor; - else - mResult.mCelestialBodyTransparency = current.mCelestialBodyTransparency; } void WeatherManager::update(float duration, bool paused) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 1bc3bc357..d5ac6d801 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -80,7 +80,8 @@ namespace MWWorld // Multiplier for clouds transparency float mCloudsMaximumPercent; - // Value between 0 and 1, defines the strength of the sun glare effect + // Value between 0 and 1, defines the strength of the sun glare effect. + // Also appears to modify how visible the sun, moons, and stars are for various weather effects. float mGlareView; // Sound effect @@ -106,9 +107,6 @@ namespace MWWorld // Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature // is broken in the vanilla game and was disabled. - - // Some weather patterns will obstruct the moons, sun, and stars. - bool mObstructsCelestialBodies; }; class MoonModel From 56b7196beaeb3c1ec8712605fa9d2ca9266f467a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 7 Aug 2015 15:34:01 +0200 Subject: [PATCH 219/419] Remove incorrect implementation of "Clouds Maximum Percent" weather setting --- apps/openmw/mwrender/sky.cpp | 12 ++++++------ apps/openmw/mwrender/sky.hpp | 3 --- apps/openmw/mwworld/weather.cpp | 3 --- apps/openmw/mwworld/weather.hpp | 2 +- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 788848cc4..138365ae4 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -605,7 +605,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mClouds() , mNextClouds() , mCloudBlendFactor(0.0f) - , mCloudOpacity(0.0f) , mCloudSpeed(0.0f) , mStarsOpacity(0.0f) , mRemainingTransitionTime(0.0f) @@ -666,12 +665,15 @@ void SkyManager::create() ModVertexAlphaVisitor modClouds(1); mCloudMesh->accept(modClouds); mCloudUpdater = new CloudUpdater; + mCloudUpdater->setOpacity(1.f); mCloudMesh->addUpdateCallback(mCloudUpdater); mCloudMesh2 = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode); mCloudMesh2->accept(modClouds); mCloudUpdater2 = new CloudUpdater; + mCloudUpdater2->setOpacity(0.f); mCloudMesh2->addUpdateCallback(mCloudUpdater2); + mCloudMesh2->setNodeMask(0); osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(false); @@ -1060,14 +1062,12 @@ void SkyManager::setWeather(const WeatherResult& weather) osg::Texture::REPEAT, osg::Texture::REPEAT)); } - if (mCloudBlendFactor != weather.mCloudBlendFactor - || mCloudOpacity != weather.mCloudOpacity) + if (mCloudBlendFactor != weather.mCloudBlendFactor) { mCloudBlendFactor = weather.mCloudBlendFactor; - mCloudOpacity = weather.mCloudOpacity; - mCloudUpdater->setOpacity(mCloudOpacity * (1.f-mCloudBlendFactor)); - mCloudUpdater2->setOpacity(mCloudOpacity * mCloudBlendFactor); + mCloudUpdater->setOpacity((1.f-mCloudBlendFactor)); + mCloudUpdater2->setOpacity(mCloudBlendFactor); mCloudMesh2->setNodeMask(mCloudBlendFactor > 0.f ? ~0 : 0); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 4b1acadc3..3855136a9 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -58,8 +58,6 @@ namespace MWRender float mCloudSpeed; - float mCloudOpacity; - float mGlareView; bool mNight; // use night skybox @@ -204,7 +202,6 @@ namespace MWRender std::string mClouds; std::string mNextClouds; float mCloudBlendFactor; - float mCloudOpacity; float mCloudSpeed; float mStarsOpacity; osg::Vec4f mCloudColour; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index c571b1d1d..8d78b969e 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -374,7 +374,6 @@ void WeatherManager::setResult(const std::string& weatherType) mResult.mCloudTexture = current.mCloudTexture; mResult.mCloudBlendFactor = 0; - mResult.mCloudOpacity = current.mCloudsMaximumPercent; mResult.mWindSpeed = current.mWindSpeed; mResult.mCloudSpeed = current.mCloudSpeed; mResult.mGlareView = current.mGlareView; @@ -478,7 +477,6 @@ void WeatherManager::transition(float factor) mResult.mNextCloudTexture = other.mCloudTexture; mResult.mCloudBlendFactor = factor; - mResult.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); mResult.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); mResult.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); mResult.mSkyColor = lerp(current.mSkyColor, other.mSkyColor, factor); @@ -488,7 +486,6 @@ void WeatherManager::transition(float factor) mResult.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor); mResult.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor); mResult.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor); - mResult.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); mResult.mGlareView = lerp(current.mGlareView, other.mGlareView, factor); mResult.mNightFade = lerp(current.mNightFade, other.mNightFade, factor); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index d5ac6d801..7f4858bc8 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -77,7 +77,7 @@ namespace MWWorld // Cloud animation speed multiplier float mCloudSpeed; - // Multiplier for clouds transparency + // TODO: What is this supposed to do? float mCloudsMaximumPercent; // Value between 0 and 1, defines the strength of the sun glare effect. From 865491d1012c5bc2291fb7463f483c2cd045c244 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:06:33 -0400 Subject: [PATCH 220/419] Added a help message to niftest Now using the boost argument parser. --- apps/niftest/niftest.cpp | 66 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index 20c8597f3..fd060447c 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -2,12 +2,17 @@ #include #include +#include #include #include #include #include +#include + +// Create local aliases for brevity +namespace bpo = boost::program_options; ///See if the file has the named extension bool hasExtension(std::string filename, std::string extensionToFind) @@ -54,13 +59,68 @@ void readBSA(std::string filename) } } +std::vector parseOptions (int argc, char** argv) +{ + bpo::options_description desc("Ensure that OpenMW can use the provided NIF and BSA files\n\n" + "Usages:\n" + " niftool \n" + " Scan the file for read errors.\n\n" + "Allowed options"); + desc.add_options() + ("help,h", "print help message.") + ("input-file", bpo::value< std::vector >(), "input file") + ; + + //Default option if none provided + bpo::positional_options_description p; + p.add("input-file", -1); + + bpo::variables_map variables; + try + { + bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv). + options(desc).positional(p).run(); + bpo::store(valid_opts, variables); + } + catch(std::exception &e) + { + std::cout << "ERROR parsing arguments: " << e.what() << "\n\n" + << desc << std::endl; + exit(1); + } + + bpo::notify(variables); + if (variables.count ("help")) + { + std::cout << desc << std::endl; + exit(1); + } + if (variables.count("input-file")) + { + std::vector files = variables["input-file"].as< std::vector >(); + + std::cout << "Input files are:"; + for(std::vector::const_iterator it=files.begin(); it!=files.end(); ++it) + { + std::cout <<" "<< *it; + } + std::cout << std::endl; + return files; + } + + std::cout << "No input files or directories specified!" << std::endl; + std::cout << desc << std::endl; + exit(1); +} + int main(int argc, char **argv) { + std::vector files = parseOptions (argc, argv); std::cout << "Reading Files" << std::endl; - for(int i = 1; i::const_iterator it=files.begin(); it!=files.end(); ++it) + { + std::string name = *it; try{ if(isNIF(name)) From efadce3e906ccb0f23cca3554ea8e21efe9ce20c Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:20:31 -0400 Subject: [PATCH 221/419] Have niftest handle directories as well Note: BSA files within the directory must be passed manually. --- apps/niftest/niftest.cpp | 48 +++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index fd060447c..c138e4551 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -8,11 +8,14 @@ #include #include #include +#include #include +#include // Create local aliases for brevity namespace bpo = boost::program_options; +namespace bfs = boost::filesystem; ///See if the file has the named extension bool hasExtension(std::string filename, std::string extensionToFind) @@ -40,22 +43,30 @@ bool isBSA(std::string filename) return hasExtension(filename,"bsa"); } -///Check all the nif files in the given BSA archive -void readBSA(std::string filename) +/// Check all the nif files in a given VFS::Archive +/// \note Takes ownership! +void readVFS(VFS::Archive* anArchive) { VFS::Manager myManager(false); - myManager.addArchive(new VFS::BsaArchive(filename)); + myManager.addArchive(anArchive); myManager.buildIndex(); std::map files=myManager.getIndex(); for(std::map::const_iterator it=files.begin(); it!=files.end(); ++it) { - std::string name = it->first; - if(isNIF(name)) - { -// std::cout << "Decoding: " << name << std::endl; - Nif::NIFFile temp_nif(myManager.get(name),name); - } + std::string name = it->first; + + try{ + if(isNIF(name)) + { + // std::cout << "Decoding: " << name << std::endl; + Nif::NIFFile temp_nif(myManager.get(name),name); + } + } + catch (std::exception& e) + { + std::cerr << "ERROR, an exception has occurred: " << e.what() << std::endl; + } } } @@ -97,15 +108,7 @@ std::vector parseOptions (int argc, char** argv) } if (variables.count("input-file")) { - std::vector files = variables["input-file"].as< std::vector >(); - - std::cout << "Input files are:"; - for(std::vector::const_iterator it=files.begin(); it!=files.end(); ++it) - { - std::cout <<" "<< *it; - } - std::cout << std::endl; - return files; + return variables["input-file"].as< std::vector >(); } std::cout << "No input files or directories specified!" << std::endl; @@ -131,11 +134,16 @@ int main(int argc, char **argv) else if(isBSA(name)) { std::cout << "Reading BSA File: " << name << std::endl; - readBSA(name); + readVFS(new VFS::BsaArchive(name)); + } + else if(bfs::is_directory(bfs::path(name))) + { + std::cout << "Reading All Files in: " << name << std::endl; + readVFS(new VFS::FileSystemArchive(name)); } else { - std::cerr << "ERROR: \"" << name << "\" is not a nif or bsa file!" << std::endl; + std::cerr << "ERROR: \"" << name << "\" is not a nif file, bsa file, or directory!" << std::endl; } } catch (std::exception& e) From 6a6da42b85ed7a3cce05348b2f4b9b614539fe2f Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:22:18 -0400 Subject: [PATCH 222/419] Updated niftest's help message --- apps/niftest/niftest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index c138e4551..c50e664b0 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -74,8 +74,8 @@ std::vector parseOptions (int argc, char** argv) { bpo::options_description desc("Ensure that OpenMW can use the provided NIF and BSA files\n\n" "Usages:\n" - " niftool \n" - " Scan the file for read errors.\n\n" + " niftool \n" + " Scan the file or directories for nif errors.\n\n" "Allowed options"); desc.add_options() ("help,h", "print help message.") From 3d78ee0c2b9fff9e7dc801091f3c0a00fa159d91 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:39:43 -0400 Subject: [PATCH 223/419] niftest now scans BSA files in directories for nif errors The program is explicit so the user knows exactly where the bad file is. --- apps/niftest/niftest.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index c50e664b0..6229d1e83 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -45,9 +45,9 @@ bool isBSA(std::string filename) /// Check all the nif files in a given VFS::Archive /// \note Takes ownership! -void readVFS(VFS::Archive* anArchive) +void readVFS(VFS::Archive* anArchive,std::string archivePath = "") { - VFS::Manager myManager(false); + VFS::Manager myManager(true); myManager.addArchive(anArchive); myManager.buildIndex(); @@ -62,6 +62,15 @@ void readVFS(VFS::Archive* anArchive) // std::cout << "Decoding: " << name << std::endl; Nif::NIFFile temp_nif(myManager.get(name),name); } + else if(isBSA(name)) + { + if(!archivePath.empty()) + { + std::cout << "Reading BSA File: " << name << std::endl; + readVFS(new VFS::BsaArchive(archivePath+name)); + std::cout << "Done with BSA File: " << name << std::endl; + } + } } catch (std::exception& e) { @@ -139,7 +148,7 @@ int main(int argc, char **argv) else if(bfs::is_directory(bfs::path(name))) { std::cout << "Reading All Files in: " << name << std::endl; - readVFS(new VFS::FileSystemArchive(name)); + readVFS(new VFS::FileSystemArchive(name),name); } else { From c7b97ee9bab59c5e11c7237505c108fac58b1692 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:49:52 -0400 Subject: [PATCH 224/419] Cleaned up niftest's output A bad file inside of a bsa archive now looks like: /Data Files/TR_Data.bsa/meshes/tr/x/tr_act_ind_mark_alm.nif --- apps/niftest/niftest.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index 6229d1e83..72393db40 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -45,6 +45,7 @@ bool isBSA(std::string filename) /// Check all the nif files in a given VFS::Archive /// \note Takes ownership! +/// \note Can not read a bsa file inside of a bsa file. void readVFS(VFS::Archive* anArchive,std::string archivePath = "") { VFS::Manager myManager(true); @@ -60,15 +61,15 @@ void readVFS(VFS::Archive* anArchive,std::string archivePath = "") if(isNIF(name)) { // std::cout << "Decoding: " << name << std::endl; - Nif::NIFFile temp_nif(myManager.get(name),name); + Nif::NIFFile temp_nif(myManager.get(name),archivePath+name); } else if(isBSA(name)) { - if(!archivePath.empty()) + if(!archivePath.empty() && !isBSA(archivePath)) { - std::cout << "Reading BSA File: " << name << std::endl; - readVFS(new VFS::BsaArchive(archivePath+name)); - std::cout << "Done with BSA File: " << name << std::endl; +// std::cout << "Reading BSA File: " << name << std::endl; + readVFS(new VFS::BsaArchive(archivePath+name),archivePath+name+"/"); +// std::cout << "Done with BSA File: " << name << std::endl; } } } @@ -129,7 +130,7 @@ int main(int argc, char **argv) { std::vector files = parseOptions (argc, argv); - std::cout << "Reading Files" << std::endl; +// std::cout << "Reading Files" << std::endl; for(std::vector::const_iterator it=files.begin(); it!=files.end(); ++it) { std::string name = *it; @@ -142,12 +143,12 @@ int main(int argc, char **argv) } else if(isBSA(name)) { - std::cout << "Reading BSA File: " << name << std::endl; +// std::cout << "Reading BSA File: " << name << std::endl; readVFS(new VFS::BsaArchive(name)); } else if(bfs::is_directory(bfs::path(name))) { - std::cout << "Reading All Files in: " << name << std::endl; +// std::cout << "Reading All Files in: " << name << std::endl; readVFS(new VFS::FileSystemArchive(name),name); } else From 20078c41c36dfb7d2f482f2c0078cd73d1fb4bf9 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 7 Aug 2015 20:53:43 -0400 Subject: [PATCH 225/419] Removed now unneeded script --- apps/niftest/find_bad_nifs.sh | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100755 apps/niftest/find_bad_nifs.sh diff --git a/apps/niftest/find_bad_nifs.sh b/apps/niftest/find_bad_nifs.sh deleted file mode 100755 index 4b599f442..000000000 --- a/apps/niftest/find_bad_nifs.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -#Script to test all nif files (both loose, and in BSA archives) in data files directory - -#The user input as an absolute path -DATAFILESDIR="`readlink -m "$1"`" -#Program used to test -TEST_PROG="`pwd`/niftest" - -#Make sure our files don't bother anyone -NIFTEST_TMP_DIR="/tmp/niftest_$RANDOM/" -mkdir "$NIFTEST_TMP_DIR" -cd "$NIFTEST_TMP_DIR" - -find "$DATAFILESDIR" -iname *bsa > nifs.txt -find "$DATAFILESDIR" -iname *nif >> nifs.txt - -sed -e 's/.*/\"&\"/' nifs.txt > quoted_nifs.txt - -xargs --arg-file=quoted_nifs.txt "$TEST_PROG" 2>&1 | tee nif_out.txt -# xargs --arg-file=quoted_nifs.txt "$TEST_PROG" 2> nif_out.txt >/dev/null - -echo "List of bad NIF Files:" -cat nif_out.txt|grep File:|cut -d ' ' -f 2- - -rm nifs.txt -rm quoted_nifs.txt -rm nif_out.txt -rmdir "$NIFTEST_TMP_DIR" From 3046795a9c1197ed7fc9766fe78de84e37da1672 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 8 Aug 2015 11:01:08 +0200 Subject: [PATCH 226/419] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 291b0d56c..16c888239 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -29,6 +29,7 @@ Programmers Cory F. Cohen (cfcohen) Cris Mihalache (Mirceam) darkf + Dieho Dmitry Shkurskiy (endorph) Douglas Diniz (Dgdiniz) Douglas Mencken (dougmencken) From 708cacdec403793a0337c6e536a1ecf53a58bd6e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 8 Aug 2015 16:47:58 +0200 Subject: [PATCH 227/419] disable merge menu item when a merge is already in progress --- apps/opencs/view/doc/view.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index df7421a14..ea11bb0f9 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -398,7 +398,8 @@ void CSVDoc::View::updateActions() mGlobalDebugProfileMenu->updateActions (running); mStopDebug->setEnabled (running); - mMerge->setEnabled (mDocument->getContentFiles().size()>1); + mMerge->setEnabled (mDocument->getContentFiles().size()>1 && + !(mDocument->getState() & CSMDoc::State_Merging)); } CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) From 1676bf917e60f8a0d0614d628be779b0f65d6e28 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:06:52 +1200 Subject: [PATCH 228/419] CombatMove logic moved into AiCombatStorage. Basically, copied from mrcheko's 1d4be08f6e4c2dbd89cc0c3408a8231ee4497277 --- apps/openmw/mwmechanics/aicombat.cpp | 91 +++++++++++++++++----------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index f386ec81b..c8876c842 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -110,6 +110,10 @@ namespace MWMechanics mForceNoShortcut(false), mLastActorPos(0,0,0), mMovement(){} + + void startCombatMove(bool isNpc, bool isDistantCombat, float distToTarget, float rangeAttack); + void updateCombatMove(float duration); + void stopCombatMove(); }; AiCombat::AiCombat(const MWWorld::Ptr& actor) : @@ -192,19 +196,8 @@ namespace MWMechanics //Update every frame - bool& combatMove = storage.mCombatMove; - float& timerCombatMove = storage.mTimerCombatMove; + storage.updateCombatMove(duration); MWMechanics::Movement& movement = storage.mMovement; - if(combatMove) - { - timerCombatMove -= duration; - if( timerCombatMove <= 0) - { - timerCombatMove = 0; - movement.mPosition[1] = movement.mPosition[0] = 0; - combatMove = false; - } - } UpdateActorsMovement(actor, movement); @@ -454,31 +447,12 @@ namespace MWMechanics if (followTarget && distToTarget > rangeAttack) { //Close-up combat: just run up on target + storage.stopCombatMove(); movement.mPosition[1] = 1; } else // (within attack dist) { - if(movement.mPosition[0] || movement.mPosition[1]) - { - storage.mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); - storage.mCombatMove = true; - } - // only NPCs are smart enough to use dodge movements - else if(actorClass.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeAttack/2))) - { - //apply sideway movement (kind of dodging) with some probability - if (Misc::Rng::rollClosedProbability() < 0.25) - { - movement.mPosition[0] = Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; - storage.mTimerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability(); - storage.mCombatMove = true; - } - } - - if(distantCombat && distToTarget < rangeAttack/4) - { - movement.mPosition[1] = -1; - } + storage.startCombatMove(actorClass.isNpc(), distantCombat, distToTarget, rangeAttack); readyToAttack = true; //only once got in melee combat, actor is allowed to use close-up shortcutting @@ -551,14 +525,13 @@ namespace MWMechanics } } - movement.mPosition[1] = 1; if (readyToAttack) { // to stop possible sideway moving after target moved out of attack range - storage.mCombatMove = true; - storage.mTimerCombatMove = 0; + storage.stopCombatMove(); + readyToAttack = false; } - readyToAttack = false; + movement.mPosition[1] = 1; } return false; @@ -663,6 +636,50 @@ namespace MWMechanics package.mPackage = combat.release(); sequence.mPackages.push_back(package); } + + void AiCombatStorage::startCombatMove(bool isNpc, bool isDistantCombat, float distToTarget, float rangeAttack) + { + if (mMovement.mPosition[0] || mMovement.mPosition[1]) + { + mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); + mCombatMove = true; + } + // only NPCs are smart enough to use dodge movements + else if (isNpc && (!isDistantCombat || (distToTarget < rangeAttack / 2))) + { + //apply sideway movement (kind of dodging) with some probability + if (Misc::Rng::rollClosedProbability() < 0.25) + { + mMovement.mPosition[0] = Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; + mTimerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability(); + mCombatMove = true; + } + } + + if (isDistantCombat && distToTarget < rangeAttack / 4) + { + mMovement.mPosition[1] = -1; + } + } + + void AiCombatStorage::updateCombatMove(float duration) + { + if (mCombatMove) + { + mTimerCombatMove -= duration; + if (mTimerCombatMove <= 0) + { + stopCombatMove(); + } + } + } + + void AiCombatStorage::stopCombatMove() + { + mTimerCombatMove = 0; + mMovement.mPosition[1] = mMovement.mPosition[0] = 0; + mCombatMove = false; + } } From 0735e3e06e3c3a1241ea78ec402a28e38f8331e1 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:08:42 +1200 Subject: [PATCH 229/419] move start attack logic to AiCombatStorage. Basically, copied from mrchenko's 1d4be08f6e4c2dbd89cc0c3408a8231ee4497277 --- apps/openmw/mwmechanics/aicombat.cpp | 82 +++++++++++++++------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index c8876c842..03dc91c0a 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -114,6 +114,8 @@ namespace MWMechanics void startCombatMove(bool isNpc, bool isDistantCombat, float distToTarget, float rangeAttack); void updateCombatMove(float duration); void stopCombatMove(); + void startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController, + const ESM::Weapon* weapon, bool distantCombat); }; AiCombat::AiCombat(const MWWorld::Ptr& actor) : @@ -194,7 +196,6 @@ namespace MWMechanics || target.getClass().getCreatureStats(target).isDead()) return true; - //Update every frame storage.updateCombatMove(duration); MWMechanics::Movement& movement = storage.mMovement; @@ -318,41 +319,9 @@ namespace MWMechanics } - float& strength = storage.mStrength; bool& readyToAttack = storage.mReadyToAttack; // start new attack - if(readyToAttack && characterController.readyToStartAttack()) - { - if (storage.mAttackCooldown <= 0) - { - storage.mAttack = true; // attack starts just now - characterController.setAttackingOrSpell(true); - - if (!distantCombat) - chooseBestAttack(weapon, movement); - - strength = Misc::Rng::rollClosedProbability(); - - const MWWorld::ESMStore &store = world->getStore(); - - //say a provoking combat phrase - if (actor.getClass().isNpc()) - { - int chance = store.get().find("iVoiceAttackOdds")->getInt(); - if (Misc::Rng::roll0to99() < chance) - { - MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); - } - } - float baseDelay = store.get().find("fCombatDelayCreature")->getFloat(); - if (actor.getClass().isNpc()) - baseDelay = store.get().find("fCombatDelayNPC")->getFloat(); - storage.mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(), baseDelay + 0.9); - } - else - storage.mAttackCooldown -= REACTION_INTERVAL; - } - + storage.startAttackIfReady(actor, characterController, weapon, distantCombat); /* * Some notes on meanings of variables: @@ -403,9 +372,6 @@ namespace MWMechanics bool canMoveByZ = (actorClass.canSwim(actor) && world->isSwimming(actor)) || world->isFlying(actor); - // for distant combat we should know if target is in LOS even if distToTarget < rangeAttack - bool inLOS = distantCombat ? world->getLOS(actor, target) : true; - // can't fight if attacker can't go where target is. E.g. A fish can't attack person on land. if (distToTarget >= rangeAttack && !actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) @@ -419,6 +385,9 @@ namespace MWMechanics return false; } + // for distant combat we should know if target is in LOS even if distToTarget < rangeAttack + bool inLOS = distantCombat ? world->getLOS(actor, target) : true; + // (within attack dist) || (not quite attack dist while following) if(inLOS && (distToTarget < rangeAttack || (distToTarget <= rangeFollow && followTarget && !isStuck))) { @@ -432,7 +401,8 @@ namespace MWMechanics if (distantCombat) { osg::Vec3f& lastTargetPos = storage.mLastTargetPos; - osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, REACTION_INTERVAL, weaptype, strength); + osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, REACTION_INTERVAL, weaptype, + storage.mStrength); lastTargetPos = vTargetPos; movement.mRotation[0] = getXAngleToDir(vAimDir); movement.mRotation[2] = getZAngleToDir(vAimDir); @@ -680,6 +650,42 @@ namespace MWMechanics mMovement.mPosition[1] = mMovement.mPosition[0] = 0; mCombatMove = false; } + + void AiCombatStorage::startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController, + const ESM::Weapon* weapon, bool distantCombat) + { + if (mReadyToAttack && characterController.readyToStartAttack()) + { + if (mAttackCooldown <= 0) + { + mAttack = true; // attack starts just now + characterController.setAttackingOrSpell(true); + + if (!distantCombat) + chooseBestAttack(weapon, mMovement); + + mStrength = Misc::Rng::rollClosedProbability(); + + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + + float baseDelay = store.get().find("fCombatDelayCreature")->getFloat(); + if (actor.getClass().isNpc()) + { + baseDelay = store.get().find("fCombatDelayNPC")->getFloat(); + + //say a provoking combat phrase + int chance = store.get().find("iVoiceAttackOdds")->getInt(); + if (Misc::Rng::roll0to99() < chance) + { + MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); + } + } + mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(), baseDelay + 0.9); + } + else + mAttackCooldown -= REACTION_INTERVAL; + } + } } From 50ddcd19532756016d668f38baa071009f98d208 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:10:08 +1200 Subject: [PATCH 230/419] more attack logic moved into AiCombatStorage. --- apps/openmw/mwmechanics/aicombat.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 03dc91c0a..a5a48991a 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -116,6 +116,7 @@ namespace MWMechanics void stopCombatMove(); void startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController, const ESM::Weapon* weapon, bool distantCombat); + void updateAttack(CharacterController& characterController); }; AiCombat::AiCombat(const MWWorld::Ptr& actor) : @@ -201,12 +202,7 @@ namespace MWMechanics MWMechanics::Movement& movement = storage.mMovement; UpdateActorsMovement(actor, movement); - - bool& attack = storage.mAttack; - if (attack && (characterController.getAttackStrength() >= storage.mStrength || characterController.readyToPrepareAttack())) - attack = false; - - characterController.setAttackingOrSpell(attack); + storage.updateAttack(characterController); float& actionCooldown = storage.mActionCooldown; actionCooldown -= duration; @@ -686,6 +682,15 @@ namespace MWMechanics mAttackCooldown -= REACTION_INTERVAL; } } + + void AiCombatStorage::updateAttack(CharacterController& characterController) + { + if (mAttack && (characterController.getAttackStrength() >= mStrength || characterController.readyToPrepareAttack())) + { + mAttack = false; + } + characterController.setAttackingOrSpell(mAttack); + } } From 038851420d5615d7ce470bd83312e0b3d00ee180 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:18:55 +1200 Subject: [PATCH 231/419] Removed unneeded temp variables. Corrected case of function names. --- apps/openmw/mwmechanics/aicombat.cpp | 16 ++++++---------- apps/openmw/mwmechanics/aicombat.hpp | 4 ++-- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index a5a48991a..b1889605d 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -199,13 +199,9 @@ namespace MWMechanics //Update every frame storage.updateCombatMove(duration); - MWMechanics::Movement& movement = storage.mMovement; - - UpdateActorsMovement(actor, movement); + updateActorsMovement(actor, storage.mMovement); storage.updateAttack(characterController); - - float& actionCooldown = storage.mActionCooldown; - actionCooldown -= duration; + storage.mActionCooldown -= duration; float& timerReact = storage.mTimerReact; if(timerReact < REACTION_INTERVAL) @@ -503,7 +499,7 @@ namespace MWMechanics return false; } - void AiCombat::UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& desiredMovement) + void AiCombat::updateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& desiredMovement) { MWMechanics::Movement& actorMovementSettings = actor.getClass().getMovementSettings(actor); if (mPathFinder.isPathConstructed()) @@ -522,12 +518,12 @@ namespace MWMechanics else { actorMovementSettings = desiredMovement; - RotateActorOnAxis(actor, 2, actorMovementSettings, desiredMovement); - RotateActorOnAxis(actor, 0, actorMovementSettings, desiredMovement); + rotateActorOnAxis(actor, 2, actorMovementSettings, desiredMovement); + rotateActorOnAxis(actor, 0, actorMovementSettings, desiredMovement); } } - void AiCombat::RotateActorOnAxis(const MWWorld::Ptr& actor, int axis, + void AiCombat::rotateActorOnAxis(const MWWorld::Ptr& actor, int axis, MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement) { actorMovementSettings.mRotation[axis] = 0; diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 4e4060819..73d0254f3 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -65,8 +65,8 @@ namespace MWMechanics AiCombatStorage& storage, MWWorld::Ptr target); /// Transfer desired movement (from AiCombatStorage) to Actor - void UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& movement); - void RotateActorOnAxis(const MWWorld::Ptr& actor, int axis, + void updateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& movement); + void rotateActorOnAxis(const MWWorld::Ptr& actor, int axis, MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement); }; From 0884a3796f7e6174bf93b1b4311680faa1c67b0a Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:20:55 +1200 Subject: [PATCH 232/419] extracted function isTargetMagicallyHidden(). --- apps/openmw/mwmechanics/aicombat.cpp | 3 +-- apps/openmw/mwmechanics/aipackage.cpp | 8 ++++++++ apps/openmw/mwmechanics/aipackage.hpp | 2 ++ apps/openmw/mwmechanics/aipursue.cpp | 3 +-- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index b1889605d..8a51a4cb0 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -222,8 +222,7 @@ namespace MWMechanics MWMechanics::Movement& movement = storage.mMovement; // Stop attacking if target is not seen - if (target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude() > 0 - || target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude() > 75) + if (isTargetMagicallyHidden(target)) { movement.mPosition[1] = movement.mPosition[0] = 0; return false; // TODO: run away instead of doing nothing diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 77efe62a8..d10edd589 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -129,3 +130,10 @@ bool MWMechanics::AiPackage::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const { return distance(mPrevDest, dest) > 10; } + +bool MWMechanics::AiPackage::isTargetMagicallyHidden(const MWWorld::Ptr& target) +{ + MagicEffects& magicEffects(target.getClass().getCreatureStats(target).getMagicEffects()); + return (magicEffects.get(ESM::MagicEffect::Invisibility).getMagnitude() > 0) + || (magicEffects.get(ESM::MagicEffect::Chameleon).getMagnitude() > 75); +} diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index da43dc6da..d73833b94 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -69,6 +69,8 @@ namespace MWMechanics /// Simulates the passing of time virtual void fastForward(const MWWorld::Ptr& actor, AiState& state) {} + bool isTargetMagicallyHidden(const MWWorld::Ptr& target); + protected: /// Causes the actor to attempt to walk to the specified location /** \return If the actor has arrived at his destination **/ diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index e936505c9..055801fde 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -43,8 +43,7 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte ) return true; //Target doesn't exist - if (target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude() > 0 - || target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude() > 75) + if (isTargetMagicallyHidden(target)) return true; if(target.getClass().getCreatureStats(target).isDead()) From 2b9e22f593ebc862cfdc1df070249725e760a460 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 14:29:38 +1200 Subject: [PATCH 233/419] extracted function stopAttack(). --- apps/openmw/mwmechanics/aicombat.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 8a51a4cb0..5ea3ba6a3 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -117,6 +117,7 @@ namespace MWMechanics void startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController, const ESM::Weapon* weapon, bool distantCombat); void updateAttack(CharacterController& characterController); + void stopAttack(); }; AiCombat::AiCombat(const MWWorld::Ptr& actor) : @@ -221,10 +222,9 @@ namespace MWMechanics { MWMechanics::Movement& movement = storage.mMovement; - // Stop attacking if target is not seen if (isTargetMagicallyHidden(target)) { - movement.mPosition[1] = movement.mPosition[0] = 0; + storage.stopAttack(); return false; // TODO: run away instead of doing nothing } @@ -368,11 +368,7 @@ namespace MWMechanics && !actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) { // TODO: start fleeing? - movement.mPosition[0] = 0; - movement.mPosition[1] = 0; - movement.mPosition[2] = 0; - readyToAttack = false; - characterController.setAttackingOrSpell(false); + storage.stopAttack(); return false; } @@ -686,6 +682,15 @@ namespace MWMechanics } characterController.setAttackingOrSpell(mAttack); } + + void AiCombatStorage::stopAttack() + { + mMovement.mPosition[0] = 0; + mMovement.mPosition[1] = 0; + mMovement.mPosition[2] = 0; + mReadyToAttack = false; + mAttack = false; + } } From e42a2478dcae9445d72c48384658c682acc11f42 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 9 Aug 2015 17:58:40 +1200 Subject: [PATCH 234/419] Removed tests that are not necessary. --- apps/openmw/mwmechanics/pathfinding.cpp | 80 ++++++++++++------------- 1 file changed, 37 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index c7d71e13e..f469832a5 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -51,8 +51,7 @@ namespace const MWWorld::CellStore *cell, const osg::Vec3f pos, int start) { - if(!grid || grid->mPoints.empty()) - return std::pair (-1, false); + assert(grid && !grid->mPoints.empty()); float distanceBetween = distanceSquared(grid->mPoints[0], pos); int closestIndex = 0; @@ -76,8 +75,6 @@ namespace // AiWander has logic that depends on whether a path was created, deleting // allowed nodes if not. Hence a path needs to be created even if the start // and the end points are the same. - //if(start == closestReachableIndex) - //closestReachableIndex = -1; // couldn't find anyting other than start return std::pair (closestReachableIndex, closestReachableIndex == closestIndex); @@ -110,6 +107,11 @@ namespace MWMechanics return sqrt(x * x + y * y + z * z); } + osg::Vec3f ToLocalCoordinates(const ESM::Pathgrid::Point &point, float xCell, float yCell) + { + return osg::Vec3f(point.mX - xCell, point.mY - yCell, static_cast(point.mZ)); + } + PathFinder::PathFinder() : mPathgrid(NULL), mCell(NULL) @@ -139,8 +141,6 @@ namespace MWMechanics * pathgrid point (e.g. wander) then it may be worth while to call * pop_back() to remove the redundant entry. * - * mPathConstructed is set true if successful, false if not - * * NOTE: co-ordinates must be converted prior to calling getClosestPoint() * * | @@ -208,46 +208,40 @@ namespace MWMechanics // outside an area enclosed by walls, but there is a pathgrid // point right behind the wall that is closer than any pathgrid // point outside the wall - int startNode = getClosestPoint(mPathgrid, - osg::Vec3f(startPoint.mX - xCell, startPoint.mY - yCell, static_cast(startPoint.mZ))); - // Some cells don't have any pathgrids at all - if(startNode != -1) + osg::Vec3f startPointInLocalCoords(ToLocalCoordinates(startPoint, xCell, yCell)); + int startNode = getClosestPoint(mPathgrid, startPointInLocalCoords); + + osg::Vec3f endPointInLocalCoords(ToLocalCoordinates(endPoint, xCell, yCell)); + std::pair endNode = getClosestReachablePoint(mPathgrid, cell, + endPointInLocalCoords, + startNode); + + // AiWander has logic that depends on whether a path was created, + // deleting allowed nodes if not. Hence a path needs to be created + // even if the start and the end points are the same. + // NOTE: aStarSearch will return an empty path if the start and end + // nodes are the same + if(startNode == endNode.first) { - std::pair endNode = getClosestReachablePoint(mPathgrid, cell, - osg::Vec3f(endPoint.mX - xCell, endPoint.mY - yCell, static_cast(endPoint.mZ)), - startNode); + mPath.push_back(endPoint); + return; + } - // this shouldn't really happen, but just in case - if(endNode.first != -1) - { - // AiWander has logic that depends on whether a path was created, - // deleting allowed nodes if not. Hence a path needs to be created - // even if the start and the end points are the same. - // NOTE: aStarSearch will return an empty path if the start and end - // nodes are the same - if(startNode == endNode.first) - { - mPath.push_back(endPoint); - return; - } + mPath = mCell->aStarSearch(startNode, endNode.first); - mPath = mCell->aStarSearch(startNode, endNode.first); - - if(!mPath.empty()) - { - // Add the destination (which may be different to the closest - // pathgrid point). However only add if endNode was the closest - // point to endPoint. - // - // This logic can fail in the opposite situate, e.g. endPoint may - // have been reachable but happened to be very close to an - // unreachable pathgrid point. - // - // The AI routines will have to deal with such situations. - if(endNode.second) - mPath.push_back(endPoint); - } - } + if(!mPath.empty()) + { + // Add the destination (which may be different to the closest + // pathgrid point). However only add if endNode was the closest + // point to endPoint. + // + // This logic can fail in the opposite situate, e.g. endPoint may + // have been reachable but happened to be very close to an + // unreachable pathgrid point. + // + // The AI routines will have to deal with such situations. + if(endNode.second) + mPath.push_back(endPoint); } return; From 55e3aaaa35c491ecd24edc74094c66c42ab3c3ef Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 10 Aug 2015 20:30:43 +1200 Subject: [PATCH 235/419] made variable const. --- apps/openmw/mwmechanics/aipackage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index d10edd589..1ab3264b7 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -133,7 +133,7 @@ bool MWMechanics::AiPackage::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const bool MWMechanics::AiPackage::isTargetMagicallyHidden(const MWWorld::Ptr& target) { - MagicEffects& magicEffects(target.getClass().getCreatureStats(target).getMagicEffects()); + const MagicEffects& magicEffects(target.getClass().getCreatureStats(target).getMagicEffects()); return (magicEffects.get(ESM::MagicEffect::Invisibility).getMagnitude() > 0) || (magicEffects.get(ESM::MagicEffect::Chameleon).getMagnitude() > 75); } From 5fba7400a6320b5b8e943635719be9384d3ada7c Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Mon, 3 Aug 2015 19:17:26 +0200 Subject: [PATCH 236/419] Borrow modified bundle utilities from https://github.com/Slicer/Slicer They support dependencies with @rpath --- cmake/BundleUtilitiesWithRPath.cmake | 961 +++++++++++++++++++++++++ cmake/COPYING-CMAKE-SCRIPTS | 266 +++++++ cmake/GetPrerequisitesWithRPath.cmake | 990 ++++++++++++++++++++++++++ 3 files changed, 2217 insertions(+) create mode 100644 cmake/BundleUtilitiesWithRPath.cmake create mode 100644 cmake/GetPrerequisitesWithRPath.cmake diff --git a/cmake/BundleUtilitiesWithRPath.cmake b/cmake/BundleUtilitiesWithRPath.cmake new file mode 100644 index 000000000..5254e1a52 --- /dev/null +++ b/cmake/BundleUtilitiesWithRPath.cmake @@ -0,0 +1,961 @@ +#.rst: +# BundleUtilities +# --------------- +# +# Functions to help assemble a standalone bundle application. +# +# A collection of CMake utility functions useful for dealing with .app +# bundles on the Mac and bundle-like directories on any OS. +# +# The following functions are provided by this module: +# +# :: +# +# fixup_bundle +# copy_and_fixup_bundle +# verify_app +# get_bundle_main_executable +# get_dotapp_dir +# get_bundle_and_executable +# get_bundle_all_executables +# get_item_key +# clear_bundle_keys +# set_bundle_key_values +# get_bundle_keys +# copy_resolved_item_into_bundle +# copy_resolved_framework_into_bundle +# fixup_bundle_item +# verify_bundle_prerequisites +# verify_bundle_symlinks +# +# Requires CMake 2.6 or greater because it uses function, break and +# PARENT_SCOPE. Also depends on GetPrerequisites.cmake. +# +# :: +# +# FIXUP_BUNDLE( ) +# +# Fix up a bundle in-place and make it standalone, such that it can be +# drag-n-drop copied to another machine and run on that machine as long +# as all of the system libraries are compatible. +# +# If you pass plugins to fixup_bundle as the libs parameter, you should +# install them or copy them into the bundle before calling fixup_bundle. +# The "libs" parameter is a list of libraries that must be fixed up, but +# that cannot be determined by otool output analysis. (i.e., plugins) +# +# Gather all the keys for all the executables and libraries in a bundle, +# and then, for each key, copy each prerequisite into the bundle. Then +# fix each one up according to its own list of prerequisites. +# +# Then clear all the keys and call verify_app on the final bundle to +# ensure that it is truly standalone. +# +# :: +# +# COPY_AND_FIXUP_BUNDLE( ) +# +# Makes a copy of the bundle at location and then fixes up +# the new copied bundle in-place at ... +# +# :: +# +# VERIFY_APP() +# +# Verifies that an application appears valid based on running +# analysis tools on it. Calls "message(FATAL_ERROR" if the application +# is not verified. +# +# :: +# +# GET_BUNDLE_MAIN_EXECUTABLE( ) +# +# The result will be the full path name of the bundle's main executable +# file or an "error:" prefixed string if it could not be determined. +# +# :: +# +# GET_DOTAPP_DIR( ) +# +# Returns the nearest parent dir whose name ends with ".app" given the +# full path to an executable. If there is no such parent dir, then +# simply return the dir containing the executable. +# +# The returned directory may or may not exist. +# +# :: +# +# GET_BUNDLE_AND_EXECUTABLE( ) +# +# Takes either a ".app" directory name or the name of an executable +# nested inside a ".app" directory and returns the path to the ".app" +# directory in and the path to its main executable in +# +# +# :: +# +# GET_BUNDLE_ALL_EXECUTABLES( ) +# +# Scans the given bundle recursively for all executable files and +# accumulates them into a variable. +# +# :: +# +# GET_ITEM_KEY( ) +# +# Given a file (item) name, generate a key that should be unique +# considering the set of libraries that need copying or fixing up to +# make a bundle standalone. This is essentially the file name including +# extension with "." replaced by "_" +# +# This key is used as a prefix for CMake variables so that we can +# associate a set of variables with a given item based on its key. +# +# :: +# +# CLEAR_BUNDLE_KEYS() +# +# Loop over the list of keys, clearing all the variables associated with +# each key. After the loop, clear the list of keys itself. +# +# Caller of get_bundle_keys should call clear_bundle_keys when done with +# list of keys. +# +# :: +# +# SET_BUNDLE_KEY_VALUES( +# ) +# +# Add a key to the list (if necessary) for the given item. If added, +# also set all the variables associated with that key. +# +# :: +# +# GET_BUNDLE_KEYS( ) +# +# Loop over all the executable and library files within the bundle (and +# given as extra ) and accumulate a list of keys representing +# them. Set values associated with each key such that we can loop over +# all of them and copy prerequisite libs into the bundle and then do +# appropriate install_name_tool fixups. +# +# :: +# +# COPY_RESOLVED_ITEM_INTO_BUNDLE( ) +# +# Copy a resolved item into the bundle if necessary. Copy is not +# necessary if the resolved_item is "the same as" the +# resolved_embedded_item. +# +# :: +# +# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE( ) +# +# Copy a resolved framework into the bundle if necessary. Copy is not +# necessary if the resolved_item is "the same as" the +# resolved_embedded_item. +# +# By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set. If you want +# full frameworks embedded in your bundles, set +# BU_COPY_FULL_FRAMEWORK_CONTENTS to ON before calling fixup_bundle. By +# default, COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework +# dylib itself plus the framework Resources directory. +# +# :: +# +# IS_RESOLVED_ITEM_EMBEDDED( ) +# +# Set variable to True if the resolved item is +# embedded into the bundle. The function does NOT check for the existence of the +# item, instead if checks if the provided path would correspond to an embeddable +# item. If is True, extra information will be displayed in case the item +# is not embedded. +# +# :: +# +# FIXUP_BUNDLE_ITEM( ) +# +# Get the direct/non-system prerequisites of the resolved embedded item. +# For each prerequisite, change the way it is referenced to the value of +# the _EMBEDDED_ITEM keyed variable for that prerequisite. (Most likely +# changing to an "@executable_path" style reference.) +# +# This function requires that the resolved_embedded_item be "inside" the +# bundle already. In other words, if you pass plugins to fixup_bundle +# as the libs parameter, you should install them or copy them into the +# bundle before calling fixup_bundle. The "libs" parameter is a list of +# libraries that must be fixed up, but that cannot be determined by +# otool output analysis. (i.e., plugins) +# +# Also, change the id of the item being fixed up to its own +# _EMBEDDED_ITEM value. +# +# Accumulate changes in a local variable and make *one* call to +# install_name_tool at the end of the function with all the changes at +# once. +# +# If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be +# marked writable before install_name_tool tries to change them. +# +# :: +# +# VERIFY_BUNDLE_PREREQUISITES( ) +# +# Verifies that the sum of all prerequisites of all files inside the +# bundle are contained within the bundle or are "system" libraries, +# presumed to exist everywhere. +# +# :: +# +# VERIFY_BUNDLE_SYMLINKS( ) +# +# Verifies that any symlinks found in the bundle point to other files +# that are already also in the bundle... Anything that points to an +# external file causes this function to fail the verification. + +#============================================================================= +# Copyright 2008-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# Copyright (c) 2015 BWH and 3D Slicer contributors, http://slicer.org +# +# Redistribution AND use is allowed according to the terms of the +# BSD-style license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +# The functions defined in this file depend on the get_prerequisites function +# (and possibly others) found in: +# +get_filename_component(BundleUtilities_cmake_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) +include("${BundleUtilities_cmake_dir}/GetPrerequisitesWithRPath.cmake") + + +function(get_bundle_main_executable bundle result_var) + set(result "error: '${bundle}/Contents/Info.plist' file does not exist") + + if(EXISTS "${bundle}/Contents/Info.plist") + set(result "error: no CFBundleExecutable in '${bundle}/Contents/Info.plist' file") + set(line_is_main_executable 0) + set(bundle_executable "") + + # Read Info.plist as a list of lines: + # + set(eol_char "E") + file(READ "${bundle}/Contents/Info.plist" info_plist) + string(REPLACE ";" "\\;" info_plist "${info_plist}") + string(REPLACE "\n" "${eol_char};" info_plist "${info_plist}") + string(REPLACE "\r" "${eol_char};" info_plist "${info_plist}") + + # Scan the lines for "CFBundleExecutable" - the line after that + # is the name of the main executable. + # + foreach(line ${info_plist}) + if(line_is_main_executable) + string(REGEX REPLACE "^.*(.*).*$" "\\1" bundle_executable "${line}") + break() + endif() + + if(line MATCHES "CFBundleExecutable") + set(line_is_main_executable 1) + endif() + endforeach() + + if(NOT "${bundle_executable}" STREQUAL "") + if(EXISTS "${bundle}/Contents/MacOS/${bundle_executable}") + set(result "${bundle}/Contents/MacOS/${bundle_executable}") + else() + + # Ultimate goal: + # If not in "Contents/MacOS" then scan the bundle for matching files. If + # there is only one executable file that matches, then use it, otherwise + # it's an error... + # + #file(GLOB_RECURSE file_list "${bundle}/${bundle_executable}") + + # But for now, pragmatically, it's an error. Expect the main executable + # for the bundle to be in Contents/MacOS, it's an error if it's not: + # + set(result "error: '${bundle}/Contents/MacOS/${bundle_executable}' does not exist") + endif() + endif() + else() + # + # More inclusive technique... (This one would work on Windows and Linux + # too, if a developer followed the typical Mac bundle naming convention...) + # + # If there is no Info.plist file, try to find an executable with the same + # base name as the .app directory: + # + endif() + + set(${result_var} "${result}" PARENT_SCOPE) +endfunction() + + +function(get_dotapp_dir exe dotapp_dir_var) + set(s "${exe}") + + if(s MATCHES "/.*\\.app/") + # If there is a ".app" parent directory, + # ascend until we hit it: + # (typical of a Mac bundle executable) + # + set(done 0) + while(NOT ${done}) + get_filename_component(snamewe "${s}" NAME_WE) + get_filename_component(sname "${s}" NAME) + get_filename_component(sdir "${s}" PATH) + set(s "${sdir}") + if(sname MATCHES "\\.app$") + set(done 1) + set(dotapp_dir "${sdir}/${sname}") + endif() + endwhile() + else() + # Otherwise use a directory containing the exe + # (typical of a non-bundle executable on Mac, Windows or Linux) + # + is_file_executable("${s}" is_executable) + if(is_executable) + get_filename_component(sdir "${s}" PATH) + set(dotapp_dir "${sdir}") + else() + set(dotapp_dir "${s}") + endif() + endif() + + + set(${dotapp_dir_var} "${dotapp_dir}" PARENT_SCOPE) +endfunction() + + +function(get_bundle_and_executable app bundle_var executable_var valid_var) + set(valid 0) + + if(EXISTS "${app}") + # Is it a directory ending in .app? + if(IS_DIRECTORY "${app}") + if(app MATCHES "\\.app$") + get_bundle_main_executable("${app}" executable) + if(EXISTS "${app}" AND EXISTS "${executable}") + set(${bundle_var} "${app}" PARENT_SCOPE) + set(${executable_var} "${executable}" PARENT_SCOPE) + set(valid 1) + #message(STATUS "info: handled .app directory case...") + else() + message(STATUS "warning: *NOT* handled - .app directory case...") + endif() + else() + message(STATUS "warning: *NOT* handled - directory but not .app case...") + endif() + else() + # Is it an executable file? + is_file_executable("${app}" is_executable) + if(is_executable) + get_dotapp_dir("${app}" dotapp_dir) + if(EXISTS "${dotapp_dir}") + set(${bundle_var} "${dotapp_dir}" PARENT_SCOPE) + set(${executable_var} "${app}" PARENT_SCOPE) + set(valid 1) + #message(STATUS "info: handled executable file in .app dir case...") + else() + get_filename_component(app_dir "${app}" PATH) + set(${bundle_var} "${app_dir}" PARENT_SCOPE) + set(${executable_var} "${app}" PARENT_SCOPE) + set(valid 1) + #message(STATUS "info: handled executable file in any dir case...") + endif() + else() + message(STATUS "warning: *NOT* handled - not .app dir, not executable file...") + endif() + endif() + else() + message(STATUS "warning: *NOT* handled - directory/file does not exist...") + endif() + + if(NOT valid) + set(${bundle_var} "error: not a bundle" PARENT_SCOPE) + set(${executable_var} "error: not a bundle" PARENT_SCOPE) + endif() + + set(${valid_var} ${valid} PARENT_SCOPE) +endfunction() + + +function(get_bundle_all_executables bundle exes_var) + set(exes "") + + file(GLOB_RECURSE file_list "${bundle}/*") + if(UNIX) + find_program(find_cmd "find") + mark_as_advanced(find_cmd) + endif() + + # find command is much quicker than checking every file one by one on Unix + # which can take long time for large bundles, and since anyway we expect + # executable to have execute flag set we can narrow the list much quicker. + if(find_cmd) + execute_process(COMMAND "${find_cmd}" "${bundle}" + -type f \( -perm -0100 -o -perm -0010 -o -perm -0001 \) + OUTPUT_VARIABLE file_list + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + string(REPLACE "\n" ";" file_list "${file_list}") + else() + file(GLOB_RECURSE file_list "${bundle}/*") + endif() + + foreach(f ${file_list}) + is_file_executable("${f}" is_executable) + if(is_executable) + set(exes ${exes} "${f}") + endif() + endforeach() + + set(${exes_var} "${exes}" PARENT_SCOPE) +endfunction() + + +function(get_item_key item key_var) + get_filename_component(item_name "${item}" NAME) + if(WIN32) + string(TOLOWER "${item_name}" item_name) + endif() + string(REPLACE "." "_" ${key_var} "${item_name}") + set(${key_var} ${${key_var}} PARENT_SCOPE) +endfunction() + + +function(clear_bundle_keys keys_var) + foreach(key ${${keys_var}}) + set(${key}_ITEM PARENT_SCOPE) + set(${key}_RESOLVED_ITEM PARENT_SCOPE) + set(${key}_DEFAULT_EMBEDDED_PATH PARENT_SCOPE) + set(${key}_EMBEDDED_ITEM PARENT_SCOPE) + set(${key}_RESOLVED_EMBEDDED_ITEM PARENT_SCOPE) + set(${key}_COPYFLAG PARENT_SCOPE) + endforeach() + set(${keys_var} PARENT_SCOPE) +endfunction() + + +function(set_bundle_key_values keys_var context item exepath dirs copyflag) + get_filename_component(item_name "${item}" NAME) + + get_item_key("${item}" key) + + list(LENGTH ${keys_var} length_before) + gp_append_unique(${keys_var} "${key}") + list(LENGTH ${keys_var} length_after) + + if(NOT length_before EQUAL length_after) + gp_resolve_item("${context}" "${item}" "${exepath}" "${dirs}" resolved_item) + + gp_item_default_embedded_path("${item}" default_embedded_path) + + if(item MATCHES "[^/]+\\.framework/") + # For frameworks, construct the name under the embedded path from the + # opening "${item_name}.framework/" to the closing "/${item_name}": + # + string(REGEX REPLACE "^.*(${item_name}.framework/.*/?${item_name}).*$" "${default_embedded_path}/\\1" embedded_item "${item}") + else() + # For other items, just use the same name as the original, but in the + # embedded path: + # + set(embedded_item "${default_embedded_path}/${item_name}") + + if(APPLE) + # For executables inside the bundle, extract the expected path. + # This remove the hack introduced in commit 6f8bdd27 consisting in + # reseting the value of 'resolved_embedded_item' with 'resolved_item'. + get_dotapp_dir("${exepath}" exe_dotapp_dir) + if(NOT DEFINED gp_bundle_executables) + get_bundle_all_executables("${exe_dotapp_dir}" gp_bundle_executables) + endif() + foreach(exe ${gp_bundle_executables}) + get_item_key("${exe}" exe_key) + list(APPEND exe_keys ${exe_key}) + endforeach() + list(FIND exe_keys ${key} is_executable) + if(NOT is_executable EQUAL "-1") + get_filename_component(resolved_item_path ${resolved_item} PATH) + file(RELATIVE_PATH exe_relative_path_from_dir ${exe_dotapp_dir} ${resolved_item_path}) + # For example, if input variables are: + # resolved_item: /path/to/MyApp.app/Contents/bin/myapp + # exe_dotapp_dir: /path/to/MyApp.app + # Computed variables will be: + # resolved_item_path: /path/to/MyApp.app/Contents/bin + # exe_relative_path_from_dir: Contents/bin + set(embedded_item "@executable_path/../../${exe_relative_path_from_dir}/${item_name}") + set(show_status 0) + if(show_status) + message(STATUS "resolved_item='${resolved_item}'") + message(STATUS "exe_dotapp_dir='${exe_dotapp_dir}'") + message(STATUS "exe_relative_path_from_dir='${exe_relative_path_from_dir}'") + message(STATUS "item_name='${item_name}'") + message(STATUS "embedded_item='${embedded_item}'") + message(STATUS "") + endif() + endif() + endif() + endif() + + gp_resolve_embedded_item("${context}" "${embedded_item}" "${exepath}" resolved_embedded_item) + get_filename_component(resolved_embedded_item "${resolved_embedded_item}" ABSOLUTE) + + # Do not copy already embedded item + set(verbose 0) + is_resolved_item_embedded("${resolved_embedded_item}" "${exepath}" "${verbose}" is_embedded) + if(EXISTS "${resolved_embedded_item}" AND is_embedded) + set(copyflag 0) + set(resolved_item "${resolved_embedded_item}") + endif() + + set(${keys_var} ${${keys_var}} PARENT_SCOPE) + set(${key}_ITEM "${item}" PARENT_SCOPE) + set(${key}_RESOLVED_ITEM "${resolved_item}" PARENT_SCOPE) + set(${key}_DEFAULT_EMBEDDED_PATH "${default_embedded_path}" PARENT_SCOPE) + set(${key}_EMBEDDED_ITEM "${embedded_item}" PARENT_SCOPE) + set(${key}_RESOLVED_EMBEDDED_ITEM "${resolved_embedded_item}" PARENT_SCOPE) + set(${key}_COPYFLAG "${copyflag}" PARENT_SCOPE) + else() + #message("warning: item key '${key}' already in the list, subsequent references assumed identical to first") + endif() +endfunction() + + +function(get_bundle_keys app libs dirs keys_var) + set(${keys_var} PARENT_SCOPE) + + get_bundle_and_executable("${app}" bundle executable valid) + if(valid) + # Always use the exepath of the main bundle executable for @executable_path + # replacements: + # + get_filename_component(exepath "${executable}" PATH) + + # But do fixups on all executables in the bundle: + # + get_bundle_all_executables("${bundle}" gp_bundle_executables) + + # For each extra lib, accumulate a key as well and then also accumulate + # any of its prerequisites. (Extra libs are typically dynamically loaded + # plugins: libraries that are prerequisites for full runtime functionality + # but that do not show up in otool -L output...) + # + foreach(lib ${libs}) + set_bundle_key_values(${keys_var} "${lib}" "${lib}" "${exepath}" "${dirs}" 0) + + set(prereqs "") + get_prerequisites("${lib}" prereqs 1 1 "${exepath}" "${dirs}") + foreach(pr ${prereqs}) + set_bundle_key_values(${keys_var} "${lib}" "${pr}" "${exepath}" "${dirs}" 1) + endforeach() + endforeach() + + # For each executable found in the bundle, accumulate keys as we go. + # The list of keys should be complete when all prerequisites of all + # binaries in the bundle have been analyzed. + # + foreach(exe ${gp_bundle_executables}) + # Add the exe itself to the keys: + # + set_bundle_key_values(${keys_var} "${exe}" "${exe}" "${exepath}" "${dirs}" 0) + + # Add each prerequisite to the keys: + # + set(prereqs "") + get_prerequisites("${exe}" prereqs 1 1 "${exepath}" "${dirs}") + foreach(pr ${prereqs}) + set_bundle_key_values(${keys_var} "${exe}" "${pr}" "${exepath}" "${dirs}" 1) + endforeach() + endforeach() + + # Propagate values to caller's scope: + # + set(${keys_var} ${${keys_var}} PARENT_SCOPE) + foreach(key ${${keys_var}}) + set(${key}_ITEM "${${key}_ITEM}" PARENT_SCOPE) + set(${key}_RESOLVED_ITEM "${${key}_RESOLVED_ITEM}" PARENT_SCOPE) + set(${key}_DEFAULT_EMBEDDED_PATH "${${key}_DEFAULT_EMBEDDED_PATH}" PARENT_SCOPE) + set(${key}_EMBEDDED_ITEM "${${key}_EMBEDDED_ITEM}" PARENT_SCOPE) + set(${key}_RESOLVED_EMBEDDED_ITEM "${${key}_RESOLVED_EMBEDDED_ITEM}" PARENT_SCOPE) + set(${key}_COPYFLAG "${${key}_COPYFLAG}" PARENT_SCOPE) + endforeach() + endif() +endfunction() + + +function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item) + if(WIN32) + # ignore case on Windows + string(TOLOWER "${resolved_item}" resolved_item_compare) + string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare) + else() + set(resolved_item_compare "${resolved_item}") + set(resolved_embedded_item_compare "${resolved_embedded_item}") + endif() + + if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}") + message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...") + else() + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") + if(UNIX AND NOT APPLE) + file(RPATH_REMOVE FILE "${resolved_embedded_item}") + endif() + endif() + +endfunction() + + +function(copy_resolved_framework_into_bundle resolved_item resolved_embedded_item) + if(WIN32) + # ignore case on Windows + string(TOLOWER "${resolved_item}" resolved_item_compare) + string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare) + else() + set(resolved_item_compare "${resolved_item}") + set(resolved_embedded_item_compare "${resolved_embedded_item}") + endif() + + if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}") + message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...") + else() + if(BU_COPY_FULL_FRAMEWORK_CONTENTS) + # Full Framework (everything): + get_filename_component(resolved_dir "${resolved_item}" PATH) + get_filename_component(resolved_dir "${resolved_dir}/../.." ABSOLUTE) + get_filename_component(resolved_embedded_dir "${resolved_embedded_item}" PATH) + get_filename_component(resolved_embedded_dir "${resolved_embedded_dir}/../.." ABSOLUTE) + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_dir}' '${resolved_embedded_dir}'") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_dir}" "${resolved_embedded_dir}") + else() + # Framework lib itself: + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") + + # Plus Resources, if they exist: + string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources" resolved_resources "${resolved_item}") + string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources" resolved_embedded_resources "${resolved_embedded_item}") + if(EXISTS "${resolved_resources}") + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_resources}' '${resolved_embedded_resources}'") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_resources}" "${resolved_embedded_resources}") + endif() + + # Some frameworks e.g. Qt put Info.plist in wrong place, so when it is + # missing in resources, copy it from other well known incorrect locations: + if(NOT EXISTS "${resolved_resources}/Info.plist") + # Check for Contents/Info.plist in framework root (older Qt SDK): + string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Contents/Info.plist" resolved_info_plist "${resolved_item}") + string(REGEX REPLACE "^(.*)/[^/]+$" "\\1/Resources/Info.plist" resolved_embedded_info_plist "${resolved_embedded_item}") + if(EXISTS "${resolved_info_plist}") + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_info_plist}' '${resolved_embedded_info_plist}'") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_info_plist}" "${resolved_embedded_info_plist}") + endif() + endif() + + # Check if framework is versioned and fix it layout + string(REGEX REPLACE "^.*/([^/]+)/[^/]+$" "\\1" resolved_embedded_version "${resolved_embedded_item}") + string(REGEX REPLACE "^(.*)/[^/]+/[^/]+$" "\\1" resolved_embedded_versions "${resolved_embedded_item}") + string(REGEX REPLACE "^.*/([^/]+)/[^/]+/[^/]+$" "\\1" resolved_embedded_versions_basename "${resolved_embedded_item}") + if(resolved_embedded_versions_basename STREQUAL "Versions") + # Ensure Current symlink points to the framework version + if(NOT EXISTS "${resolved_embedded_versions}/Current") + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${resolved_embedded_version}" "${resolved_embedded_versions}/Current") + endif() + # Restore symlinks in framework root pointing to current framework + # binary and resources: + string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1" resolved_embedded_root "${resolved_embedded_item}") + string(REGEX REPLACE "^.*/([^/]+)$" "\\1" resolved_embedded_item_basename "${resolved_embedded_item}") + if(NOT EXISTS "${resolved_embedded_root}/${resolved_embedded_item_basename}") + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/${resolved_embedded_item_basename}" "${resolved_embedded_root}/${resolved_embedded_item_basename}") + endif() + if(NOT EXISTS "${resolved_embedded_root}/Resources") + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "Versions/Current/Resources" "${resolved_embedded_root}/Resources") + endif() + endif() + endif() + if(UNIX AND NOT APPLE) + file(RPATH_REMOVE FILE "${resolved_embedded_item}") + endif() + endif() + +endfunction() + +function(is_resolved_item_embedded resolved_item exepath verbose is_embedded_var) + get_dotapp_dir("${exepath}" exe_dotapp_dir) + string(LENGTH "${exe_dotapp_dir}/" exe_dotapp_dir_length) + string(LENGTH "${resolved_item}" resolved_item_length) + set(path_too_short 0) + set(is_embedded 0) + if(${resolved_item_length} LESS ${exe_dotapp_dir_length}) + set(path_too_short 1) + endif() + if(NOT path_too_short) + string(SUBSTRING "${resolved_item}" 0 ${exe_dotapp_dir_length} item_substring) + if("${exe_dotapp_dir}/" STREQUAL "${item_substring}") + set(is_embedded 1) + endif() + endif() + if(verbose AND NOT is_embedded) + message(" exe_dotapp_dir/='${exe_dotapp_dir}/'") + message(" item_substring='${item_substring}'") + message(" resolved_item='${resolved_item}'") + message("") + endif() + set(${is_embedded_var} ${is_embedded} PARENT_SCOPE) +endfunction() + +function(fixup_bundle_item resolved_embedded_item exepath dirs) + # This item's key is "ikey": + # + get_item_key("${resolved_embedded_item}" ikey) + + # Ensure the item is "inside the .app bundle" -- it should not be fixed up if + # it is not in the .app bundle... Otherwise, we'll modify files in the build + # tree, or in other varied locations around the file system, with our call to + # install_name_tool. Make sure that doesn't happen here: + # + set(verbose 1) + is_resolved_item_embedded("${resolved_embedded_item}" "${exepath}" "${verbose}" is_embedded) + if(NOT is_embedded) + message("Install or copy the item into the bundle before calling fixup_bundle.") + message("Or maybe there's a typo or incorrect path in one of the args to fixup_bundle?") + message("") + message(FATAL_ERROR "cannot fixup an item that is not in the bundle...") + endif() + + set(prereqs "") + get_prerequisites("${resolved_embedded_item}" prereqs 1 0 "${exepath}" "${dirs}") + + set(changes "") + + foreach(pr ${prereqs}) + # Each referenced item's key is "rkey" in the loop: + # + get_item_key("${pr}" rkey) + + if(NOT "${${rkey}_EMBEDDED_ITEM}" STREQUAL "") + set(changes ${changes} "-change" "${pr}" "${${rkey}_EMBEDDED_ITEM}") + else() + message("warning: unexpected reference to '${pr}'") + endif() + endforeach() + + if(BU_CHMOD_BUNDLE_ITEMS) + execute_process(COMMAND chmod u+w "${resolved_embedded_item}") + endif() + + # Change this item's id and all of its references in one call + # to install_name_tool: + # + execute_process(COMMAND install_name_tool + ${changes} -id "${${ikey}_EMBEDDED_ITEM}" "${resolved_embedded_item}" + ) +endfunction() + + +function(fixup_bundle app libs dirs) + message(STATUS "fixup_bundle") + message(STATUS " app='${app}'") + message(STATUS " libs='${libs}'") + message(STATUS " dirs='${dirs}'") + + get_bundle_and_executable("${app}" bundle executable valid) + message(STATUS " bundle='${bundle}'") + message(STATUS " executable='${executable}'") + if(valid) + get_filename_component(exepath "${executable}" PATH) + + # TODO: Extract list of rpath dirs automatically. On MacOSX, the following could be + # done: otool -l path/to/executable | grep -A 3 LC_RPATH | grep path + # See http://www.mikeash.com/pyblog/friday-qa-2009-11-06-linking-and-install-names.html#comment-87ea054b4839586412727dcfc94c79d2 + set(GP_RPATH_DIR ${bundle}/Contents) + message(STATUS " GP_RPATH_DIR='${GP_RPATH_DIR}'") + + message(STATUS "fixup_bundle: preparing...") + get_bundle_keys("${app}" "${libs}" "${dirs}" keys) + + message(STATUS "fixup_bundle: copying...") + list(LENGTH keys n) + math(EXPR n ${n}*2) + + set(i 0) + foreach(key ${keys}) + math(EXPR i ${i}+1) + if(${${key}_COPYFLAG}) + message(STATUS "${i}/${n}: copying '${${key}_RESOLVED_ITEM}'") + else() + message(STATUS "${i}/${n}: *NOT* copying '${${key}_RESOLVED_ITEM}'") + endif() + + set(show_status 0) + if(show_status) + message(STATUS "key='${key}'") + message(STATUS "item='${${key}_ITEM}'") + message(STATUS "resolved_item='${${key}_RESOLVED_ITEM}'") + message(STATUS "default_embedded_path='${${key}_DEFAULT_EMBEDDED_PATH}'") + message(STATUS "embedded_item='${${key}_EMBEDDED_ITEM}'") + message(STATUS "resolved_embedded_item='${${key}_RESOLVED_EMBEDDED_ITEM}'") + message(STATUS "copyflag='${${key}_COPYFLAG}'") + message(STATUS "") + endif() + + if(${${key}_COPYFLAG}) + set(item "${${key}_ITEM}") + if(item MATCHES "[^/]+\\.framework/") + copy_resolved_framework_into_bundle("${${key}_RESOLVED_ITEM}" + "${${key}_RESOLVED_EMBEDDED_ITEM}") + else() + copy_resolved_item_into_bundle("${${key}_RESOLVED_ITEM}" + "${${key}_RESOLVED_EMBEDDED_ITEM}") + endif() + endif() + endforeach() + + message(STATUS "fixup_bundle: fixing...") + foreach(key ${keys}) + math(EXPR i ${i}+1) + if(APPLE) + message(STATUS "${i}/${n}: fixing up '${${key}_RESOLVED_EMBEDDED_ITEM}'") + fixup_bundle_item("${${key}_RESOLVED_EMBEDDED_ITEM}" "${exepath}" "${dirs}") + else() + message(STATUS "${i}/${n}: fix-up not required on this platform '${${key}_RESOLVED_EMBEDDED_ITEM}'") + endif() + endforeach() + + message(STATUS "fixup_bundle: cleaning up...") + clear_bundle_keys(keys) + + message(STATUS "fixup_bundle: verifying...") + verify_app("${app}") + else() + message(SEND_ERROR "error: fixup_bundle: not a valid bundle") + endif() + + message(STATUS "fixup_bundle: done") +endfunction() + + +function(copy_and_fixup_bundle src dst libs dirs) + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${src}" "${dst}") + fixup_bundle("${dst}" "${libs}" "${dirs}") +endfunction() + + +function(verify_bundle_prerequisites bundle result_var info_var) + set(result 1) + set(info "") + set(count 0) + + get_bundle_main_executable("${bundle}" main_bundle_exe) + + file(GLOB_RECURSE file_list "${bundle}/*") + foreach(f ${file_list}) + is_file_executable("${f}" is_executable) + if(is_executable) + get_filename_component(exepath "${f}" PATH) + math(EXPR count "${count} + 1") + + message(STATUS "executable file ${count}: ${f}") + + set(prereqs "") + get_prerequisites("${f}" prereqs 1 1 "${exepath}" "") + + # On the Mac, + # "embedded" and "system" prerequisites are fine... anything else means + # the bundle's prerequisites are not verified (i.e., the bundle is not + # really "standalone") + # + # On Windows (and others? Linux/Unix/...?) + # "local" and "system" prereqs are fine... + # + set(external_prereqs "") + + foreach(p ${prereqs}) + set(p_type "") + gp_file_type("${f}" "${p}" p_type) + + if(APPLE) + if(NOT "${p_type}" STREQUAL "embedded" AND NOT "${p_type}" STREQUAL "system") + set(external_prereqs ${external_prereqs} "${p}") + endif() + else() + if(NOT "${p_type}" STREQUAL "local" AND NOT "${p_type}" STREQUAL "system") + set(external_prereqs ${external_prereqs} "${p}") + endif() + endif() + endforeach() + + if(external_prereqs) + # Found non-system/somehow-unacceptable prerequisites: + set(result 0) + set(info ${info} "external prerequisites found:\nf='${f}'\nexternal_prereqs='${external_prereqs}'\n") + endif() + endif() + endforeach() + + if(result) + set(info "Verified ${count} executable files in '${bundle}'") + endif() + + set(${result_var} "${result}" PARENT_SCOPE) + set(${info_var} "${info}" PARENT_SCOPE) +endfunction() + + +function(verify_bundle_symlinks bundle result_var info_var) + set(result 1) + set(info "") + set(count 0) + + # TODO: implement this function for real... + # Right now, it is just a stub that verifies unconditionally... + + set(${result_var} "${result}" PARENT_SCOPE) + set(${info_var} "${info}" PARENT_SCOPE) +endfunction() + + +function(verify_app app) + set(verified 0) + set(info "") + + get_bundle_and_executable("${app}" bundle executable valid) + + message(STATUS "===========================================================================") + message(STATUS "Analyzing app='${app}'") + message(STATUS "bundle='${bundle}'") + message(STATUS "executable='${executable}'") + message(STATUS "valid='${valid}'") + + # Verify that the bundle does not have any "external" prerequisites: + # + verify_bundle_prerequisites("${bundle}" verified info) + message(STATUS "verified='${verified}'") + message(STATUS "info='${info}'") + message(STATUS "") + + if(verified) + # Verify that the bundle does not have any symlinks to external files: + # + verify_bundle_symlinks("${bundle}" verified info) + message(STATUS "verified='${verified}'") + message(STATUS "info='${info}'") + message(STATUS "") + endif() + + if(NOT verified) + message(FATAL_ERROR "error: verify_app failed") + endif() +endfunction() diff --git a/cmake/COPYING-CMAKE-SCRIPTS b/cmake/COPYING-CMAKE-SCRIPTS index d33c6f33b..21f1dbf7d 100644 --- a/cmake/COPYING-CMAKE-SCRIPTS +++ b/cmake/COPYING-CMAKE-SCRIPTS @@ -25,3 +25,269 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The following files are derived from the Slicer project +(https://github.com/Slicer/Slicer), which in turn derived from CMake project (http://cmake.org) and are covered under the licenses below. + +BundleUtilitiesWithRPath.cmake, GetPrerequisitesWithRPath.cmake + +# Slicer + +For more information, please see: + + http://www.slicer.org + +The 3D Slicer license below is a BSD style license, with extensions +to cover contributions and other issues specific to 3D Slicer. + + +3D Slicer Contribution and Software License Agreement ("Agreement") +Version 1.0 (December 20, 2005) + +This Agreement covers contributions to and downloads from the 3D +Slicer project ("Slicer") maintained by The Brigham and Women's +Hospital, Inc. ("Brigham"). Part A of this Agreement applies to +contributions of software and/or data to Slicer (including making +revisions of or additions to code and/or data already in Slicer). Part +B of this Agreement applies to downloads of software and/or data from +Slicer. Part C of this Agreement applies to all transactions with +Slicer. If you distribute Software (as defined below) downloaded from +Slicer, all of the paragraphs of Part B of this Agreement must be +included with and apply to such Software. + +Your contribution of software and/or data to Slicer (including prior +to the date of the first publication of this Agreement, each a +"Contribution") and/or downloading, copying, modifying, displaying, +distributing or use of any software and/or data from Slicer +(collectively, the "Software") constitutes acceptance of all of the +terms and conditions of this Agreement. If you do not agree to such +terms and conditions, you have no right to contribute your +Contribution, or to download, copy, modify, display, distribute or use +the Software. + +PART A. CONTRIBUTION AGREEMENT - License to Brigham with Right to +Sublicense ("Contribution Agreement"). + +1. As used in this Contribution Agreement, "you" means the individual + contributing the Contribution to Slicer and the institution or + entity which employs or is otherwise affiliated with such + individual in connection with such Contribution. + +2. This Contribution Agreement applies to all Contributions made to + Slicer, including without limitation Contributions made prior to + the date of first publication of this Agreement. If at any time you + make a Contribution to Slicer, you represent that (i) you are + legally authorized and entitled to make such Contribution and to + grant all licenses granted in this Contribution Agreement with + respect to such Contribution; (ii) if your Contribution includes + any patient data, all such data is de-identified in accordance with + U.S. confidentiality and security laws and requirements, including + but not limited to the Health Insurance Portability and + Accountability Act (HIPAA) and its regulations, and your disclosure + of such data for the purposes contemplated by this Agreement is + properly authorized and in compliance with all applicable laws and + regulations; and (iii) you have preserved in the Contribution all + applicable attributions, copyright notices and licenses for any + third party software or data included in the Contribution. + +3. Except for the licenses granted in this Agreement, you reserve all + right, title and interest in your Contribution. + +4. You hereby grant to Brigham, with the right to sublicense, a + perpetual, worldwide, non-exclusive, no charge, royalty-free, + irrevocable license to use, reproduce, make derivative works of, + display and distribute the Contribution. If your Contribution is + protected by patent, you hereby grant to Brigham, with the right to + sublicense, a perpetual, worldwide, non-exclusive, no-charge, + royalty-free, irrevocable license under your interest in patent + rights covering the Contribution, to make, have made, use, sell and + otherwise transfer your Contribution, alone or in combination with + any other code. + +5. You acknowledge and agree that Brigham may incorporate your + Contribution into Slicer and may make Slicer available to members + of the public on an open source basis under terms substantially in + accordance with the Software License set forth in Part B of this + Agreement. You further acknowledge and agree that Brigham shall + have no liability arising in connection with claims resulting from + your breach of any of the terms of this Agreement. + +6. YOU WARRANT THAT TO THE BEST OF YOUR KNOWLEDGE YOUR CONTRIBUTION + DOES NOT CONTAIN ANY CODE THAT REQURES OR PRESCRIBES AN "OPEN + SOURCE LICENSE" FOR DERIVATIVE WORKS (by way of non-limiting + example, the GNU General Public License or other so-called + "reciprocal" license that requires any derived work to be licensed + under the GNU General Public License or other "open source + license"). + +PART B. DOWNLOADING AGREEMENT - License from Brigham with Right to +Sublicense ("Software License"). + +1. As used in this Software License, "you" means the individual + downloading and/or using, reproducing, modifying, displaying and/or + distributing the Software and the institution or entity which + employs or is otherwise affiliated with such individual in + connection therewith. The Brigham and Women?s Hospital, + Inc. ("Brigham") hereby grants you, with right to sublicense, with + respect to Brigham's rights in the software, and data, if any, + which is the subject of this Software License (collectively, the + "Software"), a royalty-free, non-exclusive license to use, + reproduce, make derivative works of, display and distribute the + Software, provided that: + +(a) you accept and adhere to all of the terms and conditions of this +Software License; + +(b) in connection with any copy of or sublicense of all or any portion +of the Software, all of the terms and conditions in this Software +License shall appear in and shall apply to such copy and such +sublicense, including without limitation all source and executable +forms and on any user documentation, prefaced with the following +words: "All or portions of this licensed product (such portions are +the "Software") have been obtained under license from The Brigham and +Women's Hospital, Inc. and are subject to the following terms and +conditions:" + +(c) you preserve and maintain all applicable attributions, copyright +notices and licenses included in or applicable to the Software; + +(d) modified versions of the Software must be clearly identified and +marked as such, and must not be misrepresented as being the original +Software; and + +(e) you consider making, but are under no obligation to make, the +source code of any of your modifications to the Software freely +available to others on an open source basis. + +2. The license granted in this Software License includes without + limitation the right to (i) incorporate the Software into + proprietary programs (subject to any restrictions applicable to + such programs), (ii) add your own copyright statement to your + modifications of the Software, and (iii) provide additional or + different license terms and conditions in your sublicenses of + modifications of the Software; provided that in each case your use, + reproduction or distribution of such modifications otherwise + complies with the conditions stated in this Software License. + +3. This Software License does not grant any rights with respect to + third party software, except those rights that Brigham has been + authorized by a third party to grant to you, and accordingly you + are solely responsible for (i) obtaining any permissions from third + parties that you need to use, reproduce, make derivative works of, + display and distribute the Software, and (ii) informing your + sublicensees, including without limitation your end-users, of their + obligations to secure any such required permissions. + +4. The Software has been designed for research purposes only and has + not been reviewed or approved by the Food and Drug Administration + or by any other agency. YOU ACKNOWLEDGE AND AGREE THAT CLINICAL + APPLICATIONS ARE NEITHER RECOMMENDED NOR ADVISED. Any + commercialization of the Software is at the sole risk of the party + or parties engaged in such commercialization. You further agree to + use, reproduce, make derivative works of, display and distribute + the Software in compliance with all applicable governmental laws, + regulations and orders, including without limitation those relating + to export and import control. + +5. The Software is provided "AS IS" and neither Brigham nor any + contributor to the software (each a "Contributor") shall have any + obligation to provide maintenance, support, updates, enhancements + or modifications thereto. BRIGHAM AND ALL CONTRIBUTORS SPECIFICALLY + DISCLAIM ALL EXPRESS AND IMPLIED WARRANTIES OF ANY KIND INCLUDING, + BUT NOT LIMITED TO, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR + A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + BRIGHAM OR ANY CONTRIBUTOR BE LIABLE TO ANY PARTY FOR DIRECT, + INDIRECT, SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ARISING IN ANY WAY + RELATED TO THE SOFTWARE, EVEN IF BRIGHAM OR ANY CONTRIBUTOR HAS + BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. TO THE MAXIMUM + EXTENT NOT PROHIBITED BY LAW OR REGULATION, YOU FURTHER ASSUME ALL + LIABILITY FOR YOUR USE, REPRODUCTION, MAKING OF DERIVATIVE WORKS, + DISPLAY, LICENSE OR DISTRIBUTION OF THE SOFTWARE AND AGREE TO + INDEMNIFY AND HOLD HARMLESS BRIGHAM AND ALL CONTRIBUTORS FROM AND + AGAINST ANY AND ALL CLAIMS, SUITS, ACTIONS, DEMANDS AND JUDGMENTS + ARISING THEREFROM. + +6. None of the names, logos or trademarks of Brigham or any of + Brigham's affiliates or any of the Contributors, or any funding + agency, may be used to endorse or promote products produced in + whole or in part by operation of the Software or derived from or + based on the Software without specific prior written permission + from the applicable party. + +7. Any use, reproduction or distribution of the Software which is not + in accordance with this Software License shall automatically revoke + all rights granted to you under this Software License and render + Paragraphs 1 and 2 of this Software License null and void. + +8. This Software License does not grant any rights in or to any + intellectual property owned by Brigham or any Contributor except + those rights expressly granted hereunder. + +PART C. MISCELLANEOUS + +This Agreement shall be governed by and construed in accordance with +the laws of The Commonwealth of Massachusetts without regard to +principles of conflicts of law. This Agreement shall supercede and +replace any license terms that you may have agreed to previously with +respect to Slicer. + +# CMake + +CMake - Cross Platform Makefile Generator +Copyright 2000-2015 Kitware, Inc. +Copyright 2000-2011 Insight Software Consortium +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the names of Kitware, Inc., the Insight Software Consortium, + nor the names of their contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------ + +The above copyright and license notice applies to distributions of +CMake in source and binary form. Some source files contain additional +notices of original copyright by their contributors; see each source +for details. Third-party software packages supplied with CMake under +compatible licenses provide their own copyright notices documented in +corresponding subdirectories. + +------------------------------------------------------------------------------ + +CMake was initially developed by Kitware with the following sponsorship: + + * National Library of Medicine at the National Institutes of Health + as part of the Insight Segmentation and Registration Toolkit (ITK). + + * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel + Visualization Initiative. + + * National Alliance for Medical Image Computing (NAMIC) is funded by the + National Institutes of Health through the NIH Roadmap for Medical Research, + Grant U54 EB005149. + + * Kitware, Inc. diff --git a/cmake/GetPrerequisitesWithRPath.cmake b/cmake/GetPrerequisitesWithRPath.cmake new file mode 100644 index 000000000..b57295b3d --- /dev/null +++ b/cmake/GetPrerequisitesWithRPath.cmake @@ -0,0 +1,990 @@ +# - Functions to analyze and list executable file prerequisites. +# This module provides functions to list the .dll, .dylib or .so +# files that an executable or shared library file depends on. (Its +# prerequisites.) +# +# It uses various tools to obtain the list of required shared library files: +# dumpbin (Windows) +# objdump (MinGW on Windows) +# ldd (Linux/Unix) +# otool (Mac OSX) +# The following functions are provided by this module: +# get_prerequisites +# list_prerequisites +# list_prerequisites_by_glob +# gp_append_unique +# is_file_executable +# gp_item_default_embedded_path +# (projects can override with gp_item_default_embedded_path_override) +# gp_resolve_item +# (projects can override with gp_resolve_item_override) +# gp_resolve_embedded_item +# (projects can override with gp_resolve_embedded_item_override) +# gp_resolved_file_type +# (projects can override with gp_resolved_file_type_override) +# gp_file_type +# Requires CMake 2.6 or greater because it uses function, break, return and +# PARENT_SCOPE. +# +# GET_PREREQUISITES( +# ) +# Get the list of shared library files required by . The list in +# the variable named should be empty on first entry to +# this function. On exit, will contain the list of +# required shared library files. +# +# is the full path to an executable file. is the +# name of a CMake variable to contain the results. must be 0 +# or 1 indicating whether to include or exclude "system" prerequisites. If +# is set to 1 all prerequisites will be found recursively, if set to +# 0 only direct prerequisites are listed. is the path to the top +# level executable used for @executable_path replacment on the Mac. is +# a list of paths where libraries might be found: these paths are searched +# first when a target without any path info is given. Then standard system +# locations are also searched: PATH, Framework locations, /usr/lib... +# +# LIST_PREREQUISITES( [ [ []]]) +# Print a message listing the prerequisites of . +# +# is the name of a shared library or executable target or the full +# path to a shared library or executable file. If is set to 1 all +# prerequisites will be found recursively, if set to 0 only direct +# prerequisites are listed. must be 0 or 1 indicating whether +# to include or exclude "system" prerequisites. With set to 0 only +# the full path names of the prerequisites are printed, set to 1 extra +# informatin will be displayed. +# +# LIST_PREREQUISITES_BY_GLOB( ) +# Print the prerequisites of shared library and executable files matching a +# globbing pattern. is GLOB or GLOB_RECURSE and is a +# globbing expression used with "file(GLOB" or "file(GLOB_RECURSE" to retrieve +# a list of matching files. If a matching file is executable, its prerequisites +# are listed. +# +# Any additional (optional) arguments provided are passed along as the +# optional arguments to the list_prerequisites calls. +# +# GP_APPEND_UNIQUE( ) +# Append to the list variable only if the value is not +# already in the list. +# +# IS_FILE_EXECUTABLE( ) +# Return 1 in if is a binary executable, 0 otherwise. +# +# GP_IS_FILE_EXECUTABLE_EXCLUDE_REGEX can be set to a regular expression used +# to give a hint to identify more quickly if a given file is an executable or not. +# This is particularly useful on unix platform where it can avoid a lot of +# time-consuming call to "file" external process. For packages bundling hundreds +# of libraries, executables, resources and data, it largely speeds up the function +# "get_bundle_all_executables". +# On unix, a convenient command line allowing to collect recursively all file extensions +# useful to generate a regular expression like "\\.(dylib|py|pyc|so)$" is: +# find . -type f -name '*.*' | sed 's@.*/.*\.@@' | sort | uniq | tr "\\n" "|" +# +# GP_ITEM_DEFAULT_EMBEDDED_PATH( ) +# Return the path that others should refer to the item by when the item +# is embedded inside a bundle. +# +# Override on a per-project basis by providing a project-specific +# gp_item_default_embedded_path_override function. +# +# GP_RESOLVE_ITEM( ) +# Resolve an item into an existing full path file. +# +# Override on a per-project basis by providing a project-specific +# gp_resolve_item_override function. +# +# GP_RESOLVE_EMBEDDED_ITEM( ) +# Resolve an embedded item into the full path within the full path. Since the item can be +# copied later, it doesn't have to exist when calling this function. +# +# Override on a per-project basis by providing a project-specific +# gp_resolve_embedded_item_override function. +# +# If GP_RPATH_DIR variable is set then item matching '@rpath' are +# resolved using the provided directory. Currently setting this variable +# has an effect only on MacOSX when fixing up application bundle. The directory +# are also assumed to be located within the application bundle. It is +# usually the directory passed to the 'rpath' linker option. +# +# GP_RESOLVED_FILE_TYPE( ) +# Return the type of with respect to . String +# describing type of prerequisite is returned in variable named . +# +# Use and if necessary to resolve non-absolute +# values -- but only for non-embedded items. +# +# Possible types are: +# system +# local +# embedded +# other +# Override on a per-project basis by providing a project-specific +# gp_resolved_file_type_override function. +# +# GP_FILE_TYPE( ) +# Return the type of with respect to . String +# describing type of prerequisite is returned in variable named . +# +# Possible types are: +# system +# local +# embedded +# other + +#============================================================================= +# Copyright 2008-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# Copyright (c) 2015 BWH and 3D Slicer contributors, http://slicer.org +# +# Redistribution AND use is allowed according to the terms of the +# BSD-style license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +function(gp_append_unique list_var value) + set(contains 0) + + foreach(item ${${list_var}}) + if("${item}" STREQUAL "${value}") + set(contains 1) + break() + endif() + endforeach() + + if(NOT contains) + set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE) + endif() +endfunction() + + +function(is_file_executable file result_var) + # + # A file is not executable until proven otherwise: + # + set(${result_var} 0 PARENT_SCOPE) + + get_filename_component(file_full "${file}" ABSOLUTE) + string(TOLOWER "${file_full}" file_full_lower) + + # If file name ends in .exe on Windows, *assume* executable: + # + if(WIN32 AND NOT UNIX) + if("${file_full_lower}" MATCHES "\\.exe$") + set(${result_var} 1 PARENT_SCOPE) + return() + endif() + + # A clause could be added here that uses output or return value of dumpbin + # to determine ${result_var}. In 99%+? practical cases, the exe name + # match will be sufficient... + # + endif() + + # Use the information returned from the Unix shell command "file" to + # determine if ${file_full} should be considered an executable file... + # + # If the file command's output contains "executable" and does *not* contain + # "text" then it is likely an executable suitable for prerequisite analysis + # via the get_prerequisites macro. + # + if(UNIX) + + if(NOT "${GP_IS_FILE_EXECUTABLE_EXCLUDE_REGEX}" STREQUAL "") + if(${file_full} MATCHES "${GP_IS_FILE_EXECUTABLE_EXCLUDE_REGEX}") + set(${result_var} 0 PARENT_SCOPE) + return() + endif() + endif() + + if(NOT file_cmd) + find_program(file_cmd "file") + mark_as_advanced(file_cmd) + endif() + + if(file_cmd) + execute_process(COMMAND "${file_cmd}" "${file_full}" + OUTPUT_VARIABLE file_ov + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + # Replace the name of the file in the output with a placeholder token + # (the string " _file_full_ ") so that just in case the path name of + # the file contains the word "text" or "executable" we are not fooled + # into thinking "the wrong thing" because the file name matches the + # other 'file' command output we are looking for... + # + string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}") + string(TOLOWER "${file_ov}" file_ov) + + #message(STATUS "file_ov='${file_ov}'") + if("${file_ov}" MATCHES "executable") + #message(STATUS "executable!") + if("${file_ov}" MATCHES "text") + #message(STATUS "but text, so *not* a binary executable!") + else() + set(${result_var} 1 PARENT_SCOPE) + return() + endif() + endif() + + # Also detect position independent executables on Linux, + # where "file" gives "shared object ... (uses shared libraries)" + if("${file_ov}" MATCHES "shared object.*\(uses shared libs\)") + set(${result_var} 1 PARENT_SCOPE) + return() + endif() + + else() + message(STATUS "warning: No 'file' command, skipping execute_process...") + endif() + endif() +endfunction() + + +function(gp_item_default_embedded_path item default_embedded_path_var) + + # On Windows and Linux, "embed" prerequisites in the same directory + # as the executable by default: + # + set(path "@executable_path") + set(overridden 0) + + # On the Mac, relative to the executable depending on the type + # of the thing we are embedding: + # + if(APPLE) + # + # The assumption here is that all executables in the bundle will be + # in same-level-directories inside the bundle. The parent directory + # of an executable inside the bundle should be MacOS or a sibling of + # MacOS and all embedded paths returned from here will begin with + # "@executable_path/../" and will work from all executables in all + # such same-level-directories inside the bundle. + # + + # By default, embed things right next to the main bundle executable: + # + set(path "@executable_path/../../Contents/MacOS") + + # Embed .dylibs right next to the main bundle executable: + # + if(item MATCHES "\\.dylib$") + set(path "@executable_path/../MacOS") + set(overridden 1) + endif() + + # Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS): + # + if(NOT overridden) + if(item MATCHES "[^/]+\\.framework/") + set(path "@executable_path/../Frameworks") + set(overridden 1) + endif() + endif() + endif() + + # Provide a hook so that projects can override the default embedded location + # of any given library by whatever logic they choose: + # + if(COMMAND gp_item_default_embedded_path_override) + gp_item_default_embedded_path_override("${item}" path) + endif() + + set(${default_embedded_path_var} "${path}" PARENT_SCOPE) +endfunction() + + +function(gp_resolve_item context item exepath dirs resolved_item_var) + set(resolved 0) + set(resolved_item "${item}") + + # Is it already resolved? + # + if(IS_ABSOLUTE "${resolved_item}" AND EXISTS "${resolved_item}") + set(resolved 1) + endif() + + if(NOT resolved) + if(item MATCHES "@executable_path") + # + # @executable_path references are assumed relative to exepath + # + string(REPLACE "@executable_path" "${exepath}" ri "${item}") + get_filename_component(ri "${ri}" ABSOLUTE) + + if(EXISTS "${ri}") + #message(STATUS "info: embedded item exists (${ri})") + set(resolved 1) + set(resolved_item "${ri}") + else() + message(STATUS "warning: embedded item does not exist '${ri}'") + endif() + endif() + endif() + + if(NOT resolved) + if(item MATCHES "@loader_path") + # + # @loader_path references are assumed relative to the + # PATH of the given "context" (presumably another library) + # + get_filename_component(contextpath "${context}" PATH) + string(REPLACE "@loader_path" "${contextpath}" ri "${item}") + get_filename_component(ri "${ri}" ABSOLUTE) + + if(EXISTS "${ri}") + #message(STATUS "info: embedded item exists (${ri})") + set(resolved 1) + set(resolved_item "${ri}") + else() + message(STATUS "warning: embedded item does not exist '${ri}'") + endif() + endif() + endif() + + if(NOT resolved) + if(item MATCHES "@rpath") + # + # @rpath references are relative to the paths built into the binaries with -rpath + # We handle this case like we do for other Unixes. + # + # Two cases of item resolution are considered: + # + # (1) item has been copied into the bundle + # + # (2) item has NOT been copied into the bundle: Since the item can exist in a build or + # install tree outside of the bundle, the item is resolved using its name and the + # passed list of directories. + # + string(REPLACE "@rpath/" "" norpath_item "${item}") + + set(ri "ri-NOTFOUND") + if(EXISTS ${GP_RPATH_DIR}/${norpath_item}) + set(ri ${GP_RPATH_DIR}/${norpath_item}) + set(_msg "'find_file' in GP_RPATH_DIR (${ri})") + else() + get_filename_component(norpath_item_name ${norpath_item} NAME) + find_file(ri "${norpath_item_name}" ${exepath} ${dirs} NO_DEFAULT_PATH) + set(_msg "'find_file' in exepath/dirs (${ri})") + endif() + if(ri) + #message(STATUS "info: ${_msg}") + set(resolved 1) + set(resolved_item "${ri}") + set(ri "ri-NOTFOUND") + endif() + + endif() + endif() + + if(NOT resolved) + set(ri "ri-NOTFOUND") + find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH) + find_file(ri "${item}" ${exepath} ${dirs} /usr/lib) + if(ri) + #message(STATUS "info: 'find_file' in exepath/dirs (${ri})") + set(resolved 1) + set(resolved_item "${ri}") + set(ri "ri-NOTFOUND") + endif() + endif() + + if(NOT resolved) + if(item MATCHES "[^/]+\\.framework/") + set(fw "fw-NOTFOUND") + find_file(fw "${item}" + "~/Library/Frameworks" + "/Library/Frameworks" + "/System/Library/Frameworks" + ) + if(fw) + #message(STATUS "info: 'find_file' found framework (${fw})") + set(resolved 1) + set(resolved_item "${fw}") + set(fw "fw-NOTFOUND") + endif() + endif() + endif() + + # Using find_program on Windows will find dll files that are in the PATH. + # (Converting simple file names into full path names if found.) + # + if(WIN32 AND NOT UNIX) + if(NOT resolved) + set(ri "ri-NOTFOUND") + find_program(ri "${item}" PATHS "${exepath};${dirs}" NO_DEFAULT_PATH) + find_program(ri "${item}" PATHS "${exepath};${dirs}") + if(ri) + #message(STATUS "info: 'find_program' in exepath/dirs (${ri})") + set(resolved 1) + set(resolved_item "${ri}") + set(ri "ri-NOTFOUND") + endif() + endif() + endif() + + # Provide a hook so that projects can override item resolution + # by whatever logic they choose: + # + if(COMMAND gp_resolve_item_override) + gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved) + endif() + + if(NOT resolved) + message(STATUS " +warning: cannot resolve item '${item}' + + possible problems: + need more directories? + need to use InstallRequiredSystemLibraries? + run in install tree instead of build tree? +") +# message(STATUS " +#****************************************************************************** +#warning: cannot resolve item '${item}' +# +# possible problems: +# need more directories? +# need to use InstallRequiredSystemLibraries? +# run in install tree instead of build tree? +# +# context='${context}' +# item='${item}' +# exepath='${exepath}' +# dirs='${dirs}' +# resolved_item_var='${resolved_item_var}' +#****************************************************************************** +#") + endif() + + set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE) +endfunction() + +function(gp_resolve_embedded_item context embedded_item exepath resolved_embedded_item_var) + #message(STATUS "**") + set(resolved 0) + set(resolved_embedded_item "${embedded_item}") + + if(embedded_item MATCHES "@executable_path") + string(REPLACE "@executable_path" "${exepath}" resolved_embedded_item "${embedded_item}") + set(resolved 1) + endif() + if(EXISTS "${GP_RPATH_DIR}" AND embedded_item MATCHES "@rpath") + string(REPLACE "@rpath" "${GP_RPATH_DIR}" resolved_embedded_item "${embedded_item}") + set(resolved 1) + endif() + + # Provide a hook so that projects can override embedded item resolution + # by whatever logic they choose: + # + if(COMMAND gp_resolve_embedded_item_override) + gp_resolve_embedded_item_override( + "${context}" "${embedded_item}" "${exepath}" resolved_embedded_item resolved) + endif() + + if(NOT resolved) + message(STATUS " +warning: cannot resolve embedded item '${embedded_item}' + possible problems: + need more directories? + need to use InstallRequiredSystemLibraries? + run in install tree instead of build tree? + + context='${context}' + embedded_item='${embedded_item}' + GP_RPATH_DIR='${GP_RPATH_DIR}' + exepath='${exepath}' + resolved_embedded_item_var='${resolved_embedded_item_var}' +") + endif() + + set(${resolved_embedded_item_var} "${resolved_embedded_item}" PARENT_SCOPE) +endfunction() + +function(gp_resolved_file_type original_file file exepath dirs type_var) + #message(STATUS "**") + + if(NOT IS_ABSOLUTE "${original_file}") + message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file") + endif() + + set(is_embedded 0) + set(is_local 0) + set(is_system 0) + + set(resolved_file "${file}") + + if("${file}" MATCHES "^@(executable_|loader_|r)path") + set(is_embedded 1) + endif() + + if(NOT is_embedded) + if(NOT IS_ABSOLUTE "${file}") + gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file) + endif() + + string(TOLOWER "${original_file}" original_lower) + string(TOLOWER "${resolved_file}" lower) + + if(UNIX) + if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11/|/usr/X11R6/|/usr/bin/|/usr/.*/lib/)") + set(is_system 1) + endif() + endif() + + if(APPLE) + if(resolved_file MATCHES "^(/System/Library/|/usr/lib/|/opt/X11/)") + set(is_system 1) + endif() + endif() + + if(WIN32) + string(TOLOWER "$ENV{SystemRoot}" sysroot) + string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}") + + string(TOLOWER "$ENV{windir}" windir) + string(REGEX REPLACE "\\\\" "/" windir "${windir}") + + if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)") + set(is_system 1) + endif() + + if(UNIX) + # if cygwin, we can get the properly formed windows paths from cygpath + find_program(CYGPATH_EXECUTABLE cygpath) + + if(CYGPATH_EXECUTABLE) + execute_process(COMMAND ${CYGPATH_EXECUTABLE} -W + OUTPUT_VARIABLE env_windir + OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${CYGPATH_EXECUTABLE} -S + OUTPUT_VARIABLE env_sysdir + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(TOLOWER "${env_windir}" windir) + string(TOLOWER "${env_sysdir}" sysroot) + + if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)") + set(is_system 1) + endif() + endif() + endif() + endif() + + if(NOT is_system) + get_filename_component(original_path "${original_lower}" PATH) + get_filename_component(path "${lower}" PATH) + if("${original_path}" STREQUAL "${path}") + set(is_local 1) + else() + string(LENGTH "${original_path}/" original_length) + string(LENGTH "${lower}" path_length) + if(${path_length} GREATER ${original_length}) + string(SUBSTRING "${lower}" 0 ${original_length} path) + if("${original_path}/" STREQUAL "${path}") + set(is_embedded 1) + endif() + endif() + endif() + endif() + endif() + + # Return type string based on computed booleans: + # + set(type "other") + + if(is_system) + set(type "system") + elseif(is_embedded) + set(type "embedded") + elseif(is_local) + set(type "local") + endif() + + #message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'") + #message(STATUS " type: '${type}'") + + if(NOT is_embedded) + if(NOT IS_ABSOLUTE "${resolved_file}") + if(lower MATCHES "^msvc[^/]+dll" AND is_system) + message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'") + else() + message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect") + endif() + endif() + endif() + + # Provide a hook so that projects can override the decision on whether a + # library belongs to the system or not by whatever logic they choose: + # + if(COMMAND gp_resolved_file_type_override) + gp_resolved_file_type_override("${resolved_file}" type) + endif() + + set(${type_var} "${type}" PARENT_SCOPE) + + #message(STATUS "**") +endfunction() + + +function(gp_file_type original_file file type_var) + if(NOT IS_ABSOLUTE "${original_file}") + message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file") + endif() + + get_filename_component(exepath "${original_file}" PATH) + + set(type "") + gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type) + + set(${type_var} "${type}" PARENT_SCOPE) +endfunction() + + +function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs) + set(verbose 0) + set(eol_char "E") + + if(NOT IS_ABSOLUTE "${target}") + message("warning: target '${target}' is not absolute...") + endif() + + if(NOT EXISTS "${target}") + message("warning: target '${target}' does not exist...") + endif() + + set(gp_cmd_paths ${gp_cmd_paths} + "C:/Program Files/Microsoft Visual Studio 9.0/VC/bin" + "C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin" + "C:/Program Files/Microsoft Visual Studio 8/VC/BIN" + "C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN" + "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN" + "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN" + "/usr/local/bin" + "/usr/bin" + ) + + # + # + # Try to choose the right tool by default. Caller can set gp_tool prior to + # calling this function to force using a different tool. + # + if("${gp_tool}" STREQUAL "") + set(gp_tool "ldd") + + if(APPLE) + set(gp_tool "otool") + endif() + + if(WIN32 AND NOT UNIX) # This is how to check for cygwin, har! + find_program(gp_dumpbin "dumpbin" PATHS ${gp_cmd_paths}) + if(gp_dumpbin) + set(gp_tool "dumpbin") + else() # Try harder. Maybe we're on MinGW + set(gp_tool "objdump") + endif() + endif() + endif() + + find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths}) + + if(NOT gp_cmd) + message(STATUS "warning: could not find '${gp_tool}' - cannot analyze prerequisites...") + return() + endif() + + set(gp_tool_known 0) + + if("${gp_tool}" STREQUAL "ldd") + set(gp_cmd_args "") + set(gp_regex "^[\t ]*[^\t ]+ => ([^\t\(]+) .*${eol_char}$") + set(gp_regex_error "not found${eol_char}$") + set(gp_regex_fallback "^[\t ]*([^\t ]+) => ([^\t ]+).*${eol_char}$") + set(gp_regex_cmp_count 1) + set(gp_tool_known 1) + endif() + + if("${gp_tool}" STREQUAL "otool") + set(gp_cmd_args "-L") + set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$") + set(gp_regex_error "") + set(gp_regex_fallback "") + set(gp_regex_cmp_count 3) + set(gp_tool_known 1) + endif() + + if("${gp_tool}" STREQUAL "dumpbin") + set(gp_cmd_args "/dependents") + set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$") + set(gp_regex_error "") + set(gp_regex_fallback "") + set(gp_regex_cmp_count 1) + set(gp_tool_known 1) + set(ENV{VS_UNICODE_OUTPUT} "") # Block extra output from inside VS IDE. + endif() + + if("${gp_tool}" STREQUAL "objdump") + set(gp_cmd_args "-p") + set(gp_regex "^\t*DLL Name: (.*\\.[Dd][Ll][Ll])${eol_char}$") + set(gp_regex_error "") + set(gp_regex_fallback "") + set(gp_regex_cmp_count 1) + set(gp_tool_known 1) + endif() + + if(NOT gp_tool_known) + message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...") + message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'") + message(STATUS "Valid gp_tool values are dumpbin, ldd, objdump and otool.") + return() + endif() + + + if("${gp_tool}" STREQUAL "dumpbin") + # When running dumpbin, it also needs the "Common7/IDE" directory in the + # PATH. It will already be in the PATH if being run from a Visual Studio + # command prompt. Add it to the PATH here in case we are running from a + # different command prompt. + # + get_filename_component(gp_cmd_dir "${gp_cmd}" PATH) + get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE) + # Use cmake paths as a user may have a PATH element ending with a backslash. + # This will escape the list delimiter and create havoc! + if(EXISTS "${gp_cmd_dlls_dir}") + # only add to the path if it is not already in the path + set(gp_found_cmd_dlls_dir 0) + file(TO_CMAKE_PATH "$ENV{PATH}" env_path) + foreach(gp_env_path_element ${env_path}) + if("${gp_env_path_element}" STREQUAL "${gp_cmd_dlls_dir}") + set(gp_found_cmd_dlls_dir 1) + endif() + endforeach() + + if(NOT gp_found_cmd_dlls_dir) + file(TO_NATIVE_PATH "${gp_cmd_dlls_dir}" gp_cmd_dlls_dir) + set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}") + endif() + endif() + endif() + # + # + + if("${gp_tool}" STREQUAL "ldd") + set(old_ld_env "$ENV{LD_LIBRARY_PATH}") + foreach(dir ${exepath} ${dirs}) + set(ENV{LD_LIBRARY_PATH} "${dir}:$ENV{LD_LIBRARY_PATH}") + endforeach() + endif() + + + # Track new prerequisites at each new level of recursion. Start with an + # empty list at each level: + # + set(unseen_prereqs) + + # Run gp_cmd on the target: + # + execute_process( + COMMAND ${gp_cmd} ${gp_cmd_args} ${target} + OUTPUT_VARIABLE gp_cmd_ov + ) + + if("${gp_tool}" STREQUAL "ldd") + set(ENV{LD_LIBRARY_PATH} "${old_ld_env}") + endif() + + if(verbose) + message(STATUS "") + message(STATUS "gp_cmd_ov='${gp_cmd_ov}'") + message(STATUS "") + endif() + + get_filename_component(target_dir "${target}" PATH) + + # Convert to a list of lines: + # + string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}") + string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}") + + # check for install id and remove it from list, since otool -L can include a + # reference to itself + set(gp_install_id) + if("${gp_tool}" STREQUAL "otool") + execute_process( + COMMAND otool -D ${target} + OUTPUT_VARIABLE gp_install_id_ov + ) + # second line is install name + string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}") + if(gp_install_id) + # trim + string(REGEX MATCH "[^\n ].*[^\n ]" gp_install_id "${gp_install_id}") + #message("INSTALL ID is \"${gp_install_id}\"") + endif() + endif() + + # Analyze each line for file names that match the regular expression: + # + foreach(candidate ${candidates}) + if("${candidate}" MATCHES "${gp_regex}") + + # Extract information from each candidate: + if(gp_regex_error AND "${candidate}" MATCHES "${gp_regex_error}") + string(REGEX REPLACE "${gp_regex_fallback}" "\\1" raw_item "${candidate}") + else() + string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}") + endif() + + if(gp_regex_cmp_count GREATER 1) + string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}") + endif() + + if(gp_regex_cmp_count GREATER 2) + string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}") + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}") + endif() + + # Use the raw_item as the list entries returned by this function. Use the + # gp_resolve_item function to resolve it to an actual full path file if + # necessary. + # + set(item "${raw_item}") + + # Add each item unless it is excluded: + # + set(add_item 1) + + if("${item}" STREQUAL "${gp_install_id}") + set(add_item 0) + endif() + + if(add_item AND ${exclude_system}) + set(type "") + gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type) + + if("${type}" STREQUAL "system") + set(add_item 0) + endif() + endif() + + if(add_item) + list(LENGTH ${prerequisites_var} list_length_before_append) + gp_append_unique(${prerequisites_var} "${item}") + list(LENGTH ${prerequisites_var} list_length_after_append) + + if(${recurse}) + # If item was really added, this is the first time we have seen it. + # Add it to unseen_prereqs so that we can recursively add *its* + # prerequisites... + # + # But first: resolve its name to an absolute full path name such + # that the analysis tools can simply accept it as input. + # + if(NOT list_length_before_append EQUAL list_length_after_append) + gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item) + set(unseen_prereqs ${unseen_prereqs} "${resolved_item}") + endif() + endif() + endif() + else() + if(verbose) + message(STATUS "ignoring non-matching line: '${candidate}'") + endif() + endif() + endforeach() + + list(LENGTH ${prerequisites_var} prerequisites_var_length) + if(prerequisites_var_length GREATER 0) + list(SORT ${prerequisites_var}) + endif() + if(${recurse}) + set(more_inputs ${unseen_prereqs}) + foreach(input ${more_inputs}) + get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}") + endforeach() + endif() + + set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE) +endfunction() + + +function(list_prerequisites target) + if("${ARGV1}" STREQUAL "") + set(all 1) + else() + set(all "${ARGV1}") + endif() + + if("${ARGV2}" STREQUAL "") + set(exclude_system 0) + else() + set(exclude_system "${ARGV2}") + endif() + + if("${ARGV3}" STREQUAL "") + set(verbose 0) + else() + set(verbose "${ARGV3}") + endif() + + set(count 0) + set(count_str "") + set(print_count "${verbose}") + set(print_prerequisite_type "${verbose}") + set(print_target "${verbose}") + set(type_str "") + + get_filename_component(exepath "${target}" PATH) + + set(prereqs "") + get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "") + + if(print_target) + message(STATUS "File '${target}' depends on:") + endif() + + foreach(d ${prereqs}) + math(EXPR count "${count} + 1") + + if(print_count) + set(count_str "${count}. ") + endif() + + if(print_prerequisite_type) + gp_file_type("${target}" "${d}" type) + set(type_str " (${type})") + endif() + + message(STATUS "${count_str}${d}${type_str}") + endforeach() +endfunction() + + +function(list_prerequisites_by_glob glob_arg glob_exp) + message(STATUS "=============================================================================") + message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'") + message(STATUS "") + file(${glob_arg} file_list ${glob_exp}) + foreach(f ${file_list}) + is_file_executable("${f}" is_f_executable) + if(is_f_executable) + message(STATUS "=============================================================================") + list_prerequisites("${f}" ${ARGN}) + message(STATUS "") + endif() + endforeach() +endfunction() From c868010c20f1aa01b1a5fe66375340e4b12a9ada Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Mon, 3 Aug 2015 19:21:02 +0200 Subject: [PATCH 237/419] OS X: don't consider libs from `/usr/local` as "system dependencies" during packaging Otherwise they won't be moved into final application bundle. --- cmake/GetPrerequisitesWithRPath.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/GetPrerequisitesWithRPath.cmake b/cmake/GetPrerequisitesWithRPath.cmake index b57295b3d..5b5751ead 100644 --- a/cmake/GetPrerequisitesWithRPath.cmake +++ b/cmake/GetPrerequisitesWithRPath.cmake @@ -537,7 +537,7 @@ function(gp_resolved_file_type original_file file exepath dirs type_var) string(TOLOWER "${resolved_file}" lower) if(UNIX) - if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11/|/usr/X11R6/|/usr/bin/|/usr/.*/lib/)") + if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11/|/usr/X11R6/|/usr/bin/)") set(is_system 1) endif() endif() From 2ded28f6aaf8da8ab6d069f3125e4eb53fdd58a9 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Mon, 3 Aug 2015 19:21:35 +0200 Subject: [PATCH 238/419] OS X: reintroduce packaging code It's much simpler now thanks to bundle utilities with @rpath support. --- CMakeLists.txt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a14beb423..f7c458da5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -736,13 +736,18 @@ if (APPLE) install(CODE " set(BU_CHMOD_BUNDLE_ITEMS ON) - include(BundleUtilities) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) + include(BundleUtilitiesWithRPath) " COMPONENT Runtime) - #For now, search unresolved dependencies only in default system paths, so if you put unresolveable (i.e. with @executable_path in id name) lib or framework somewhere else, it would fail - set(DIRS "") + set(DIRS "${CMAKE_PREFIX_PATH}/lib") - include(CPack) + install(CODE " + cmake_policy(SET CMP0009 OLD) + fixup_bundle(\"${OPENMW_APP}\" \"\" \"${DIRS}\") + fixup_bundle(\"${OPENCS_APP}\" \"\" \"${DIRS}\") + " COMPONENT Runtime) + include(CPack) endif (APPLE) # Doxygen Target -- simply run 'make doc' or 'make doc_pages' From 34d601360f5daad9bfc67afe67ff1ca9ec5ae34c Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sat, 8 Aug 2015 17:19:26 +0200 Subject: [PATCH 239/419] OS X: setup OSG plugins packaging --- CMakeLists.txt | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f7c458da5..9e966cf6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -306,6 +306,11 @@ add_subdirectory(files/) if (APPLE) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS") + + if (OPENMW_OSX_DEPLOYMENT) + SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) + SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE) + endif() else (APPLE) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}") @@ -740,12 +745,59 @@ if (APPLE) include(BundleUtilitiesWithRPath) " COMPONENT Runtime) + set(ABSOLUTE_PLUGINS "") + set(USED_OSG_PLUGINS + osgdb_tga + osgdb_dds + osgdb_imageio + ) + + foreach (PLUGIN_NAME ${USED_OSG_PLUGINS}) + set(PLUGIN_ABS "${OSG_PLUGIN_LIB_SEARCH_PATH}/${PLUGIN_NAME}.so") + set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS}) + endforeach () + + get_filename_component(PLUGIN_PREFIX_DIR "${OSG_PLUGIN_LIB_SEARCH_PATH}" NAME) + + # installs used plugins in bundle at given path (bundle_path must be relative to ${CMAKE_INSTALL_PREFIX}) + # and returns list of install paths for all installed plugins + function (install_plugins_for_bundle bundle_path plugins_var) + set(RELATIVE_PLUGIN_INSTALL_BASE "${bundle_path}/Contents/PlugIns/${PLUGIN_PREFIX_DIR}") + + set(PLUGINS "") + set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${RELATIVE_PLUGIN_INSTALL_BASE}") + + foreach (PLUGIN ${ABSOLUTE_PLUGINS}) + get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME) + get_filename_component(PLUGIN_RELATIVE_WE ${PLUGIN} NAME_WE) + + set(PLUGIN_DYLIB_IN_BUNDLE "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}") + set(PLUGINS ${PLUGINS} "${PLUGIN_DYLIB_IN_BUNDLE}") + + install(CODE " + copy_resolved_item_into_bundle(\"${PLUGIN}\" \"${PLUGIN_DYLIB_IN_BUNDLE}\") + " COMPONENT Runtime) + endforeach () + + set(${plugins_var} ${PLUGINS} PARENT_SCOPE) + endfunction (install_plugins_for_bundle) + + install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS) + install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS) + set(DIRS "${CMAKE_PREFIX_PATH}/lib") install(CODE " + function(gp_item_default_embedded_path_override item default_embedded_path_var) + if (\${item} MATCHES ${PLUGIN_PREFIX_DIR}) + set(path \"@executable_path/../PlugIns/${PLUGIN_PREFIX_DIR}\") + set(\${default_embedded_path_var} \"\${path}\" PARENT_SCOPE) + endif() + endfunction() + cmake_policy(SET CMP0009 OLD) - fixup_bundle(\"${OPENMW_APP}\" \"\" \"${DIRS}\") - fixup_bundle(\"${OPENCS_APP}\" \"\" \"${DIRS}\") + fixup_bundle(\"${OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\") + fixup_bundle(\"${OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\") " COMPONENT Runtime) include(CPack) endif (APPLE) From d9b11f963ad733d0ee105cd777202179e0b33658 Mon Sep 17 00:00:00 2001 From: Rohit Nirmal Date: Tue, 11 Aug 2015 21:45:02 -0500 Subject: [PATCH 240/419] Gamepad: Slow down simulated mouse with right trigger in menus. --- apps/openmw/mwinput/inputmanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 09e0b638b..2d767c6f5 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -370,6 +370,9 @@ namespace MWInput float zAxis = mInputBinder->getChannel(A_LookUpDown)->getValue()*2.0f-1.0f; const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + xAxis *= (1.5f - mInputBinder->getChannel(A_Use)->getValue()); + yAxis *= (1.5f - mInputBinder->getChannel(A_Use)->getValue()); + // We keep track of our own mouse position, so that moving the mouse while in // game mode does not move the position of the GUI cursor mGuiCursorX += xAxis * dt * 1500.0f * mInvUiScalingFactor; From 904ad949524864239f4b1f428d03a947360728a0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Aug 2015 12:03:20 +0200 Subject: [PATCH 241/419] added merge operation (doesn't do anything yet) --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/model/doc/document.cpp | 6 +++++ apps/opencs/model/doc/document.hpp | 5 ++-- apps/opencs/model/tools/mergeoperation.cpp | 15 +++++++++++ apps/opencs/model/tools/mergeoperation.hpp | 28 +++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 31 +++++++++++++++++++--- apps/opencs/model/tools/tools.hpp | 11 ++++++-- apps/opencs/view/tools/merge.cpp | 8 ++++++ 8 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 apps/opencs/model/tools/mergeoperation.cpp create mode 100644 apps/opencs/model/tools/mergeoperation.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 91c778c06..833ca6551 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -42,6 +42,7 @@ opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck + mergeoperation ) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 44e6142b0..a331706bc 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2388,6 +2388,12 @@ void CSMDoc::Document::runSearch (const CSMWorld::UniversalId& searchId, const C emit stateChanged (getState(), this); } +void CSMDoc::Document::runMerge (const boost::filesystem::path& target) +{ + mTools.runMerge (target); + emit stateChanged (getState(), this); +} + void CSMDoc::Document::abortOperation (int type) { if (type==State_Saving) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index c9271fa54..901a8e3e4 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -129,7 +129,9 @@ namespace CSMDoc CSMWorld::UniversalId newSearch(); void runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search); - + + void runMerge (const boost::filesystem::path& target); + void abortOperation (int type); const CSMWorld::Data& getData() const; @@ -173,4 +175,3 @@ namespace CSMDoc } #endif - diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp new file mode 100644 index 000000000..65cfdb4ff --- /dev/null +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -0,0 +1,15 @@ + +#include "mergeoperation.hpp" + +#include "../doc/state.hpp" + +CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document) +: CSMDoc::Operation (CSMDoc::State_Merging, true) +{ + +} + +void CSMTools::MergeOperation::setTarget (const boost::filesystem::path& target) +{ + +} diff --git a/apps/opencs/model/tools/mergeoperation.hpp b/apps/opencs/model/tools/mergeoperation.hpp new file mode 100644 index 000000000..84526b2f2 --- /dev/null +++ b/apps/opencs/model/tools/mergeoperation.hpp @@ -0,0 +1,28 @@ +#ifndef CSM_TOOLS_MERGEOPERATION_H +#define CSM_TOOLS_MERGEOPERATION_H + +#include + +#include "../doc/operation.hpp" + +namespace CSMDoc +{ + class Document; +} + +namespace CSMTools +{ + class MergeOperation : public CSMDoc::Operation + { + + + public: + + MergeOperation (CSMDoc::Document& document); + + /// \attention Do not call this function while a merge is running. + void setTarget (const boost::filesystem::path& target); + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index c9c116091..ba894a867 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -28,6 +28,7 @@ #include "searchoperation.hpp" #include "pathgridcheck.hpp" #include "soundgencheck.hpp" +#include "mergeoperation.hpp" CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { @@ -35,6 +36,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { case CSMDoc::State_Verifying: return &mVerifier; case CSMDoc::State_Searching: return &mSearch; + case CSMDoc::State_Merging: return &mMerge; } return 0; @@ -53,7 +55,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() std::vector settings; settings.push_back ("script-editor/warnings"); - + mVerifierOperation->configureSettings (settings); connect (&mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); @@ -116,7 +118,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() CSMTools::Tools::Tools (CSMDoc::Document& document) : mDocument (document), mData (document.getData()), mVerifierOperation (0), - mSearchOperation (0), mNextReportNumber (0) + mSearchOperation (0), mMergeOperation (0), mNextReportNumber (0) { // index 0: load error log mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); @@ -142,6 +144,12 @@ CSMTools::Tools::~Tools() delete mSearchOperation; } + if (mMergeOperation) + { + mMerge.abortAndWait(); + delete mMergeOperation; + } + for (std::map::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter) delete iter->second; } @@ -153,7 +161,7 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier (const CSMWorld::UniversalId& if (mReports.find (reportNumber)==mReports.end()) mReports.insert (std::make_pair (reportNumber, new ReportModel)); - + mActiveReports[CSMDoc::State_Verifying] = reportNumber; getVerifier()->start(); @@ -183,6 +191,21 @@ void CSMTools::Tools::runSearch (const CSMWorld::UniversalId& searchId, const Se mSearch.start(); } +void CSMTools::Tools::runMerge (const boost::filesystem::path& target) +{ + // not setting an active report, because merge does not produce messages + + if (!mMergeOperation) + { + mMergeOperation = new MergeOperation (mDocument); + mMerge.setOperation (mMergeOperation); + } + + mMergeOperation->setTarget (target); + + mMerge.start(); +} + void CSMTools::Tools::abortOperation (int type) { if (CSMDoc::OperationHolder *operation = get (type)) @@ -195,6 +218,7 @@ int CSMTools::Tools::getRunningOperations() const { CSMDoc::State_Verifying, CSMDoc::State_Searching, + CSMDoc::State_Merging, -1 }; @@ -225,4 +249,3 @@ void CSMTools::Tools::verifierMessage (const CSMDoc::Message& message, int type) if (iter!=mActiveReports.end()) mReports[iter->second]->add (message); } - diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 78484d15d..952099928 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -1,9 +1,11 @@ #ifndef CSM_TOOLS_TOOLS_H #define CSM_TOOLS_TOOLS_H +#include + #include -#include +#include #include "../doc/operationholder.hpp" @@ -24,6 +26,7 @@ namespace CSMTools class ReportModel; class Search; class SearchOperation; + class MergeOperation; class Tools : public QObject { @@ -35,6 +38,8 @@ namespace CSMTools CSMDoc::OperationHolder mVerifier; SearchOperation *mSearchOperation; CSMDoc::OperationHolder mSearch; + MergeOperation *mMergeOperation; + CSMDoc::OperationHolder mMerge; std::map mReports; int mNextReportNumber; std::map mActiveReports; // type, report number @@ -67,7 +72,9 @@ namespace CSMTools CSMWorld::UniversalId newSearch(); void runSearch (const CSMWorld::UniversalId& searchId, const Search& search); - + + void runMerge (const boost::filesystem::path& target); + void abortOperation (int type); ///< \attention The operation is not aborted immediately. diff --git a/apps/opencs/view/tools/merge.cpp b/apps/opencs/view/tools/merge.cpp index baadd9179..faf7be3b4 100644 --- a/apps/opencs/view/tools/merge.cpp +++ b/apps/opencs/view/tools/merge.cpp @@ -66,7 +66,9 @@ CSVTools::Merge::Merge (QWidget *parent) QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Cancel, Qt::Horizontal, this); connect (buttons->button (QDialogButtonBox::Cancel), SIGNAL (clicked()), this, SLOT (reject())); + mOkay = new QPushButton ("Merge", this); + connect (mOkay, SIGNAL (clicked()), this, SLOT (accept())); mOkay->setDefault (true); buttons->addButton (mOkay, QDialogButtonBox::AcceptRole); @@ -109,6 +111,12 @@ void CSVTools::Merge::cancel() void CSVTools::Merge::accept() { QDialog::accept(); + + if ((mDocument->getState() & CSMDoc::State_Merging)==0) + { + mDocument->runMerge (mAdjuster->getPath()); + hide(); + } } void CSVTools::Merge::reject() From e2377396a7cf7b9cd1ec91e0f385721a124a49cc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Aug 2015 12:53:00 +0200 Subject: [PATCH 242/419] inheriting Merge from QWidget instead of QDialog, because QDialog is bloody useless for non-modal dialogues (which makes the class completely useless, since modal dialogues are the spawn of Satan) --- apps/opencs/editor.cpp | 2 ++ apps/opencs/view/tools/merge.cpp | 24 ++++++++++++++---------- apps/opencs/view/tools/merge.hpp | 15 +++++++-------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 170e88320..0b385f275 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -379,4 +379,6 @@ void CS::Editor::mergeDocument (CSMDoc::Document *document) { mMerge.configure (document); mMerge.show(); + mMerge.raise(); + mMerge.activateWindow(); } diff --git a/apps/opencs/view/tools/merge.cpp b/apps/opencs/view/tools/merge.cpp index faf7be3b4..f775390ee 100644 --- a/apps/opencs/view/tools/merge.cpp +++ b/apps/opencs/view/tools/merge.cpp @@ -7,14 +7,26 @@ #include #include #include +#include #include "../../model/doc/document.hpp" #include "../doc/filewidget.hpp" #include "../doc/adjusterwidget.hpp" +void CSVTools::Merge::keyPressEvent (QKeyEvent *event) +{ + if (event->key()==Qt::Key_Escape) + { + event->accept(); + cancel(); + } + else + QWidget::keyPressEvent (event); +} + CSVTools::Merge::Merge (QWidget *parent) -: QDialog (parent), mDocument (0) +: QWidget (parent), mDocument (0) { setWindowTitle ("Merge Content Files into a new Game File"); @@ -65,7 +77,7 @@ CSVTools::Merge::Merge (QWidget *parent) // buttons QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Cancel, Qt::Horizontal, this); - connect (buttons->button (QDialogButtonBox::Cancel), SIGNAL (clicked()), this, SLOT (reject())); + connect (buttons->button (QDialogButtonBox::Cancel), SIGNAL (clicked()), this, SLOT (cancel())); mOkay = new QPushButton ("Merge", this); connect (mOkay, SIGNAL (clicked()), this, SLOT (accept())); @@ -110,8 +122,6 @@ void CSVTools::Merge::cancel() void CSVTools::Merge::accept() { - QDialog::accept(); - if ((mDocument->getState() & CSMDoc::State_Merging)==0) { mDocument->runMerge (mAdjuster->getPath()); @@ -119,12 +129,6 @@ void CSVTools::Merge::accept() } } -void CSVTools::Merge::reject() -{ - QDialog::reject(); - cancel(); -} - void CSVTools::Merge::stateChanged (bool valid) { mOkay->setEnabled (valid); diff --git a/apps/opencs/view/tools/merge.hpp b/apps/opencs/view/tools/merge.hpp index 4538baebe..b8369ffa3 100644 --- a/apps/opencs/view/tools/merge.hpp +++ b/apps/opencs/view/tools/merge.hpp @@ -1,7 +1,7 @@ #ifndef CSV_TOOLS_REPORTTABLE_H #define CSV_TOOLS_REPORTTABLE_H -#include +#include #include @@ -21,7 +21,7 @@ namespace CSVDoc namespace CSVTools { - class Merge : public QDialog + class Merge : public QWidget { Q_OBJECT @@ -31,6 +31,8 @@ namespace CSVTools CSVDoc::FileWidget *mNewFile; CSVDoc::AdjusterWidget *mAdjuster; + void keyPressEvent (QKeyEvent *event); + public: Merge (QWidget *parent = 0); @@ -42,18 +44,15 @@ namespace CSVTools CSMDoc::Document *getDocument() const; - void cancel(); - public slots: - virtual void accept(); - - virtual void reject(); + void cancel(); private slots: - void stateChanged (bool valid); + void accept(); + void stateChanged (bool valid); }; } From d8655f2ff862dbaf90fb285ef01cdf6891cdbea6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Aug 2015 14:49:32 +0200 Subject: [PATCH 243/419] forgot to connect merge operation signals --- apps/opencs/model/tools/tools.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index ba894a867..681f74404 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -128,6 +128,10 @@ CSMTools::Tools::Tools (CSMDoc::Document& document) connect (&mSearch, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); connect (&mSearch, SIGNAL (reportMessage (const CSMDoc::Message&, int)), this, SLOT (verifierMessage (const CSMDoc::Message&, int))); + + connect (&mMerge, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); + connect (&mMerge, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); + // don't need to connect report message, since there are no messages for merge } CSMTools::Tools::~Tools() From c07ced4c8fe626ab74f2c554504aefc55a86fb78 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 13 Aug 2015 17:01:25 +0200 Subject: [PATCH 244/419] Editor: fix magic effect magnitudes incorrectly labelled as Min/Max Range --- apps/opencs/model/world/columns.cpp | 2 ++ apps/opencs/model/world/columns.hpp | 3 +++ apps/opencs/model/world/data.cpp | 8 ++++---- apps/opencs/model/world/refidcollection.cpp | 4 ++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 7aec68309..579bc9899 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -35,6 +35,8 @@ namespace CSMWorld { ColumnId_Volume, "Volume" }, { ColumnId_MinRange, "Min Range" }, { ColumnId_MaxRange, "Max Range" }, + { ColumnId_MinMagnitude, "Min Magnitude" }, + { ColumnId_MaxMagnitude, "Max Magnitude" }, { ColumnId_SoundFile, "Sound File" }, { ColumnId_MapColour, "Map Colour" }, { ColumnId_SleepEncounter, "Sleep Encounter" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index d699c67b7..5dfa479f6 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -306,6 +306,9 @@ namespace CSMWorld ColumnId_FileDescription = 276, ColumnId_Author = 277, + ColumnId_MinMagnitude = 278, + ColumnId_MaxMagnitude = 279, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 3714117b6..25a04715d 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -224,9 +224,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mSpells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MinMagnitude, ColumnBase::Display_Integer)); mSpells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MaxMagnitude, ColumnBase::Display_Integer)); mTopics.addColumn (new StringIdColumn); mTopics.addColumn (new RecordStateColumn); @@ -340,9 +340,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mEnchantments.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MinMagnitude, ColumnBase::Display_Integer)); mEnchantments.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MaxMagnitude, ColumnBase::Display_Integer)); mBodyParts.addColumn (new StringIdColumn); mBodyParts.addColumn (new RecordStateColumn); diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 947454d77..5b2d184a7 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -93,9 +93,9 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new NestedChildColumn (Columns::ColumnId_Duration, ColumnBase::Display_Integer)); // reuse from light mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_MinRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MinMagnitude, ColumnBase::Display_Integer)); mColumns.back().addColumn( - new NestedChildColumn (Columns::ColumnId_MaxRange, ColumnBase::Display_Integer)); // reuse from sound + new NestedChildColumn (Columns::ColumnId_MaxMagnitude, ColumnBase::Display_Integer)); EnchantableColumns enchantableColumns (inventoryColumns); From 86f0e505e956583e9d62f13fd565a30f4a8f388f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 28 Jul 2015 23:27:25 +0200 Subject: [PATCH 245/419] Add a fixPosition for the --start exterior cell (Fixes #2790) --- apps/openmw/mwworld/worldimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 15c8cbeb2..a97c8f0d4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -228,6 +228,7 @@ namespace MWWorld if (findExteriorPosition (mStartCell, pos)) { changeToExteriorCell (pos); + fixPosition(getPlayerPtr()); } else { From 0d8f07d5634a8127c350d3418e5b9dd836e67aa2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 31 Jul 2015 20:55:31 +0200 Subject: [PATCH 246/419] Properly apply changes when backing out of chargen dialogs (Fixes #2627) --- apps/openmw/mwgui/charactercreation.cpp | 107 +++++++++++------------- apps/openmw/mwgui/charactercreation.hpp | 5 ++ 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index d0a050526..6585a0dd0 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -312,7 +312,7 @@ namespace MWGui }; } - void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) + void CharacterCreation::selectPickedClass() { if (mPickClassDialog) { @@ -332,20 +332,18 @@ namespace MWGui } updatePlayerHealth(); + } + + void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) + { + selectPickedClass(); handleDialogDone(CSE_ClassChosen, GM_Birth); } void CharacterCreation::onPickClassDialogBack() { - if (mPickClassDialog) - { - const std::string classId = mPickClassDialog->getClassId(); - if (!classId.empty()) - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); - MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); - mPickClassDialog = 0; - } + selectPickedClass(); MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); @@ -390,29 +388,7 @@ namespace MWGui handleDialogDone(CSE_NameChosen, GM_Race); } - void CharacterCreation::onRaceDialogBack() - { - if (mRaceDialog) - { - const ESM::NPC &data = mRaceDialog->getResult(); - mPlayerRaceId = data.mRace; - if (!mPlayerRaceId.empty()) { - MWBase::Environment::get().getMechanicsManager()->setPlayerRace( - data.mRace, - data.isMale(), - data.mHead, - data.mHair - ); - } - MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); - mRaceDialog = 0; - } - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); - } - - void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) + void CharacterCreation::selectRace() { if (mRaceDialog) { @@ -433,11 +409,24 @@ namespace MWGui } updatePlayerHealth(); + } + + void CharacterCreation::onRaceDialogBack() + { + selectRace(); + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); + } + + void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) + { + selectRace(); handleDialogDone(CSE_RaceChosen, GM_Class); } - void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) + void CharacterCreation::selectBirthSign() { if (mBirthSignDialog) { @@ -449,24 +438,24 @@ namespace MWGui } updatePlayerHealth(); + } + + void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) + { + selectBirthSign(); handleDialogDone(CSE_BirthSignChosen, GM_Review); } void CharacterCreation::onBirthSignDialogBack() { - if (mBirthSignDialog) - { - MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mBirthSignDialog->getBirthId()); - MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); - mBirthSignDialog = 0; - } + selectBirthSign(); MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } - void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) + void CharacterCreation::selectCreatedClass() { if (mCreateClassDialog) { @@ -495,19 +484,23 @@ namespace MWGui mPlayerClass = klass; MWBase::Environment::get().getWindowManager()->setPlayerClass(klass); - // Do not delete dialog, so that choices are rembered in case we want to go back and adjust them later + // Do not delete dialog, so that choices are remembered in case we want to go back and adjust them later mCreateClassDialog->setVisible(false); } - updatePlayerHealth(); + } + + void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) + { + selectCreatedClass(); handleDialogDone(CSE_ClassChosen, GM_Birth); } void CharacterCreation::onCreateClassDialogBack() { - // Do not delete dialog, so that choices are rembered in case we want to go back and adjust them later - mCreateClassDialog->setVisible(false); + // not done in MW, but we do it for consistency with the other dialogs + selectCreatedClass(); MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); @@ -631,18 +624,7 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->say(sGenerateClassSteps(mGenerateClassStep).mSound); } - void CharacterCreation::onGenerateClassBack() - { - MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); - mGenerateClassResultDialog = 0; - - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - } - - void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) + void CharacterCreation::selectGeneratedClass() { MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = 0; @@ -656,6 +638,19 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); updatePlayerHealth(); + } + + void CharacterCreation::onGenerateClassBack() + { + selectGeneratedClass(); + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + } + + void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) + { + selectGeneratedClass(); handleDialogDone(CSE_ClassChosen, GM_Birth); } diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index f6e7c6c92..7fb67caf6 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -83,6 +83,7 @@ namespace MWGui //Race dialog void onRaceDialogDone(WindowBase* parWindow); void onRaceDialogBack(); + void selectRace(); //Class dialogs void onClassChoice(int _index); @@ -94,10 +95,14 @@ namespace MWGui void onClassQuestionChosen(int _index); void onGenerateClassBack(); void onGenerateClassDone(WindowBase* parWindow); + void selectGeneratedClass(); + void selectCreatedClass(); + void selectPickedClass(); //Birthsign dialog void onBirthSignDialogDone(WindowBase* parWindow); void onBirthSignDialogBack(); + void selectBirthSign(); //Review dialog void onReviewDialogDone(WindowBase* parWindow); From 211deeb63e2c5f70dd3a8a78dcb8f16cd17b2c5d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 4 Aug 2015 17:33:34 +0200 Subject: [PATCH 247/419] Don't attempt to lock or unlock unsuitable objects (Fixes #2826) --- apps/openmw/mwclass/container.cpp | 13 +++++++------ apps/openmw/mwclass/container.hpp | 2 ++ apps/openmw/mwclass/door.cpp | 5 +++++ apps/openmw/mwclass/door.hpp | 2 ++ apps/openmw/mwmechanics/security.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 6 +++--- apps/openmw/mwworld/class.cpp | 5 +++++ apps/openmw/mwworld/class.hpp | 2 ++ 8 files changed, 27 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 862ae6c5d..830493627 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -281,9 +281,12 @@ namespace MWClass ptr.getCellRef().setLockLevel(-abs(ptr.getCellRef().getLockLevel())); //Makes lockLevel negative } + bool Container::canLock(const MWWorld::Ptr &ptr) const + { + return true; + } - MWWorld::Ptr - Container::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + MWWorld::Ptr Container::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -291,8 +294,7 @@ namespace MWClass return MWWorld::Ptr(&cell.get().insert(*ref), &cell); } - void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) - const + void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const { const ESM::ContainerState& state2 = dynamic_cast (state); @@ -307,8 +309,7 @@ namespace MWClass readState (state2.mInventory); } - void Container::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) - const + void Container::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) const { ESM::ContainerState& state2 = dynamic_cast (state); diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 3268d45d1..3541937d1 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -57,6 +57,8 @@ namespace MWClass virtual void unlock (const MWWorld::Ptr& ptr) const; ///< Unlock object + virtual bool canLock(const MWWorld::Ptr &ptr) const; + virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const; ///< Read additional state from \a state into \a ptr. diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 5a8c736d9..5062cc557 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -207,6 +207,11 @@ namespace MWClass ptr.getCellRef().setLockLevel(-abs(ptr.getCellRef().getLockLevel())); //Makes lockLevel negative } + bool Door::canLock(const MWWorld::Ptr &ptr) const + { + return true; + } + std::string Door::getScript (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 9cfb46509..db5a7f32a 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -47,6 +47,8 @@ namespace MWClass virtual void unlock (const MWWorld::Ptr& ptr) const; ///< Unlock object + virtual bool canLock(const MWWorld::Ptr &ptr) const; + virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index 9eab5bfef..97878db87 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -31,7 +31,7 @@ namespace MWMechanics void Security::pickLock(const MWWorld::Ptr &lock, const MWWorld::Ptr &lockpick, std::string& resultMessage, std::string& resultSound) { - if (!(lock.getCellRef().getLockLevel() > 0)) //If it's unlocked back out immediately + if (!(lock.getCellRef().getLockLevel() > 0) || !lock.getClass().canLock(lock)) //If it's unlocked back out immediately return; int lockStrength = lock.getCellRef().getLockLevel(); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 1613300d7..675177508 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -562,7 +562,7 @@ namespace MWMechanics void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, const MWWorld::Ptr &caster, const MWMechanics::EffectKey& effect, float magnitude) { short effectId = effect.mId; - if (!target.getClass().isActor()) + if (target.getClass().canLock(target)) { if (effectId == ESM::MagicEffect::Lock) { @@ -570,7 +570,7 @@ namespace MWMechanics { if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicLockSuccess}"); - target.getCellRef().setLockLevel(static_cast(magnitude)); + target.getClass().lock(target, static_cast(magnitude)); } } else if (effectId == ESM::MagicEffect::Open) @@ -586,7 +586,7 @@ namespace MWMechanics if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicOpenSuccess}"); } - target.getCellRef().setLockLevel(-abs(target.getCellRef().getLockLevel())); + target.getClass().unlock(target); } else MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 180cba332..18200e33b 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -144,6 +144,11 @@ namespace MWWorld throw std::runtime_error ("class does not support unlocking"); } + bool Class::canLock(const Ptr &ptr) const + { + return false; + } + void Class::setRemainingUsageTime (const Ptr& ptr, float duration) const { throw std::runtime_error ("class does not support time-based uses"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index cd05b471b..1157db670 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -161,6 +161,8 @@ namespace MWWorld virtual void unlock (const Ptr& ptr) const; ///< Unlock object (default implementation: throw an exception) + virtual bool canLock (const Ptr& ptr) const; + virtual void setRemainingUsageTime (const Ptr& ptr, float duration) const; ///< Sets the remaining duration of the object, such as an equippable light /// source. (default implementation: throw an exception) From 1e18a73b1c7ba1551a2eecbd1c4b45fd4298dd9a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 4 Aug 2015 17:55:38 +0200 Subject: [PATCH 248/419] Don't play magic effect sounds & visual effects for unsuitable targets (Fixes #2811) --- apps/openmw/mwmechanics/spellcasting.cpp | 43 ++++++++++++++++-------- apps/openmw/mwmechanics/spellcasting.hpp | 3 +- apps/openmw/mwworld/worldimp.cpp | 4 --- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 675177508..eacd674ed 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -489,8 +489,8 @@ namespace MWMechanics if (!wasDead && isDead) MWBase::Environment::get().getMechanicsManager()->actorKilled(target, caster); } - else - applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); + else if (!applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude)) + continue; } // Re-casting a summon effect will remove the creature from previous castings of that effect. @@ -559,7 +559,7 @@ namespace MWMechanics target.getClass().onHit(target, 0.f, true, MWWorld::Ptr(), caster, true); } - void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, const MWWorld::Ptr &caster, const MWMechanics::EffectKey& effect, float magnitude) + bool CastSpell::applyInstantEffect(const MWWorld::Ptr &target, const MWWorld::Ptr &caster, const MWMechanics::EffectKey& effect, float magnitude) { short effectId = effect.mId; if (target.getClass().canLock(target)) @@ -572,6 +572,7 @@ namespace MWMechanics MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicLockSuccess}"); target.getClass().lock(target, static_cast(magnitude)); } + return true; } else if (effectId == ESM::MagicEffect::Open) { @@ -590,43 +591,55 @@ namespace MWMechanics } else MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f); + return true; } } - else + else if (target.getClass().isActor()) { - if (effectId == ESM::MagicEffect::CurePoison) + switch (effectId) + { + case ESM::MagicEffect::CurePoison: target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison); - else if (effectId == ESM::MagicEffect::CureParalyzation) + return true; + case ESM::MagicEffect::CureParalyzation: target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Paralyze); - else if (effectId == ESM::MagicEffect::CureCommonDisease) + return true; + case ESM::MagicEffect::CureCommonDisease: target.getClass().getCreatureStats(target).getSpells().purgeCommonDisease(); - else if (effectId == ESM::MagicEffect::CureBlightDisease) + return true; + case ESM::MagicEffect::CureBlightDisease: target.getClass().getCreatureStats(target).getSpells().purgeBlightDisease(); - else if (effectId == ESM::MagicEffect::CureCorprusDisease) + return true; + case ESM::MagicEffect::CureCorprusDisease: target.getClass().getCreatureStats(target).getSpells().purgeCorprusDisease(); - else if (effectId == ESM::MagicEffect::Dispel) + return true; + case ESM::MagicEffect::Dispel: target.getClass().getCreatureStats(target).getActiveSpells().purgeAll(magnitude); - else if (effectId == ESM::MagicEffect::RemoveCurse) + return true; + case ESM::MagicEffect::RemoveCurse: target.getClass().getCreatureStats(target).getSpells().purgeCurses(); + return true; + } if (target != MWBase::Environment::get().getWorld()->getPlayerPtr()) - return; - if (!MWBase::Environment::get().getWorld()->isTeleportingEnabled()) - return; + return false; if (effectId == ESM::MagicEffect::DivineIntervention) { MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "divinemarker"); + return true; } else if (effectId == ESM::MagicEffect::AlmsiviIntervention) { MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "templemarker"); + return true; } else if (effectId == ESM::MagicEffect::Mark) { MWBase::Environment::get().getWorld()->getPlayer().markPosition( target.getCell(), target.getRefData().getPosition()); + return true; } else if (effectId == ESM::MagicEffect::Recall) { @@ -640,8 +653,10 @@ namespace MWMechanics markedPosition, false); action.execute(target); } + return true; } } + return false; } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 418e9f56d..5b48bd4a8 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -97,7 +97,8 @@ namespace MWMechanics const ESM::EffectList& effects, ESM::RangeType range, bool reflected=false, bool exploded=false); /// @note \a caster can be any type of object, or even an empty object. - void applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude); + /// @return was the target suitable for the effect? + bool applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude); }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a97c8f0d4..fb2778940 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2656,10 +2656,6 @@ namespace MWWorld target = result.mHitObject; hitPosition = result.mHitPos; - // don't allow casting on non-activatable objects - if (!target.isEmpty() && !target.getClass().isActor() && target.getClass().getName(target).empty()) - target = MWWorld::Ptr(); - std::string selectedSpell = stats.getSpells().getSelectedSpell(); MWMechanics::CastSpell cast(actor, target); From e8c9d3ea2ae72fe72ae974e69a24490ab9c361a9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 6 Aug 2015 23:29:19 +0200 Subject: [PATCH 249/419] Fix cell names on world map not always being translated (Fixes #2832) --- apps/openmw/mwgui/mapwindow.cpp | 2 +- apps/openmw/mwgui/mapwindow.hpp | 3 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index e26c076e7..2df1c8f3c 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -783,7 +783,7 @@ namespace MWGui MyGUI::Widget* markerWidget = mGlobalMap->createWidget("MarkerButton", widgetCoord, MyGUI::Align::Default); - markerWidget->setUserString("Caption_TextOneLine", name); + markerWidget->setUserString("Caption_TextOneLine", "#{sCell=" + name + "}"); setGlobalMapMarkerTooltip(markerWidget, x, y); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index a5594bee8..a41d5d527 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -190,7 +190,8 @@ namespace MWGui void renderGlobalMap(Loading::Listener* loadingListener); - // adds the marker to the global map + /// adds the marker to the global map + /// @param name The ESM::Cell::mName void addVisitedLocation(const std::string& name, int x, int y); // reveals this cell's map on the global map diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 4552c42f2..db5593704 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -993,7 +993,7 @@ namespace MWGui if (cell->getCell()->isExterior()) { if (!cell->getCell()->mName.empty()) - mMap->addVisitedLocation ("#{sCell=" + name + "}", cell->getCell()->getGridX (), cell->getCell()->getGridY ()); + mMap->addVisitedLocation (name, cell->getCell()->getGridX (), cell->getCell()->getGridY ()); mMap->cellExplored (cell->getCell()->getGridX(), cell->getCell()->getGridY()); } From d76fb2d26601bf6d082762b68b157860d41fec0a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 14 Aug 2015 13:38:39 +0200 Subject: [PATCH 250/419] Apply disintegrate only to weapons and armor (Fixes #2853) --- apps/openmw/mwmechanics/spellcasting.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index eacd674ed..b98bf9f96 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -941,7 +941,8 @@ namespace MWMechanics MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr); MWWorld::ContainerStoreIterator item = inv.getSlot(slot); - if (item != inv.end()) + + if (item != inv.end() && (item.getType() == MWWorld::ContainerStore::Type_Armor || item.getType() == MWWorld::ContainerStore::Type_Weapon)) { if (!item->getClass().hasItemHealth(*item)) return false; From c57e72fe03c35e3c888e7e894f718914ef71744d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 16:09:53 +0200 Subject: [PATCH 251/419] Adjust the sleep interruption chance (Fixes #2781) --- apps/openmw/mwgui/waitdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 4aeec146f..37a827745 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -157,7 +157,7 @@ namespace MWGui // figure out if player will be woken while sleeping int x = Misc::Rng::rollDice(hoursToWait); float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->getFloat(); - if (x < fSleepRandMod * hoursToWait) + if (x < static_cast(fSleepRandMod * hoursToWait)) { float fSleepRestMod = world->getStore().get().find("fSleepRestMod")->getFloat(); mInterruptAt = hoursToWait - int(fSleepRestMod * hoursToWait); From e36ebc77d57e48973b9514e31a0d82aa02547fa5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 18:39:00 +0200 Subject: [PATCH 252/419] Editor: remove creature flag of unknown purpose from the UI --- apps/opencs/model/world/columns.cpp | 1 - apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/refidcollection.cpp | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 579bc9899..177fb59ce 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -109,7 +109,6 @@ namespace CSMWorld { ColumnId_OriginalCreature, "Original Creature" }, { ColumnId_Biped, "Biped" }, { ColumnId_HasWeapon, "Has Weapon" }, - { ColumnId_NoMovement, "No Movement" }, { ColumnId_Swims, "Swims" }, { ColumnId_Flies, "Flies" }, { ColumnId_Walks, "Walks" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 5dfa479f6..2f66542b1 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -102,7 +102,7 @@ namespace CSMWorld ColumnId_OriginalCreature = 87, ColumnId_Biped = 88, ColumnId_HasWeapon = 89, - ColumnId_NoMovement = 90, + // unused ColumnId_Swims = 91, ColumnId_Flies = 92, ColumnId_Walks = 93, diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 5b2d184a7..16da4aad9 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -321,7 +321,6 @@ CSMWorld::RefIdCollection::RefIdCollection() { { Columns::ColumnId_Biped, ESM::Creature::Bipedal }, { Columns::ColumnId_HasWeapon, ESM::Creature::Weapon }, - { Columns::ColumnId_NoMovement, ESM::Creature::None }, { Columns::ColumnId_Swims, ESM::Creature::Swims }, { Columns::ColumnId_Flies, ESM::Creature::Flies }, { Columns::ColumnId_Walks, ESM::Creature::Walks }, From 58cd2b1a84828f406e2970b7d688fc1e01b0ba38 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 19:01:21 +0200 Subject: [PATCH 253/419] Remove "Tri Bip*" nodes in creature meshes (meant for debugging)? (Fixes #2148) --- apps/openmw/mwrender/animation.cpp | 43 +++++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 4 +- apps/openmw/mwrender/npcanimation.cpp | 2 +- 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ee0ce6df1..c1ae5fed5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -208,6 +208,38 @@ namespace std::vector mToRemove; }; + class RemoveTriBipVisitor : public osg::NodeVisitor + { + public: + RemoveTriBipVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } + + virtual void apply(osg::Geode &node) + { + const std::string toFind = "tri bip"; + if (Misc::StringUtils::ciCompareLen(node.getName(), toFind, toFind.size()) == 0) + { + // Not safe to remove in apply(), since the visitor is still iterating the child list + mToRemove.push_back(&node); + } + } + + void remove() + { + for (std::vector::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) + { + osg::Node* node = *it; + if (node->getNumParents()) + node->getParent(0)->removeChild(node); + } + } + + private: + std::vector mToRemove; + }; + } namespace MWRender @@ -898,7 +930,7 @@ namespace MWRender return movement; } - void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly) + void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature) { if (mObjectRoot) { @@ -933,6 +965,13 @@ namespace MWRender removeDrawableVisitor.remove(); } + if (isCreature) + { + RemoveTriBipVisitor removeTriBipVisitor; + mObjectRoot->accept(removeTriBipVisitor); + removeTriBipVisitor.remove(); + } + NodeMapVisitor visitor; mObjectRoot->accept(visitor); mNodeMap = visitor.getNodeMap(); @@ -1308,7 +1347,7 @@ namespace MWRender { if (!model.empty()) { - setObjectRoot(model, false, false); + setObjectRoot(model, false, false, false); if (animated) addAnimSource(model); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 23f807238..30b6d156a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -273,7 +273,7 @@ protected: * @param baseonly If true, then any meshes or particle systems in the model are ignored * (useful for NPCs, where only the skeleton is needed for the root, and the actual NPC parts are then assembled from separate files). */ - void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly); + void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature); /* Adds the keyframe controllers in the specified model as a new animation source. Note that * the filename portion of the provided model name will be prepended with 'x', and the .nif diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 35294b1b5..f46736a39 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -24,7 +24,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, if(!model.empty()) { - setObjectRoot(model, false, false); + setObjectRoot(model, false, false, true); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) addAnimSource("meshes\\xbase_anim.nif"); @@ -42,7 +42,7 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const if(!model.empty()) { - setObjectRoot(model, true, false); + setObjectRoot(model, true, false, true); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) addAnimSource("meshes\\xbase_anim.nif"); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 6417bc812..c5a107837 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -378,7 +378,7 @@ void NpcAnimation::updateNpcBase() : "meshes\\wolf\\skin.1st.nif"); smodel = Misc::ResourceHelpers::correctActorModelPath(smodel, mResourceSystem->getVFS()); - setObjectRoot(smodel, true, true); + setObjectRoot(smodel, true, true, false); if(mViewMode != VM_FirstPerson) { From 7dd09dd637c317d3d94497b9d1cca4e1c4e54420 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 20:44:15 +0200 Subject: [PATCH 254/419] Fix being able to flip journal pages with the mousewheel when the options overlay is active (Fixes #2855) --- apps/openmw/mwgui/journalwindow.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 4cfcc8064..8238f6585 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -61,6 +61,7 @@ namespace DisplayStateStack mStates; Book mTopicIndexBook; bool mQuestMode; + bool mOptionsMode; bool mAllQuests; template @@ -182,6 +183,7 @@ namespace mQuestMode = false; mAllQuests = false; + mOptionsMode = false; } void adjustButton (char const * name, bool optional = false) @@ -244,6 +246,7 @@ namespace void setBookMode () { + mOptionsMode = false; setVisible (OptionsBTN, true); setVisible (OptionsOverlay, false); @@ -253,6 +256,8 @@ namespace void setOptionsMode () { + mOptionsMode = true; + setVisible (OptionsBTN, false); setVisible (OptionsOverlay, true); @@ -508,6 +513,8 @@ namespace void notifyNextPage(MyGUI::Widget* _sender) { + if (mOptionsMode) + return; if (!mStates.empty ()) { unsigned int & page = mStates.top ().mPage; @@ -523,6 +530,8 @@ namespace void notifyPrevPage(MyGUI::Widget* _sender) { + if (mOptionsMode) + return; if (!mStates.empty ()) { unsigned int & page = mStates.top ().mPage; From 47ac20af40a8d322380e0e6d81a22812466e4666 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 22:28:59 +0200 Subject: [PATCH 255/419] Workaround flipped cursor on OS X --- components/sdlutil/sdlcursormanager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 89928d165..70a159306 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -126,7 +126,13 @@ namespace glViewport(0, 0, width, height); +#if defined(__APPLE__) + // FIXME: why are the extra flips needed on Mac? glReadPixels bug? + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,1,0), osg::Vec3(2,0,0), osg::Vec3(0,-2,0)); +#else osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); +#endif + geom->drawImplementation(renderInfo); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, resultImage->data()); From dbcce482a686f1b568663585d01e99b6fcab6447 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Wed, 12 Aug 2015 00:38:02 +0200 Subject: [PATCH 256/419] OS X: enable high resolution mode for OpenMW & OpenCS We don't support retina completely yet, but it's still better than blurry mess, and Qt does pretty good job for OpenCS already. --- CMakeLists.txt | 2 +- apps/opencs/CMakeLists.txt | 1 + .../mac/{Info.plist => openmw-Info.plist.in} | 2 + files/mac/openmw-cs-Info.plist.in | 38 +++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) rename files/mac/{Info.plist => openmw-Info.plist.in} (95%) create mode 100644 files/mac/openmw-cs-Info.plist.in diff --git a/CMakeLists.txt b/CMakeLists.txt index ad3c21e53..1e966a163 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -289,7 +289,7 @@ if(MYGUI_STATIC) endif (MYGUI_STATIC) if (APPLE) - configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist + configure_file(${OpenMW_SOURCE_DIR}/files/mac/openmw-Info.plist.in "${APP_BUNDLE_DIR}/Contents/Info.plist") configure_file(${OpenMW_SOURCE_DIR}/files/mac/openmw.icns diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e6dd045e1..b1953ee97 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -192,6 +192,7 @@ if(APPLE) MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs" MACOSX_BUNDLE_SHORT_VERSION_STRING ${OPENMW_VERSION} MACOSX_BUNDLE_BUNDLE_VERSION ${OPENMW_VERSION} + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/files/mac/openmw-cs-Info.plist.in" ) set_source_files_properties(${OPENCS_MAC_ICON} PROPERTIES diff --git a/files/mac/Info.plist b/files/mac/openmw-Info.plist.in similarity index 95% rename from files/mac/Info.plist rename to files/mac/openmw-Info.plist.in index f832b09c9..efd55ee5c 100644 --- a/files/mac/Info.plist +++ b/files/mac/openmw-Info.plist.in @@ -26,5 +26,7 @@ NSHumanReadableCopyright + NSHighResolutionCapable + diff --git a/files/mac/openmw-cs-Info.plist.in b/files/mac/openmw-cs-Info.plist.in new file mode 100644 index 000000000..684ad7908 --- /dev/null +++ b/files/mac/openmw-cs-Info.plist.in @@ -0,0 +1,38 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + ${MACOSX_BUNDLE_INFO_STRING} + CFBundleIconFile + ${MACOSX_BUNDLE_ICON_FILE} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + ${MACOSX_BUNDLE_LONG_VERSION_STRING} + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleSignature + ???? + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + CSResourcesFileMapped + + LSRequiresCarbon + + NSHumanReadableCopyright + ${MACOSX_BUNDLE_COPYRIGHT} + NSHighResolutionCapable + + + From af5ffa554821b4263c9a28ec279a48b1bd5937b2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 22:53:29 +0200 Subject: [PATCH 257/419] Don't warn about SDL touch events --- components/sdlutil/sdlinputwrapper.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index f607b7046..200d19bd8 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -138,6 +138,16 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v break; case SDL_CLIPBOARDUPDATE: break; // We don't need this event, clipboard is retrieved on demand + + case SDL_FINGERDOWN: + case SDL_FINGERUP: + case SDL_FINGERMOTION: + case SDL_DOLLARGESTURE: + case SDL_DOLLARRECORD: + case SDL_MULTIGESTURE: + // No use for touch & gesture events + break; + default: std::ios::fmtflags f(std::cerr.flags()); std::cerr << "Unhandled SDL event of type 0x" << std::hex << evt.type << std::endl; From 82419763687c7afea51ec807324099bff925d77a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Aug 2015 23:27:37 +0200 Subject: [PATCH 258/419] Don't attempt to play non-existing hit animations (Fixes #2856) --- apps/openmw/mwmechanics/character.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 22ddf1fb7..3959c413a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -247,15 +247,16 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat bool block = mPtr.getClass().getCreatureStats(mPtr).getBlock(); if(mHitState == CharState_None) { - if (mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0 + if ((mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0 || mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0) + && mAnimation->hasAnimation("knockout")) { mHitState = CharState_KnockOut; mCurrentHit = "knockout"; mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, false, 1, "start", "stop", 0.0f, ~0ul); mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(true); } - else if(knockdown) + else if(knockdown && mAnimation->hasAnimation("knockdown")) { mHitState = CharState_KnockDown; mCurrentHit = "knockdown"; @@ -263,11 +264,15 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat } else if (recovery) { - mHitState = CharState_Hit; - mCurrentHit = chooseRandomGroup("hit"); - mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); + std::string anim = chooseRandomGroup("hit"); + if (mAnimation->hasAnimation(anim)) + { + mHitState = CharState_Hit; + mCurrentHit = anim; + mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); + } } - else if (block) + else if (block && mAnimation->hasAnimation("shield")) { mHitState = CharState_Block; mCurrentHit = "shield"; From c25dacb4802c97761e66b9d5f157d847951774b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 01:50:44 +0200 Subject: [PATCH 259/419] Fix "Level" string in the save/load menu not being localised (Bug #2840) --- apps/openmw/mwgui/savegamedialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index d490d49cd..ae36cbacc 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -347,7 +347,7 @@ namespace MWGui char buffer[size]; if (std::strftime(buffer, size, "%x %X", timeinfo) > 0) text << buffer << "\n"; - text << "Level " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; + text << "#{sLevel} " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; text << mCurrentSlot->mProfile.mPlayerCell << "\n"; // text << "Time played: " << slot->mProfile.mTimePlayed << "\n"; From afb3d94ba41263127d90416302ed26f97885fc98 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 01:55:14 +0200 Subject: [PATCH 260/419] Fix cell names in the save/load menu not being localised (Fixes #2840) --- apps/openmw/mwgui/savegamedialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index ae36cbacc..82dd0d8a9 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -348,7 +348,7 @@ namespace MWGui if (std::strftime(buffer, size, "%x %X", timeinfo) > 0) text << buffer << "\n"; text << "#{sLevel} " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; - text << mCurrentSlot->mProfile.mPlayerCell << "\n"; + text << "#{sCell=" << mCurrentSlot->mProfile.mPlayerCell << "}\n"; // text << "Time played: " << slot->mProfile.mTimePlayed << "\n"; int hour = int(mCurrentSlot->mProfile.mInGameTime.mGameHour); From 8426d376f02765a5e446c818a1f2d0b40c481f3a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 02:06:04 +0200 Subject: [PATCH 261/419] Use separate touch spell raycasts for actors and objects (Fixes #2849) --- apps/openmw/mwworld/worldimp.cpp | 34 ++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fb2778940..f1bcec731 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2624,12 +2624,10 @@ namespace MWWorld { MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); - // Get the target to use for "on touch" effects + // Get the target to use for "on touch" effects, using the facing direction from Head node MWWorld::Ptr target; float distance = 192.f; // ?? osg::Vec3f hitPosition = actor.getRefData().getPosition().asVec3(); - - // For NPCs use facing direction from Head node osg::Vec3f origin(actor.getRefData().getPosition().asVec3()); MWRender::Animation* anim = mRendering->getAnimation(actor); @@ -2652,9 +2650,33 @@ namespace MWWorld osg::Vec3f direction = orient * osg::Vec3f(0,1,0); osg::Vec3f dest = origin + direction * distance; - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(origin, dest, actor); - target = result.mHitObject; - hitPosition = result.mHitPos; + // For actor targets, we want to use bounding boxes (physics raycast). + // This is to give a slight tolerance for errors, especially with creatures like the Skeleton that would be very hard to aim at otherwise. + // For object targets, we want the detailed shapes (rendering raycast). + // If we used the bounding boxes for static objects, then we would not be able to target e.g. objects lying on a shelf. + + MWPhysics::PhysicsSystem::RayResult result1 = mPhysics->castRay(origin, dest, actor, MWPhysics::CollisionType_Actor); + + MWRender::RenderingManager::RayResult result2 = mRendering->castRay(origin, dest, true, true); + + float dist1 = FLT_MAX; + float dist2 = FLT_MAX; + + if (result1.mHit) + dist1 = (origin - result1.mHitPos).length(); + if (result2.mHit) + dist2 = (origin - result2.mHitPointWorld).length(); + + if (dist1 <= dist2 && result1.mHit) + { + target = result1.mHitObject; + hitPosition = result1.mHitPos; + } + else if (result2.mHit) + { + target = result2.mHitObject; + hitPosition = result2.mHitPointWorld; + } std::string selectedSpell = stats.getSpells().getSelectedSpell(); From 3d419a612a1898847e5a536462072dae34ec0345 Mon Sep 17 00:00:00 2001 From: slothlife Date: Sat, 15 Aug 2015 23:38:49 -0500 Subject: [PATCH 262/419] Corrected some weather transition calculations Reversed some formulas for Transition Delta and Clouds Maximum Percent and implemented them. Refactored Weather some to encapsulate those formulas (to more closely match MoonModel). Did some small cleanup of WeatherManager. --- apps/openmw/mwworld/weather.cpp | 222 ++++++++++++++++---------------- apps/openmw/mwworld/weather.hpp | 68 ++++++---- 2 files changed, 153 insertions(+), 137 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 8d78b969e..99193de67 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -37,6 +37,68 @@ namespace } } +Weather::Weather(const std::string& name, + const MWWorld::Fallback& fallback, + float stormWindSpeed, + float rainSpeed, + const std::string& ambientLoopSoundID, + const std::string& particleEffect) + : mCloudTexture(fallback.getFallbackString("Weather_" + name + "_Cloud_Texture")) + , mSkySunriseColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color")) + , mSkyDayColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Day_Color")) + , mSkySunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Sunset_Color")) + , mSkyNightColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Night_Color")) + , mFogSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunrise_Color")) + , mFogDayColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Day_Color")) + , mFogSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunset_Color")) + , mFogNightColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Night_Color")) + , mAmbientSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunrise_Color")) + , mAmbientDayColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Day_Color")) + , mAmbientSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunset_Color")) + , mAmbientNightColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Night_Color")) + , mSunSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunrise_Color")) + , mSunDayColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Day_Color")) + , mSunSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunset_Color")) + , mSunNightColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Night_Color")) + , mLandFogDayDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth")) + , mLandFogNightDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Night_Depth")) + , mSunDiscSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Disc_Sunset_Color")) + , mWindSpeed(fallback.getFallbackFloat("Weather_" + name + "_Wind_Speed")) + , mCloudSpeed(fallback.getFallbackFloat("Weather_" + name + "_Cloud_Speed")) + , mGlareView(fallback.getFallbackFloat("Weather_" + name + "_Glare_View")) + , mAmbientLoopSoundID(ambientLoopSoundID) + , mIsStorm(mWindSpeed > stormWindSpeed) + , mRainSpeed(rainSpeed) + , mRainFrequency(fallback.getFallbackFloat("Weather_" + name + "_Rain_Entrance_Speed")) + , mParticleEffect(particleEffect) + , mRainEffect(fallback.getFallbackBool("Weather_" + name + "_Using_Precip") ? "meshes\\raindrop.nif" : "") + , mTransitionDelta(fallback.getFallbackFloat("Weather_" + name + "_Transition_Delta")) + , mCloudsMaximumPercent(fallback.getFallbackFloat("Weather_" + name + "_Clouds_Maximum_Percent")) +{ +/* +Unhandled: +Rain Diameter=600 ? +Rain Height Min=200 ? +Rain Height Max=700 ? +Rain Threshold=0.6 ? +Max Raindrops=650 ? +*/ +} + +float Weather::transitionSeconds() const +{ + // This formula is reversed from Morrowind by observing different Transition Delta values with Clouds + // Maximum Percent set to 1.0, and watching for when the light from the sun was no longer visible. + static const float deltasPerHour = 0.00835; + return (deltasPerHour / mTransitionDelta) * 60.0f * 60.0f; +} + +float Weather::cloudBlendFactor(float transitionRatio) const +{ + // Clouds Maximum Percent affects how quickly the sky transitions from one sky texture to the next. + return transitionRatio / mCloudsMaximumPercent; +} + MoonModel::MoonModel(const std::string& name, const MWWorld::Fallback& fallback) : mFadeInStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Start")) , mFadeInFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Finish")) @@ -206,80 +268,29 @@ inline float MoonModel::earlyMoonShadowAlpha(float angle) const return 0.0f; } -void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name) -{ - std::string upper=name; - upper[0]=toupper(name[0]); - weather.mCloudsMaximumPercent = mFallback->getFallbackFloat("Weather_"+upper+"_Clouds_Maximum_Percent"); - weather.mTransitionDelta = mFallback->getFallbackFloat("Weather_"+upper+"_Transition_Delta"); - weather.mSkySunriseColor=mFallback->getFallbackColour("Weather_"+upper+"_Sky_Sunrise_Color"); - weather.mSkyDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Day_Color"); - weather.mSkySunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Sunset_Color"); - weather.mSkyNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Night_Color"); - weather.mFogSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Sunrise_Color"); - weather.mFogDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Day_Color"); - weather.mFogSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Sunset_Color"); - weather.mFogNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Night_Color"); - weather.mAmbientSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Sunrise_Color"); - weather.mAmbientDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Day_Color"); - weather.mAmbientSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Sunset_Color"); - weather.mAmbientNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Night_Color"); - weather.mSunSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Sunrise_Color"); - weather.mSunDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Day_Color"); - weather.mSunSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Sunset_Color"); - weather.mSunNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Night_Color"); - weather.mSunDiscSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Disc_Sunset_Color"); - weather.mLandFogDayDepth = mFallback->getFallbackFloat("Weather_"+upper+"_Land_Fog_Day_Depth"); - weather.mLandFogNightDepth = mFallback->getFallbackFloat("Weather_"+upper+"_Land_Fog_Night_Depth"); - weather.mWindSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Wind_Speed"); - weather.mCloudSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Cloud_Speed"); - weather.mGlareView = mFallback->getFallbackFloat("Weather_"+upper+"_Glare_View"); - weather.mCloudTexture = mFallback->getFallbackString("Weather_"+upper+"_Cloud_Texture"); - - static const float fStromWindSpeed = mStore->get().find("fStromWindSpeed")->getFloat(); - - weather.mIsStorm = weather.mWindSpeed > fStromWindSpeed; - - bool usesPrecip = mFallback->getFallbackBool("Weather_"+upper+"_Using_Precip"); - if (usesPrecip) - weather.mRainEffect = "meshes\\raindrop.nif"; - weather.mRainSpeed = mRainSpeed; - weather.mRainFrequency = mFallback->getFallbackFloat("Weather_"+upper+"_Rain_Entrance_Speed"); - /* -Unhandled: -Rain Diameter=600 ? -Rain Height Min=200 ? -Rain Height Max=700 ? -Rain Threshold=0.6 ? -Max Raindrops=650 ? -*/ - - mWeatherSettings[name] = weather; -} - WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::Fallback* fallback, MWWorld::ESMStore* store) : - mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mFallback(fallback), mStore(store), + mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mStore(store), mRendering(rendering), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true), mRemainingTransitionTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0), mMasser("Masser", *fallback), mSecunda("Secunda", *fallback) { //Globals - mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); - mThunderSoundID1 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); - mThunderSoundID2 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); - mThunderSoundID3 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); - mSunriseTime = mFallback->getFallbackFloat("Weather_Sunrise_Time"); - mSunsetTime = mFallback->getFallbackFloat("Weather_Sunset_Time"); - mSunriseDuration = mFallback->getFallbackFloat("Weather_Sunrise_Duration"); - mSunsetDuration = mFallback->getFallbackFloat("Weather_Sunset_Duration"); - mHoursBetweenWeatherChanges = mFallback->getFallbackFloat("Weather_Hours_Between_Weather_Changes"); + mThunderSoundID0 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); + mThunderSoundID1 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); + mThunderSoundID2 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); + mThunderSoundID3 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); + mSunriseTime = fallback->getFallbackFloat("Weather_Sunrise_Time"); + mSunsetTime = fallback->getFallbackFloat("Weather_Sunset_Time"); + mSunriseDuration = fallback->getFallbackFloat("Weather_Sunrise_Duration"); + mSunsetDuration = fallback->getFallbackFloat("Weather_Sunset_Duration"); + mHoursBetweenWeatherChanges = fallback->getFallbackFloat("Weather_Hours_Between_Weather_Changes"); mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600; - mThunderFrequency = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); - mThunderThreshold = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); + mThunderFrequency = fallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); + mThunderThreshold = fallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); mThunderSoundDelay = 0.25; - mRainSpeed = mFallback->getFallbackFloat("Weather_Precip_Gravity"); + mRainSpeed = fallback->getFallbackFloat("Weather_Precip_Gravity"); //Some useful values /* TODO: Use pre-sunrise_time, pre-sunset_time, @@ -292,47 +303,16 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::F mDayStart = mSunriseTime + mSunriseDuration; mDayEnd = mSunsetTime; - //Weather - Weather clear; - setFallbackWeather(clear,"clear"); - - Weather cloudy; - setFallbackWeather(cloudy,"cloudy"); - - Weather foggy; - setFallbackWeather(foggy,"foggy"); - - Weather thunderstorm; - thunderstorm.mAmbientLoopSoundID = "rain heavy"; - thunderstorm.mRainEffect = "meshes\\raindrop.nif"; - setFallbackWeather(thunderstorm,"thunderstorm"); - - Weather rain; - rain.mAmbientLoopSoundID = "rain"; - rain.mRainEffect = "meshes\\raindrop.nif"; - setFallbackWeather(rain,"rain"); - - Weather overcast; - setFallbackWeather(overcast,"overcast"); - - Weather ashstorm; - ashstorm.mAmbientLoopSoundID = "ashstorm"; - ashstorm.mParticleEffect = "meshes\\ashcloud.nif"; - setFallbackWeather(ashstorm,"ashstorm"); - - Weather blight; - blight.mAmbientLoopSoundID = "blight"; - blight.mParticleEffect = "meshes\\blightcloud.nif"; - setFallbackWeather(blight,"blight"); - - Weather snow; - snow.mParticleEffect = "meshes\\snow.nif"; - setFallbackWeather(snow, "snow"); - - Weather blizzard; - blizzard.mAmbientLoopSoundID = "BM Blizzard"; - blizzard.mParticleEffect = "meshes\\blizzard.nif"; - setFallbackWeather(blizzard,"blizzard"); + addWeather("Clear", *fallback); + addWeather("Cloudy", *fallback); + addWeather("Foggy", *fallback); + addWeather("Overcast", *fallback); + addWeather("Rain", *fallback, "rain"); + addWeather("Thunderstorm", *fallback, "rain heavy"); + addWeather("Ashstorm", *fallback, "ashstorm", "meshes\\ashcloud.nif"); + addWeather("Blight", *fallback, "blight", "meshes\\blightcloud.nif"); + addWeather("Snow", *fallback, "", "meshes\\snow.nif"); + addWeather("Blizzard", *fallback, "BM Blizzard", "meshes\\blizzard.nif"); } WeatherManager::~WeatherManager() @@ -358,19 +338,19 @@ void WeatherManager::setWeather(const std::string& weather, bool instant) if (mNextWeather != "") { // transition more than 50% finished? - if (mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600) <= 0.5) + if (mRemainingTransitionTime / (findWeather(mCurrentWeather).transitionSeconds()) <= 0.5) mCurrentWeather = mNextWeather; } mNextWeather = weather; - mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600.f; + mRemainingTransitionTime = findWeather(mCurrentWeather).transitionSeconds(); } mFirstUpdate = false; } void WeatherManager::setResult(const std::string& weatherType) { - const Weather& current = mWeatherSettings[weatherType]; + const Weather& current = findWeather(weatherType); mResult.mCloudTexture = current.mCloudTexture; mResult.mCloudBlendFactor = 0; @@ -473,9 +453,11 @@ void WeatherManager::transition(float factor) setResult(mNextWeather); const MWRender::WeatherResult other = mResult; + const Weather& nextWeather = findWeather(mNextWeather); + mResult.mCloudTexture = current.mCloudTexture; mResult.mNextCloudTexture = other.mCloudTexture; - mResult.mCloudBlendFactor = factor; + mResult.mCloudBlendFactor = nextWeather.cloudBlendFactor(factor); mResult.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); mResult.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); @@ -547,7 +529,7 @@ void WeatherManager::update(float duration, bool paused) } if (mNextWeather != "") - transition(1 - (mRemainingTransitionTime / (mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600))); + transition(1 - (mRemainingTransitionTime / (findWeather(mCurrentWeather).transitionSeconds()))); else setResult(mCurrentWeather); @@ -945,3 +927,23 @@ void WeatherManager::advanceTime(double hours) { mTimePassed += hours*3600; } + +inline void WeatherManager::addWeather(const std::string& name, + const MWWorld::Fallback& fallback, + const std::string& ambientLoopSoundID, + const std::string& particleEffect) +{ + static const float fStromWindSpeed = mStore->get().find("fStromWindSpeed")->getFloat(); + + Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, ambientLoopSoundID, particleEffect); + + std::string lower = name; + lower[0] = tolower(lower[0]); + mWeatherSettings.insert(std::make_pair(lower, weather)); +} + +inline Weather& WeatherManager::findWeather(const std::string& name) +{ + return mWeatherSettings.at(name); +} + diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 7f4858bc8..710e45d9b 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -33,53 +33,55 @@ namespace MWWorld class Fallback; /// Defines a single weather setting (according to INI) - struct Weather + class Weather { + public: + Weather(const std::string& name, + const MWWorld::Fallback& fallback, + float stormWindSpeed, + float rainSpeed, + const std::string& ambientLoopSoundID, + const std::string& particleEffect); + std::string mCloudTexture; // Sky (atmosphere) colors - osg::Vec4f mSkySunriseColor, - mSkyDayColor, - mSkySunsetColor, - mSkyNightColor; + osg::Vec4f mSkySunriseColor; + osg::Vec4f mSkyDayColor; + osg::Vec4f mSkySunsetColor; + osg::Vec4f mSkyNightColor; // Fog colors - osg::Vec4f mFogSunriseColor, - mFogDayColor, - mFogSunsetColor, - mFogNightColor; + osg::Vec4f mFogSunriseColor; + osg::Vec4f mFogDayColor; + osg::Vec4f mFogSunsetColor; + osg::Vec4f mFogNightColor; // Ambient lighting colors - osg::Vec4f mAmbientSunriseColor, - mAmbientDayColor, - mAmbientSunsetColor, - mAmbientNightColor; + osg::Vec4f mAmbientSunriseColor; + osg::Vec4f mAmbientDayColor; + osg::Vec4f mAmbientSunsetColor; + osg::Vec4f mAmbientNightColor; // Sun (directional) lighting colors - osg::Vec4f mSunSunriseColor, - mSunDayColor, - mSunSunsetColor, - mSunNightColor; + osg::Vec4f mSunSunriseColor; + osg::Vec4f mSunDayColor; + osg::Vec4f mSunSunsetColor; + osg::Vec4f mSunNightColor; // Fog depth/density - float mLandFogDayDepth, - mLandFogNightDepth; + float mLandFogDayDepth; + float mLandFogNightDepth; // Color modulation for the sun itself during sunset (not completely sure) osg::Vec4f mSunDiscSunsetColor; - // Duration of weather transition (in days) - float mTransitionDelta; - // Used by scripts to animate signs, etc based on the wind (GetWindSpeed) float mWindSpeed; // Cloud animation speed multiplier float mCloudSpeed; - // TODO: What is this supposed to do? - float mCloudsMaximumPercent; - // Value between 0 and 1, defines the strength of the sun glare effect. // Also appears to modify how visible the sun, moons, and stars are for various weather effects. float mGlareView; @@ -107,6 +109,13 @@ namespace MWWorld // Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature // is broken in the vanilla game and was disabled. + + float transitionSeconds() const; + float cloudBlendFactor(float transitionRatio) const; + + private: + float mTransitionDelta; + float mCloudsMaximumPercent; }; class MoonModel @@ -197,9 +206,7 @@ namespace MWWorld MWBase::SoundPtr mAmbientSound; std::string mPlayingSoundID; - MWWorld::Fallback* mFallback; MWWorld::ESMStore* mStore; - void setFallbackWeather(Weather& weather,const std::string& name); MWRender::RenderingManager* mRendering; std::map mWeatherSettings; @@ -251,6 +258,13 @@ namespace MWWorld std::string mThunderSoundID3; MoonModel mMasser; MoonModel mSecunda; + + void addWeather(const std::string& name, + const MWWorld::Fallback& fallback, + const std::string& ambientLoopSoundID = "", + const std::string& particleEffect = ""); + + Weather& findWeather(const std::string& name); }; } From 5049c9ab6a85a58c0b56c2498ea55f36e359a397 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 16 Aug 2015 17:41:33 +1200 Subject: [PATCH 263/419] removed unnecessary tests. --- apps/openmw/mwmechanics/pathfinding.cpp | 32 ++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f469832a5..d8e6a37b7 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -25,8 +25,7 @@ namespace // int getClosestPoint(const ESM::Pathgrid* grid, const osg::Vec3f& pos) { - if(!grid || grid->mPoints.empty()) - return -1; + assert(grid && !grid->mPoints.empty()); float distanceBetween = distanceSquared(grid->mPoints[0], pos); int closestIndex = 0; @@ -228,21 +227,22 @@ namespace MWMechanics } mPath = mCell->aStarSearch(startNode, endNode.first); + assert(!mPath.empty()); - if(!mPath.empty()) - { - // Add the destination (which may be different to the closest - // pathgrid point). However only add if endNode was the closest - // point to endPoint. - // - // This logic can fail in the opposite situate, e.g. endPoint may - // have been reachable but happened to be very close to an - // unreachable pathgrid point. - // - // The AI routines will have to deal with such situations. - if(endNode.second) - mPath.push_back(endPoint); - } + // If endNode found is NOT the closest PathGrid point to the endPoint, + // assume endPoint is not reachable from endNode. In which case, + // path ends at endNode. + // + // So only add the destination (which may be different to the closest + // pathgrid point) when endNode was the closest point to endPoint. + // + // This logic can fail in the opposite situate, e.g. endPoint may + // have been reachable but happened to be very close to an + // unreachable pathgrid point. + // + // The AI routines will have to deal with such situations. + if(endNode.second) + mPath.push_back(endPoint); return; } From 942a987d528de8202e15c63607a20539675d3b85 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 16 Aug 2015 18:55:02 +1200 Subject: [PATCH 264/419] centralize the world/cell coordinate conversion logic. --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 13 ++---- .../mwmechanics/coordinateconverter.cpp | 43 +++++++++++++++++++ .../mwmechanics/coordinateconverter.hpp | 37 ++++++++++++++++ apps/openmw/mwmechanics/pathfinding.cpp | 24 +++++------ apps/openmw/mwmechanics/pathgrid.cpp | 20 ++------- apps/openmw/mwrender/pathgrid.cpp | 7 +-- 7 files changed, 99 insertions(+), 47 deletions(-) create mode 100644 apps/openmw/mwmechanics/coordinateconverter.cpp create mode 100644 apps/openmw/mwmechanics/coordinateconverter.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index cd1ac31ec..c33b711e6 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -82,7 +82,7 @@ add_openmw_dir (mwmechanics drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning - character actors objects aistate + character actors objects aistate coordinateconverter ) add_openmw_dir (mwstate diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 440814fb7..afe34218e 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -20,6 +20,7 @@ #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" +#include "coordinateconverter.hpp" @@ -587,11 +588,7 @@ namespace MWMechanics void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell) { - if (cell->isExterior()) - { - point.mX += cell->mData.mX * ESM::Land::REAL_SIZE; - point.mY += cell->mData.mY * ESM::Land::REAL_SIZE; - } + CoordinateConverter(cell).ToWorld(point); } void AiWander::trimAllowedNodes(std::vector& nodes, @@ -749,11 +746,7 @@ namespace MWMechanics { // get NPC's position in local (i.e. cell) co-ordinates osg::Vec3f npcPos(mInitialActorPosition); - if(cell->isExterior()) - { - npcPos[0] = npcPos[0] - static_cast(cell->mData.mX * ESM::Land::REAL_SIZE); - npcPos[1] = npcPos[1] - static_cast(cell->mData.mY * ESM::Land::REAL_SIZE); - } + CoordinateConverter(cell).ToLocal(npcPos); // mAllowedNodes for this actor with pathgrid point indexes based on mDistance // NOTE: mPoints and mAllowedNodes are in local co-ordinates diff --git a/apps/openmw/mwmechanics/coordinateconverter.cpp b/apps/openmw/mwmechanics/coordinateconverter.cpp new file mode 100644 index 000000000..583ac41c5 --- /dev/null +++ b/apps/openmw/mwmechanics/coordinateconverter.cpp @@ -0,0 +1,43 @@ +#include "coordinateconverter.hpp" + +#include +#include + +namespace MWMechanics +{ + CoordinateConverter::CoordinateConverter(const ESM::Cell* cell) + : mCellX(0), mCellY(0) + { + if (cell->isExterior()) + { + mCellX = cell->mData.mX * ESM::Land::REAL_SIZE; + mCellY = cell->mData.mY * ESM::Land::REAL_SIZE; + } + } + + void CoordinateConverter::ToWorld(ESM::Pathgrid::Point& point) + { + point.mX += mCellX; + point.mY += mCellY; + } + + void CoordinateConverter::ToWorld(osg::Vec3f& point) + { + point.x() += static_cast(mCellX); + point.y() += static_cast(mCellY); + } + + void CoordinateConverter::ToLocal(osg::Vec3f& point) + { + point.x() -= static_cast(mCellX); + point.y() -= static_cast(mCellY); + } + + osg::Vec3f CoordinateConverter::ToLocalVec3(const ESM::Pathgrid::Point& point) + { + return osg::Vec3f( + static_cast(point.mX - mCellX), + static_cast(point.mY - mCellY), + static_cast(point.mZ)); + } +} diff --git a/apps/openmw/mwmechanics/coordinateconverter.hpp b/apps/openmw/mwmechanics/coordinateconverter.hpp new file mode 100644 index 000000000..2c4d3d3ba --- /dev/null +++ b/apps/openmw/mwmechanics/coordinateconverter.hpp @@ -0,0 +1,37 @@ +#ifndef GAME_MWMECHANICS_COORDINATECONVERTER_H +#define GAME_MWMECHANICS_COORDINATECONVERTER_H + +#include +#include + +namespace ESM +{ + struct Cell; +} + +namespace MWMechanics +{ + /// \brief convert coordinates between world and local cell + class CoordinateConverter + { + public: + CoordinateConverter(const ESM::Cell* cell); + + /// in-place conversion from local to world + void ToWorld(ESM::Pathgrid::Point& point); + + /// in-place conversion from local to world + void ToWorld(osg::Vec3f& point); + + /// in-place conversion from world to local + void ToLocal(osg::Vec3f& point); + + osg::Vec3f ToLocalVec3(const ESM::Pathgrid::Point& point); + + private: + int mCellX; + int mCellY; + }; +} + +#endif diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index d8e6a37b7..1147371b1 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -5,6 +5,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "coordinateconverter.hpp" namespace { @@ -106,11 +107,6 @@ namespace MWMechanics return sqrt(x * x + y * y + z * z); } - osg::Vec3f ToLocalCoordinates(const ESM::Pathgrid::Point &point, float xCell, float yCell) - { - return osg::Vec3f(point.mX - xCell, point.mY - yCell, static_cast(point.mZ)); - } - PathFinder::PathFinder() : mPathgrid(NULL), mCell(NULL) @@ -194,23 +190,17 @@ namespace MWMechanics } // NOTE: getClosestPoint expects local co-ordinates - float xCell = 0; - float yCell = 0; - if (mCell->isExterior()) - { - xCell = static_cast(mCell->getCell()->mData.mX * ESM::Land::REAL_SIZE); - yCell = static_cast(mCell->getCell()->mData.mY * ESM::Land::REAL_SIZE); - } + CoordinateConverter converter(mCell->getCell()); // NOTE: It is possible that getClosestPoint returns a pathgrind point index // that is unreachable in some situations. e.g. actor is standing // outside an area enclosed by walls, but there is a pathgrid // point right behind the wall that is closer than any pathgrid // point outside the wall - osg::Vec3f startPointInLocalCoords(ToLocalCoordinates(startPoint, xCell, yCell)); + osg::Vec3f startPointInLocalCoords(converter.ToLocalVec3(startPoint)); int startNode = getClosestPoint(mPathgrid, startPointInLocalCoords); - osg::Vec3f endPointInLocalCoords(ToLocalCoordinates(endPoint, xCell, yCell)); + osg::Vec3f endPointInLocalCoords(converter.ToLocalVec3(endPoint)); std::pair endNode = getClosestReachablePoint(mPathgrid, cell, endPointInLocalCoords, startNode); @@ -229,6 +219,12 @@ namespace MWMechanics mPath = mCell->aStarSearch(startNode, endNode.first); assert(!mPath.empty()); + // convert supplied path to world co-ordinates + for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) + { + converter.ToWorld(*iter); + } + // If endNode found is NOT the closest PathGrid point to the endPoint, // assume endPoint is not reachable from endNode. In which case, // path ends at endNode. diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 66af864ea..871baecdc 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -312,29 +312,15 @@ namespace MWMechanics if(current != goal) return path; // for some reason couldn't build a path - // reconstruct path to return, using world co-ordinates - int xCell = 0; - int yCell = 0; - if (mIsExterior) - { - xCell = mPathgrid->mData.mX * ESM::Land::REAL_SIZE; - yCell = mPathgrid->mData.mY * ESM::Land::REAL_SIZE; - } - + // reconstruct path to return, using local co-ordinates while(graphParent[current] != -1) { - ESM::Pathgrid::Point pt = mPathgrid->mPoints[current]; - pt.mX += xCell; - pt.mY += yCell; - path.push_front(pt); + path.push_front(mPathgrid->mPoints[current]); current = graphParent[current]; } // add first node to path explicitly - ESM::Pathgrid::Point pt = mPathgrid->mPoints[start]; - pt.mX += xCell; - pt.mY += yCell; - path.push_front(pt); + path.push_front(mPathgrid->mPoints[start]); return path; } } diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index 9fffd76d1..bd22446de 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -17,6 +17,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/pathfinding.hpp" +#include "../mwmechanics/coordinateconverter.hpp" #include "vismask.hpp" @@ -207,11 +208,7 @@ void Pathgrid::enableCellPathgrid(const MWWorld::CellStore *store) if (!pathgrid) return; osg::Vec3f cellPathGridPos(0, 0, 0); - if (store->getCell()->isExterior()) - { - cellPathGridPos.x() = static_cast(store->getCell()->mData.mX * ESM::Land::REAL_SIZE); - cellPathGridPos.y() = static_cast(store->getCell()->mData.mY * ESM::Land::REAL_SIZE); - } + MWMechanics::CoordinateConverter(store->getCell()).ToWorld(cellPathGridPos); osg::ref_ptr cellPathGrid = new osg::PositionAttitudeTransform; cellPathGrid->setPosition(cellPathGridPos); From 4d9d8a060d6821744e03ea5ddbfcd298885219c2 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 16 Aug 2015 18:56:28 +1200 Subject: [PATCH 265/419] Pathing bugfix. When path contains one one point from path grid, point is no longer being discarded. --- apps/openmw/mwmechanics/pathfinding.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 1147371b1..777ccacae 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -212,6 +212,10 @@ namespace MWMechanics // nodes are the same if(startNode == endNode.first) { + ESM::Pathgrid::Point temp(mPathgrid->mPoints[startNode]); + converter.ToWorld(temp); + mPath.push_back(temp); + mPath.push_back(endPoint); return; } From 1b663f01aff94811a46825467cad8f38ed025b24 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 16 Aug 2015 15:24:48 +0200 Subject: [PATCH 266/419] create merged document and open a view for it (document is still empty at this point) --- apps/opencs/CMakeLists.txt | 8 +++++-- apps/opencs/editor.cpp | 3 ++- apps/opencs/model/doc/document.cpp | 4 +++- apps/opencs/model/doc/document.hpp | 6 ++++- apps/opencs/model/doc/documentmanager.cpp | 16 ++++++++++++- apps/opencs/model/doc/documentmanager.hpp | 13 +++++++++++ apps/opencs/model/doc/operation.hpp | 4 +++- apps/opencs/model/tools/mergeoperation.cpp | 19 ++++++++++++---- apps/opencs/model/tools/mergeoperation.hpp | 19 ++++++++++++++-- apps/opencs/model/tools/mergestages.cpp | 18 +++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 26 ++++++++++++++++++++++ apps/opencs/model/tools/mergestate.hpp | 20 +++++++++++++++++ apps/opencs/model/tools/tools.cpp | 4 +++- apps/opencs/model/tools/tools.hpp | 7 +++++- apps/opencs/view/tools/merge.cpp | 13 ++++++++--- apps/opencs/view/tools/merge.hpp | 4 +++- 16 files changed, 165 insertions(+), 19 deletions(-) create mode 100644 apps/opencs/model/tools/mergestages.cpp create mode 100644 apps/opencs/model/tools/mergestages.hpp create mode 100644 apps/opencs/model/tools/mergestate.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 833ca6551..091b566d1 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,14 +35,18 @@ opencs_hdrs_noqt (model/world opencs_units (model/tools - tools reportmodel + tools reportmodel mergeoperation ) opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck - mergeoperation + mergestages + ) + +opencs_hdrs_noqt (model/tools + mergestate ) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 0b385f275..7f9e2746e 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -21,7 +21,8 @@ CS::Editor::Editor () : mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), mViewManager (mDocumentManager), mPid(""), - mLock(), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) + mLock(), mMerge (mDocumentManager), + mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) { std::pair > config = readConfig(); diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index a331706bc..67ecbd641 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2294,6 +2294,8 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int))); connect (&mTools, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool))); + connect (&mTools, SIGNAL (mergeDone (CSMDoc::Document*)), + this, SIGNAL (mergeDone (CSMDoc::Document*))); connect (&mSaving, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int))); connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool))); @@ -2388,7 +2390,7 @@ void CSMDoc::Document::runSearch (const CSMWorld::UniversalId& searchId, const C emit stateChanged (getState(), this); } -void CSMDoc::Document::runMerge (const boost::filesystem::path& target) +void CSMDoc::Document::runMerge (std::auto_ptr target) { mTools.runMerge (target); emit stateChanged (getState(), this); diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 901a8e3e4..3eaa5bb14 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -130,7 +130,7 @@ namespace CSMDoc void runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search); - void runMerge (const boost::filesystem::path& target); + void runMerge (std::auto_ptr target); void abortOperation (int type); @@ -158,6 +158,10 @@ namespace CSMDoc void progress (int current, int max, int type, int threads, CSMDoc::Document *document); + /// \attention When this signal is emitted, *this hands over the ownership of the + /// document. This signal must be handled to avoid a leak. + void mergeDone (CSMDoc::Document *document); + private slots: void modificationStateChanged (bool clean); diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 02d4ab5c0..03758dc6a 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -57,10 +57,24 @@ bool CSMDoc::DocumentManager::isEmpty() void CSMDoc::DocumentManager::addDocument (const std::vector& files, const boost::filesystem::path& savePath, bool new_) { - Document *document = new Document (mVFS, mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts); + Document *document = makeDocument (files, savePath, new_); + insertDocument (document); +} +CSMDoc::Document *CSMDoc::DocumentManager::makeDocument ( + const std::vector< boost::filesystem::path >& files, + const boost::filesystem::path& savePath, bool new_) +{ + return new Document (mVFS, mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts); +} + +void CSMDoc::DocumentManager::insertDocument (CSMDoc::Document *document) +{ mDocuments.push_back (document); + connect (document, SIGNAL (mergeDone (CSMDoc::Document*)), + this, SLOT (insertDocument (CSMDoc::Document*))); + emit loadRequest (document); mLoader.hasThingsToDo().wakeAll(); diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index f9b18bfe6..4f6b2b2c9 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -56,6 +56,15 @@ namespace CSMDoc ///< \param new_ Do not load the last content file in \a files and instead create in an /// appropriate way. + /// Create a new document. The ownership of the created document is transferred to + /// the calling function. The DocumentManager does not manage it. Loading has not + /// taken place at the point when the document is returned. + /// + /// \param new_ Do not load the last content file in \a files and instead create in an + /// appropriate way. + Document *makeDocument (const std::vector< boost::filesystem::path >& files, + const boost::filesystem::path& savePath, bool new_); + void setResourceDir (const boost::filesystem::path& parResDir); void setEncoding (ToUTF8::FromType encoding); @@ -84,6 +93,10 @@ namespace CSMDoc void removeDocument (CSMDoc::Document *document); ///< Emits the lastDocumentDeleted signal, if applicable. + /// Hand over document to *this. The ownership is transferred. The DocumentManager + /// will initiate the load procedure, if necessary + void insertDocument (CSMDoc::Document *document); + signals: void documentAdded (CSMDoc::Document *document); diff --git a/apps/opencs/model/doc/operation.hpp b/apps/opencs/model/doc/operation.hpp index 703f9d44b..3c86a6e23 100644 --- a/apps/opencs/model/doc/operation.hpp +++ b/apps/opencs/model/doc/operation.hpp @@ -83,7 +83,9 @@ namespace CSMDoc void executeStage(); - void operationDone(); + protected slots: + + virtual void operationDone(); }; } diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 65cfdb4ff..c93452dad 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -2,14 +2,25 @@ #include "mergeoperation.hpp" #include "../doc/state.hpp" +#include "../doc/document.hpp" + +#include "mergestages.hpp" CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document) -: CSMDoc::Operation (CSMDoc::State_Merging, true) +: CSMDoc::Operation (CSMDoc::State_Merging, true), mState (document) { - + appendStage (new FinishMergedDocumentStage (mState)); } -void CSMTools::MergeOperation::setTarget (const boost::filesystem::path& target) +void CSMTools::MergeOperation::setTarget (std::auto_ptr document) { - + mState.mTarget = document; +} + +void CSMTools::MergeOperation::operationDone() +{ + CSMDoc::Operation::operationDone(); + + if (mState.mCompleted) + emit mergeDone (mState.mTarget.release()); } diff --git a/apps/opencs/model/tools/mergeoperation.hpp b/apps/opencs/model/tools/mergeoperation.hpp index 84526b2f2..dc958d31b 100644 --- a/apps/opencs/model/tools/mergeoperation.hpp +++ b/apps/opencs/model/tools/mergeoperation.hpp @@ -1,10 +1,12 @@ #ifndef CSM_TOOLS_MERGEOPERATION_H #define CSM_TOOLS_MERGEOPERATION_H -#include +#include #include "../doc/operation.hpp" +#include "mergestate.hpp" + namespace CSMDoc { class Document; @@ -14,14 +16,27 @@ namespace CSMTools { class MergeOperation : public CSMDoc::Operation { + Q_OBJECT + MergeState mState; public: MergeOperation (CSMDoc::Document& document); /// \attention Do not call this function while a merge is running. - void setTarget (const boost::filesystem::path& target); + void setTarget (std::auto_ptr document); + + protected slots: + + virtual void operationDone(); + + signals: + + /// \attention When this signal is emitted, *this hands over the ownership of the + /// document. This signal must be handled to avoid a leak. + void mergeDone (CSMDoc::Document *document); + }; } diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp new file mode 100644 index 000000000..16ea0495a --- /dev/null +++ b/apps/opencs/model/tools/mergestages.cpp @@ -0,0 +1,18 @@ + +#include "mergestages.hpp" + +#include "mergestate.hpp" + +CSMTools::FinishMergedDocumentStage::FinishMergedDocumentStage (MergeState& state) +: mState (state) +{} + +int CSMTools::FinishMergedDocumentStage::setup() +{ + return 1; +} + +void CSMTools::FinishMergedDocumentStage::perform (int stage, CSMDoc::Messages& messages) +{ + mState.mCompleted = true; +} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp new file mode 100644 index 000000000..138b89d72 --- /dev/null +++ b/apps/opencs/model/tools/mergestages.hpp @@ -0,0 +1,26 @@ +#ifndef CSM_TOOLS_MERGESTAGES_H +#define CSM_TOOLS_MERGESTAGES_H + +#include "../doc/stage.hpp" + +namespace CSMTools +{ + struct MergeState; + + class FinishMergedDocumentStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + FinishMergedDocumentStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/mergestate.hpp b/apps/opencs/model/tools/mergestate.hpp new file mode 100644 index 000000000..4482ba6f4 --- /dev/null +++ b/apps/opencs/model/tools/mergestate.hpp @@ -0,0 +1,20 @@ +#ifndef CSM_TOOLS_MERGESTATE_H +#define CSM_TOOLS_MERGESTATE_H + +#include + +#include "../doc/document.hpp" + +namespace CSMTools +{ + struct MergeState + { + std::auto_ptr mTarget; + CSMDoc::Document& mSource; + bool mCompleted; + + MergeState (CSMDoc::Document& source) : mSource (source), mCompleted (false) {} + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 681f74404..78b052813 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -195,7 +195,7 @@ void CSMTools::Tools::runSearch (const CSMWorld::UniversalId& searchId, const Se mSearch.start(); } -void CSMTools::Tools::runMerge (const boost::filesystem::path& target) +void CSMTools::Tools::runMerge (std::auto_ptr target) { // not setting an active report, because merge does not produce messages @@ -203,6 +203,8 @@ void CSMTools::Tools::runMerge (const boost::filesystem::path& target) { mMergeOperation = new MergeOperation (mDocument); mMerge.setOperation (mMergeOperation); + connect (mMergeOperation, SIGNAL (mergeDone (CSMDoc::Document*)), + this, SIGNAL (mergeDone (CSMDoc::Document*))); } mMergeOperation->setTarget (target); diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 952099928..2302fe2e0 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -1,6 +1,7 @@ #ifndef CSM_TOOLS_TOOLS_H #define CSM_TOOLS_TOOLS_H +#include #include #include @@ -73,7 +74,7 @@ namespace CSMTools void runSearch (const CSMWorld::UniversalId& searchId, const Search& search); - void runMerge (const boost::filesystem::path& target); + void runMerge (std::auto_ptr target); void abortOperation (int type); ///< \attention The operation is not aborted immediately. @@ -92,6 +93,10 @@ namespace CSMTools void progress (int current, int max, int type); void done (int type, bool failed); + + /// \attention When this signal is emitted, *this hands over the ownership of the + /// document. This signal must be handled to avoid a leak. + void mergeDone (CSMDoc::Document *document); }; } diff --git a/apps/opencs/view/tools/merge.cpp b/apps/opencs/view/tools/merge.cpp index f775390ee..566a5ee06 100644 --- a/apps/opencs/view/tools/merge.cpp +++ b/apps/opencs/view/tools/merge.cpp @@ -10,6 +10,7 @@ #include #include "../../model/doc/document.hpp" +#include "../../model/doc/documentmanager.hpp" #include "../doc/filewidget.hpp" #include "../doc/adjusterwidget.hpp" @@ -25,8 +26,8 @@ void CSVTools::Merge::keyPressEvent (QKeyEvent *event) QWidget::keyPressEvent (event); } -CSVTools::Merge::Merge (QWidget *parent) -: QWidget (parent), mDocument (0) +CSVTools::Merge::Merge (CSMDoc::DocumentManager& documentManager, QWidget *parent) +: QWidget (parent), mDocument (0), mDocumentManager (documentManager) { setWindowTitle ("Merge Content Files into a new Game File"); @@ -124,7 +125,13 @@ void CSVTools::Merge::accept() { if ((mDocument->getState() & CSMDoc::State_Merging)==0) { - mDocument->runMerge (mAdjuster->getPath()); + std::vector< boost::filesystem::path > files (1, mAdjuster->getPath()); + + std::auto_ptr target ( + mDocumentManager.makeDocument (files, files[0], true)); + + mDocument->runMerge (target); + hide(); } } diff --git a/apps/opencs/view/tools/merge.hpp b/apps/opencs/view/tools/merge.hpp index b8369ffa3..d4ed7e34b 100644 --- a/apps/opencs/view/tools/merge.hpp +++ b/apps/opencs/view/tools/merge.hpp @@ -11,6 +11,7 @@ class QListWidget; namespace CSMDoc { class Document; + class DocumentManager; } namespace CSVDoc @@ -30,12 +31,13 @@ namespace CSVTools QListWidget *mFiles; CSVDoc::FileWidget *mNewFile; CSVDoc::AdjusterWidget *mAdjuster; + CSMDoc::DocumentManager& mDocumentManager; void keyPressEvent (QKeyEvent *event); public: - Merge (QWidget *parent = 0); + Merge (CSMDoc::DocumentManager& documentManager, QWidget *parent = 0); /// Configure dialogue for a new merge void configure (CSMDoc::Document *document); From c8d6679a25130a3085a8563c3d7411aa46ead54c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 17:40:20 +0200 Subject: [PATCH 267/419] Remove an unused function --- apps/openmw/mwgui/sortfilteritemmodel.cpp | 4 ---- apps/openmw/mwgui/sortfilteritemmodel.hpp | 2 -- 2 files changed, 6 deletions(-) diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 183ab07ff..1d086f2ee 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -71,7 +71,6 @@ namespace MWGui SortFilterItemModel::SortFilterItemModel(ItemModel *sourceModel) : mCategory(Category_All) , mFilter(0) - , mShowEquipped(true) , mSortByType(true) { mSourceModel = sourceModel; @@ -91,9 +90,6 @@ namespace MWGui { MWWorld::Ptr base = item.mBase; - if (item.mType == ItemStack::Type_Equipped && !mShowEquipped) - return false; - int category = 0; if (base.getTypeName() == typeid(ESM::Armor).name() || base.getTypeName() == typeid(ESM::Clothing).name()) diff --git a/apps/openmw/mwgui/sortfilteritemmodel.hpp b/apps/openmw/mwgui/sortfilteritemmodel.hpp index 1b68bdd4f..064f62e77 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.hpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.hpp @@ -24,7 +24,6 @@ namespace MWGui void setCategory (int category); void setFilter (int filter); - void setShowEquipped (bool show) { mShowEquipped = show; } /// Use ItemStack::Type for sorting? void setSortByType(bool sort) { mSortByType = sort; } @@ -49,7 +48,6 @@ namespace MWGui int mCategory; int mFilter; - bool mShowEquipped; bool mSortByType; }; From 9fad33cd14b33c7fde4523a1189801b7e6689e1b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 17:49:37 +0200 Subject: [PATCH 268/419] Don't reset the item model's sort/filter options in updatePlayer (Fixes #2863) --- apps/openmw/mwgui/inventorywindow.cpp | 7 ++++++- apps/openmw/mwgui/itemmodel.cpp | 19 +++++++++++++++++++ apps/openmw/mwgui/itemmodel.hpp | 4 ++++ apps/openmw/mwgui/itemview.cpp | 4 ++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 9c9138ed5..580e583c9 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -119,7 +119,12 @@ namespace MWGui { mPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); mTradeModel = new TradeItemModel(new InventoryItemModel(mPtr), MWWorld::Ptr()); - mSortModel = new SortFilterItemModel(mTradeModel); + + if (mSortModel) // reuse existing SortModel when possible to keep previous category/filter settings + mSortModel->setSourceModel(mTradeModel); + else + mSortModel = new SortFilterItemModel(mTradeModel); + mItemView->setModel(mSortModel); mPreview->updatePtr(mPtr); diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 9fce6e84d..a1e36bce6 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -120,6 +120,11 @@ namespace MWGui } + ProxyItemModel::ProxyItemModel() + : mSourceModel(NULL) + { + } + ProxyItemModel::~ProxyItemModel() { delete mSourceModel; @@ -164,4 +169,18 @@ namespace MWGui return mSourceModel->getIndex(item); } + void ProxyItemModel::setSourceModel(ItemModel *sourceModel) + { + if (mSourceModel == sourceModel) + return; + + if (mSourceModel) + { + delete mSourceModel; + mSourceModel = NULL; + } + + mSourceModel = sourceModel; + } + } diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index 53c7018e2..2019c1042 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -80,11 +80,15 @@ namespace MWGui class ProxyItemModel : public ItemModel { public: + ProxyItemModel(); virtual ~ProxyItemModel(); virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); virtual ModelIndex getIndex (ItemStack item); + /// @note Takes ownership of the passed pointer. + void setSourceModel(ItemModel* sourceModel); + ModelIndex mapToSource (ModelIndex index); ModelIndex mapFromSource (ModelIndex index); protected: diff --git a/apps/openmw/mwgui/itemview.cpp b/apps/openmw/mwgui/itemview.cpp index df44eb33c..2cdfcada4 100644 --- a/apps/openmw/mwgui/itemview.cpp +++ b/apps/openmw/mwgui/itemview.cpp @@ -30,8 +30,12 @@ ItemView::~ItemView() void ItemView::setModel(ItemModel *model) { + if (mModel == model) + return; + delete mModel; mModel = model; + update(); } From 47dd9505a9464dc5c947f409c3c4a80cf4d8e395 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 16 Aug 2015 18:27:17 +0200 Subject: [PATCH 269/419] copy meta data from game file when merging --- apps/opencs/model/doc/document.cpp | 2 +- apps/opencs/model/tools/mergeoperation.cpp | 4 ++-- apps/opencs/model/tools/mergeoperation.hpp | 4 +++- apps/opencs/model/tools/mergestages.cpp | 27 ++++++++++++++++++++-- apps/opencs/model/tools/mergestages.hpp | 5 +++- apps/opencs/model/tools/tools.cpp | 6 ++--- apps/opencs/model/tools/tools.hpp | 5 +++- apps/opencs/model/world/data.cpp | 10 ++++++-- apps/opencs/model/world/data.hpp | 2 ++ 9 files changed, 52 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 67ecbd641..8d5580bcf 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2250,7 +2250,7 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager, const std::vector& blacklistedScripts) : mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager), - mTools (*this), + mTools (*this, encoding), mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), mSavingOperation (*this, mProjectPath, encoding), diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index c93452dad..9e5fb2745 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -6,10 +6,10 @@ #include "mergestages.hpp" -CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document) +CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::FromType encoding) : CSMDoc::Operation (CSMDoc::State_Merging, true), mState (document) { - appendStage (new FinishMergedDocumentStage (mState)); + appendStage (new FinishMergedDocumentStage (mState, encoding)); } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergeoperation.hpp b/apps/opencs/model/tools/mergeoperation.hpp index dc958d31b..bdaeb2ccd 100644 --- a/apps/opencs/model/tools/mergeoperation.hpp +++ b/apps/opencs/model/tools/mergeoperation.hpp @@ -3,6 +3,8 @@ #include +#include + #include "../doc/operation.hpp" #include "mergestate.hpp" @@ -22,7 +24,7 @@ namespace CSMTools public: - MergeOperation (CSMDoc::Document& document); + MergeOperation (CSMDoc::Document& document, ToUTF8::FromType encoding); /// \attention Do not call this function while a merge is running. void setTarget (std::auto_ptr document); diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 16ea0495a..776808b26 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -3,8 +3,11 @@ #include "mergestate.hpp" -CSMTools::FinishMergedDocumentStage::FinishMergedDocumentStage (MergeState& state) -: mState (state) +#include "../doc/document.hpp" +#include "../world/data.hpp" + +CSMTools::FinishMergedDocumentStage::FinishMergedDocumentStage (MergeState& state, ToUTF8::FromType encoding) +: mState (state), mEncoder (encoding) {} int CSMTools::FinishMergedDocumentStage::setup() @@ -14,5 +17,25 @@ int CSMTools::FinishMergedDocumentStage::setup() void CSMTools::FinishMergedDocumentStage::perform (int stage, CSMDoc::Messages& messages) { + // We know that the content file list contains at least two entries and that the first one + // does exist on disc (otherwise it would have been impossible to initiate a merge on that + // document). + boost::filesystem::path path = mState.mSource.getContentFiles()[0]; + + ESM::ESMReader reader; + reader.setEncoder (&mEncoder); + reader.open (path.string()); + + CSMWorld::MetaData source; + source.mId = "sys::meta"; + source.load (reader); + + CSMWorld::MetaData target = mState.mTarget->getData().getMetaData(); + + target.mAuthor = source.mAuthor; + target.mDescription = source.mDescription; + + mState.mTarget->getData().setMetaData (target); + mState.mCompleted = true; } diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 138b89d72..9844feaca 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -1,6 +1,8 @@ #ifndef CSM_TOOLS_MERGESTAGES_H #define CSM_TOOLS_MERGESTAGES_H +#include + #include "../doc/stage.hpp" namespace CSMTools @@ -10,10 +12,11 @@ namespace CSMTools class FinishMergedDocumentStage : public CSMDoc::Stage { MergeState& mState; + ToUTF8::Utf8Encoder mEncoder; public: - FinishMergedDocumentStage (MergeState& state); + FinishMergedDocumentStage (MergeState& state, ToUTF8::FromType encoding); virtual int setup(); ///< \return number of steps diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 78b052813..c4ff6868b 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -116,9 +116,9 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() return &mVerifier; } -CSMTools::Tools::Tools (CSMDoc::Document& document) +CSMTools::Tools::Tools (CSMDoc::Document& document, ToUTF8::FromType encoding) : mDocument (document), mData (document.getData()), mVerifierOperation (0), - mSearchOperation (0), mMergeOperation (0), mNextReportNumber (0) + mSearchOperation (0), mMergeOperation (0), mNextReportNumber (0), mEncoding (encoding) { // index 0: load error log mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); @@ -201,7 +201,7 @@ void CSMTools::Tools::runMerge (std::auto_ptr target) if (!mMergeOperation) { - mMergeOperation = new MergeOperation (mDocument); + mMergeOperation = new MergeOperation (mDocument, mEncoding); mMerge.setOperation (mMergeOperation); connect (mMergeOperation, SIGNAL (mergeDone (CSMDoc::Document*)), this, SIGNAL (mergeDone (CSMDoc::Document*))); diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 2302fe2e0..e16a3854c 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include @@ -44,6 +46,7 @@ namespace CSMTools std::map mReports; int mNextReportNumber; std::map mActiveReports; // type, report number + ToUTF8::FromType mEncoding; // not implemented Tools (const Tools&); @@ -59,7 +62,7 @@ namespace CSMTools public: - Tools (CSMDoc::Document& document); + Tools (CSMDoc::Document& document, ToUTF8::FromType encoding); virtual ~Tools(); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 3714117b6..d8999d950 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -483,7 +483,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mMetaData.addColumn (new FormatColumn); mMetaData.addColumn (new AuthorColumn); mMetaData.addColumn (new FileDescriptionColumn); - + addModel (new IdTable (&mGlobals), UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skill); @@ -828,6 +828,12 @@ const CSMWorld::MetaData& CSMWorld::Data::getMetaData() const return mMetaData.getRecord (0).get(); } +void CSMWorld::Data::setMetaData (const MetaData& metaData) +{ + Record record (RecordBase::State_ModifiedOnly, 0, &metaData); + mMetaData.setRecord (0, record); +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -880,7 +886,7 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base mMetaData.setRecord (0, Record (RecordBase::State_ModifiedOnly, 0, &metaData)); } - + return mReader->getRecordCount(); } diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 06f76607f..5706b005b 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -255,6 +255,8 @@ namespace CSMWorld const MetaData& getMetaData() const; + void setMetaData (const MetaData& metaData); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// From d1e1c0f38bfd2f94b6120571bb49ead59e298e87 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Aug 2015 23:42:08 +0200 Subject: [PATCH 270/419] Editor: fix a typo in ESM::Light flag mappings --- apps/opencs/model/world/refidcollection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 16da4aad9..85ddbacdb 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -380,7 +380,7 @@ CSMWorld::RefIdCollection::RefIdCollection() { Columns::ColumnId_Portable, ESM::Light::Carry }, { Columns::ColumnId_NegativeLight, ESM::Light::Negative }, { Columns::ColumnId_Flickering, ESM::Light::Flicker }, - { Columns::ColumnId_SlowFlickering, ESM::Light::Flicker }, + { Columns::ColumnId_SlowFlickering, ESM::Light::FlickerSlow }, { Columns::ColumnId_Pulsing, ESM::Light::Pulse }, { Columns::ColumnId_SlowPulsing, ESM::Light::PulseSlow }, { Columns::ColumnId_Fire, ESM::Light::Fire }, From be7bd9529d312c64de2c5d1329dfbe8caefc02e8 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sun, 16 Aug 2015 16:56:44 -0500 Subject: [PATCH 271/419] Classes shouldn't use MWBase::Environment to access their own members. --- apps/openmw/engine.cpp | 74 +++++++++---------- .../mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 6 +- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 8d25a923f..95851b75f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -66,7 +66,7 @@ namespace void OMW::Engine::executeLocalScripts() { - MWWorld::LocalScripts& localScripts = MWBase::Environment::get().getWorld()->getLocalScripts(); + MWWorld::LocalScripts& localScripts = mEnvironment.getWorld()->getLocalScripts(); localScripts.startIteration(); @@ -76,7 +76,7 @@ void OMW::Engine::executeLocalScripts() MWScript::InterpreterContext interpreterContext ( &script.second.getRefData().getLocals(), script.second); - MWBase::Environment::get().getScriptManager()->run (script.first, interpreterContext); + mEnvironment.getScriptManager()->run (script.first, interpreterContext); } localScripts.setIgnore (MWWorld::Ptr()); @@ -90,7 +90,7 @@ void OMW::Engine::frame(float frametime) mEnvironment.setFrameDuration (frametime); // update input - MWBase::Environment::get().getInputManager()->update(frametime, false); + mEnvironment.getInputManager()->update(frametime, false); // When the window is minimized, pause everything. Currently this *has* to be here to work around a MyGUI bug. // If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures. @@ -99,76 +99,76 @@ void OMW::Engine::frame(float frametime) // sound if (mUseSound) - MWBase::Environment::get().getSoundManager()->update(frametime); + mEnvironment.getSoundManager()->update(frametime); // Main menu opened? Then scripts are also paused. - bool paused = MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu); + bool paused = mEnvironment.getWindowManager()->containsMode(MWGui::GM_MainMenu); // update game state - MWBase::Environment::get().getStateManager()->update (frametime); + mEnvironment.getStateManager()->update (frametime); - bool guiActive = MWBase::Environment::get().getWindowManager()->isGuiMode(); + bool guiActive = mEnvironment.getWindowManager()->isGuiMode(); osg::Timer_t beforeScriptTick = osg::Timer::instance()->tick(); - if (MWBase::Environment::get().getStateManager()->getState()== + if (mEnvironment.getStateManager()->getState()== MWBase::StateManager::State_Running) { if (!paused) { - if (MWBase::Environment::get().getWorld()->getScriptsEnabled()) + if (mEnvironment.getWorld()->getScriptsEnabled()) { // local scripts executeLocalScripts(); // global scripts - MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); + mEnvironment.getScriptManager()->getGlobalScripts().run(); } - MWBase::Environment::get().getWorld()->markCellAsUnchanged(); + mEnvironment.getWorld()->markCellAsUnchanged(); } if (!guiActive) - MWBase::Environment::get().getWorld()->advanceTime( - frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); + mEnvironment.getWorld()->advanceTime( + frametime*mEnvironment.getWorld()->getTimeScaleFactor()/3600); } osg::Timer_t afterScriptTick = osg::Timer::instance()->tick(); // update actors osg::Timer_t beforeMechanicsTick = osg::Timer::instance()->tick(); - if (MWBase::Environment::get().getStateManager()->getState()!= + if (mEnvironment.getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { - MWBase::Environment::get().getMechanicsManager()->update(frametime, + mEnvironment.getMechanicsManager()->update(frametime, guiActive); } osg::Timer_t afterMechanicsTick = osg::Timer::instance()->tick(); - if (MWBase::Environment::get().getStateManager()->getState()== + if (mEnvironment.getStateManager()->getState()== MWBase::StateManager::State_Running) { MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr(); if(!guiActive && player.getClass().getCreatureStats(player).isDead()) - MWBase::Environment::get().getStateManager()->endGame(); + mEnvironment.getStateManager()->endGame(); } // update world osg::Timer_t beforePhysicsTick = osg::Timer::instance()->tick();; - if (MWBase::Environment::get().getStateManager()->getState()!= + if (mEnvironment.getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { - MWBase::Environment::get().getWorld()->update(frametime, guiActive); + mEnvironment.getWorld()->update(frametime, guiActive); } osg::Timer_t afterPhysicsTick = osg::Timer::instance()->tick(); // update GUI - MWBase::Environment::get().getWindowManager()->onFrame(frametime); - if (MWBase::Environment::get().getStateManager()->getState()!= + mEnvironment.getWindowManager()->onFrame(frametime); + if (mEnvironment.getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { #if 0 - MWBase::Environment::get().getWindowManager()->wmUpdateFps(fps); + mEnvironment.getWindowManager()->wmUpdateFps(fps); #endif - MWBase::Environment::get().getWindowManager()->update(); + mEnvironment.getWindowManager()->update(); } int frameNumber = mViewer->getFrameStamp()->getFrameNumber(); @@ -511,7 +511,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setWorld( new MWWorld::World (mViewer, rootNode, mResourceSystem.get(), mFileCollections, mContentFiles, mEncoder, mFallbackMap, mActivationDistanceOverride, mCellName, mStartupScript)); - MWBase::Environment::get().getWorld()->setupPlayer(); + mEnvironment.getWorld()->setupPlayer(); input->setPlayer(&mEnvironment.getWorld()->getPlayer()); window->initUI(); @@ -528,7 +528,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mScriptContext = new MWScript::CompilerContext (MWScript::CompilerContext::Type_Full); mScriptContext->setExtensions (&mExtensions); - mEnvironment.setScriptManager (new MWScript::ScriptManager (MWBase::Environment::get().getWorld()->getStore(), + mEnvironment.setScriptManager (new MWScript::ScriptManager (mEnvironment.getWorld()->getStore(), mVerboseScripts, *mScriptContext, mWarningsMode, mScriptBlacklistUse ? mScriptBlacklist : std::vector())); @@ -543,7 +543,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) // scripts if (mCompileAll) { - std::pair result = MWBase::Environment::get().getScriptManager()->compileAll(); + std::pair result = mEnvironment.getScriptManager()->compileAll(); if (result.first) std::cout << "compiled " << result.second << " of " << result.first << " scripts (" @@ -648,38 +648,38 @@ void OMW::Engine::go() if (!mSaveGameFile.empty()) { - MWBase::Environment::get().getStateManager()->loadGame(mSaveGameFile); + mEnvironment.getStateManager()->loadGame(mSaveGameFile); } else if (!mSkipMenu) { // start in main menu - MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + mEnvironment.getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); try { // Is there an ini setting for this filename or something? - MWBase::Environment::get().getSoundManager()->streamMusic("Special/morrowind title.mp3"); + mEnvironment.getSoundManager()->streamMusic("Special/morrowind title.mp3"); std::string logo = mFallbackMap["Movies_Morrowind_Logo"]; if (!logo.empty()) - MWBase::Environment::get().getWindowManager()->playVideo(logo, true); + mEnvironment.getWindowManager()->playVideo(logo, true); } catch (...) {} } else { - MWBase::Environment::get().getStateManager()->newGame (!mNewGame); + mEnvironment.getStateManager()->newGame (!mNewGame); } // Start the main rendering loop osg::Timer frameTimer; double simulationTime = 0.0; - while (!mViewer->done() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) + while (!mViewer->done() && !mEnvironment.getStateManager()->hasQuitRequest()) { double dt = frameTimer.time_s(); frameTimer.setStartTick(); dt = std::min(dt, 0.2); - bool guiActive = MWBase::Environment::get().getWindowManager()->isGuiMode(); + bool guiActive = mEnvironment.getWindowManager()->isGuiMode(); if (!guiActive) simulationTime += dt; @@ -700,15 +700,15 @@ void OMW::Engine::go() void OMW::Engine::activate() { - if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + if (mEnvironment.getWindowManager()->isGuiMode()) return; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr(); if (player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0 || player.getClass().getCreatureStats(player).getKnockedDown()) return; - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject(); + MWWorld::Ptr ptr = mEnvironment.getWorld()->getFacedObject(); if (ptr.isEmpty()) return; @@ -724,7 +724,7 @@ void OMW::Engine::activate() return; } - MWBase::Environment::get().getWorld()->activate(ptr, MWBase::Environment::get().getWorld()->getPlayerPtr()); + mEnvironment.getWorld()->activate(ptr, mEnvironment.getWorld()->getPlayerPtr()); } void OMW::Engine::screenshot() diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index b2cd8414e..9436e35d2 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1367,7 +1367,7 @@ namespace MWMechanics // Doesn't handle possible edge case where no one reported the assault, but in such a case, // for bystanders it is not possible to tell who attacked first, anyway. if (victimStats.getCrimeId() != -1) - MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, victim, MWBase::MechanicsManager::OT_Murder); + commitCrime(attacker, victim, MWBase::MechanicsManager::OT_Murder); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 15c8cbeb2..1738878ea 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1421,7 +1421,7 @@ namespace MWWorld if (ptr.getClass().isActor()) { // Collided with actor, ask actor to try to avoid door - if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr() ) { + if(ptr != getPlayerPtr() ) { MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) //Only add it once seq.stack(MWMechanics::AiAvoidDoor(it->first),ptr); @@ -1738,7 +1738,7 @@ namespace MWWorld else { cellid.mPaged = true; - MWBase::Environment::get().getWorld()->positionToIndex( + positionToIndex( ref.mRef.getDoorDest().pos[0], ref.mRef.getDoorDest().pos[1], cellid.mIndex.mX, @@ -2516,7 +2516,7 @@ namespace MWWorld if (reported) { npcStats.setBounty(npcStats.getBounty()+ - MWBase::Environment::get().getWorld()->getStore().get().find("iWereWolfBounty")->getInt()); + mStore.get().find("iWereWolfBounty")->getInt()); windowManager->messageBox("#{sCrimeMessage}"); } } From b583a2ec330592ca1cf38d260640e2782dd121ff Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 17 Aug 2015 00:05:57 +0200 Subject: [PATCH 272/419] Make SetDelete a no-op for items in containers (Fixes #2864) --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 6e5029cc3..d345cdf7e 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -256,6 +256,7 @@ namespace MWBase virtual void fixPosition (const MWWorld::Ptr& actor) = 0; ///< Attempt to fix position so that the Ptr is no longer inside collision geometry. + /// @note No-op for items in containers. Use ContainerStore::removeItem instead. virtual void deleteObject (const MWWorld::Ptr& ptr) = 0; virtual void undeleteObject (const MWWorld::Ptr& ptr) = 0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 15c8cbeb2..e1de0f07a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1050,7 +1050,7 @@ namespace MWWorld void World::deleteObject (const Ptr& ptr) { - if (!ptr.getRefData().isDeleted()) + if (!ptr.getRefData().isDeleted() && ptr.getContainerStore() == NULL) { ptr.getRefData().setCount(0); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5251427c5..35e433549 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -336,7 +336,9 @@ namespace MWWorld /// use the "Head" node as a basis. virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance); + /// @note No-op for items in containers. Use ContainerStore::removeItem instead. virtual void deleteObject (const Ptr& ptr); + virtual void undeleteObject (const Ptr& ptr); virtual MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z); From dca08b0b42e1151e598d0e4cf95c4cb4306b508e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 18 Aug 2015 14:51:32 +0200 Subject: [PATCH 273/419] Remove a firing assert (Fixes #2871) --- apps/openmw/mwmechanics/pathfinding.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 777ccacae..798a0ea21 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -221,7 +221,8 @@ namespace MWMechanics } mPath = mCell->aStarSearch(startNode, endNode.first); - assert(!mPath.empty()); + if (mPath.empty()) + return; // convert supplied path to world co-ordinates for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) From 67bd6cd70837605e1acebe41048b0f7ff88190ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 18 Aug 2015 23:06:12 +0200 Subject: [PATCH 274/419] Remove empty line at the beginning of files git ls-files -z | xargs -0 sed -i '1{/^$/d}' --- apps/opencs/editor.cpp | 1 - apps/opencs/main.cpp | 1 - apps/opencs/model/doc/blacklist.cpp | 1 - apps/opencs/model/doc/documentmanager.cpp | 1 - apps/opencs/model/doc/loader.cpp | 1 - apps/opencs/model/doc/messages.cpp | 1 - apps/opencs/model/doc/operation.cpp | 1 - apps/opencs/model/doc/operationholder.cpp | 1 - apps/opencs/model/doc/runner.cpp | 1 - apps/opencs/model/doc/saving.cpp | 1 - apps/opencs/model/doc/savingstages.cpp | 1 - apps/opencs/model/doc/savingstate.cpp | 1 - apps/opencs/model/doc/stage.cpp | 1 - apps/opencs/model/filter/andnode.cpp | 1 - apps/opencs/model/filter/booleannode.cpp | 1 - apps/opencs/model/filter/leafnode.cpp | 1 - apps/opencs/model/filter/narynode.cpp | 1 - apps/opencs/model/filter/node.cpp | 1 - apps/opencs/model/filter/notnode.cpp | 1 - apps/opencs/model/filter/ornode.cpp | 1 - apps/opencs/model/filter/parser.cpp | 1 - apps/opencs/model/filter/textnode.cpp | 1 - apps/opencs/model/filter/unarynode.cpp | 1 - apps/opencs/model/filter/valuenode.cpp | 1 - apps/opencs/model/tools/birthsigncheck.cpp | 1 - apps/opencs/model/tools/classcheck.cpp | 1 - apps/opencs/model/tools/factioncheck.cpp | 1 - apps/opencs/model/tools/mandatoryid.cpp | 1 - apps/opencs/model/tools/racecheck.cpp | 1 - apps/opencs/model/tools/regioncheck.cpp | 1 - apps/opencs/model/tools/reportmodel.cpp | 1 - apps/opencs/model/tools/scriptcheck.cpp | 1 - apps/opencs/model/tools/search.cpp | 1 - apps/opencs/model/tools/searchoperation.cpp | 1 - apps/opencs/model/tools/searchstage.cpp | 1 - apps/opencs/model/tools/skillcheck.cpp | 1 - apps/opencs/model/tools/soundcheck.cpp | 1 - apps/opencs/model/tools/spellcheck.cpp | 1 - apps/opencs/model/tools/startscriptcheck.cpp | 1 - apps/opencs/model/tools/tools.cpp | 1 - apps/opencs/model/world/cell.cpp | 1 - apps/opencs/model/world/cellcoordinates.cpp | 1 - apps/opencs/model/world/cellselection.cpp | 1 - apps/opencs/model/world/collectionbase.cpp | 1 - apps/opencs/model/world/columns.cpp | 1 - apps/opencs/model/world/commanddispatcher.cpp | 1 - apps/opencs/model/world/data.cpp | 1 - apps/opencs/model/world/idtablebase.cpp | 1 - apps/opencs/model/world/idtableproxymodel.cpp | 1 - apps/opencs/model/world/infocollection.cpp | 1 - apps/opencs/model/world/metadata.cpp | 1 - apps/opencs/model/world/record.cpp | 1 - apps/opencs/model/world/ref.cpp | 1 - apps/opencs/model/world/refcollection.cpp | 1 - apps/opencs/model/world/refiddata.cpp | 1 - apps/opencs/model/world/regionmap.cpp | 1 - apps/opencs/model/world/resources.cpp | 1 - apps/opencs/model/world/resourcesmanager.cpp | 1 - apps/opencs/model/world/resourcetable.cpp | 1 - apps/opencs/model/world/scope.cpp | 1 - apps/opencs/model/world/scriptcontext.cpp | 1 - apps/opencs/model/world/tablemimedata.hpp | 1 - apps/opencs/model/world/universalid.cpp | 1 - apps/opencs/view/doc/adjusterwidget.cpp | 1 - apps/opencs/view/doc/filewidget.cpp | 1 - apps/opencs/view/doc/globaldebugprofilemenu.cpp | 1 - apps/opencs/view/doc/loader.cpp | 1 - apps/opencs/view/doc/newgame.cpp | 1 - apps/opencs/view/doc/runlogsubview.cpp | 1 - apps/opencs/view/doc/startup.cpp | 1 - apps/opencs/view/doc/subviewfactory.cpp | 1 - apps/opencs/view/doc/viewmanager.cpp | 1 - apps/opencs/view/filter/editwidget.cpp | 1 - apps/opencs/view/filter/filterbox.cpp | 1 - apps/opencs/view/filter/recordfilterbox.cpp | 1 - apps/opencs/view/render/cell.cpp | 1 - apps/opencs/view/render/editmode.cpp | 1 - apps/opencs/view/render/lightingbright.cpp | 1 - apps/opencs/view/render/pagedworldspacewidget.cpp | 1 - apps/opencs/view/render/previewwidget.cpp | 1 - apps/opencs/view/render/unpagedworldspacewidget.cpp | 1 - apps/opencs/view/render/worldspacewidget.cpp | 1 - apps/opencs/view/tools/reportsubview.cpp | 1 - apps/opencs/view/tools/reporttable.cpp | 1 - apps/opencs/view/tools/searchbox.cpp | 1 - apps/opencs/view/tools/searchsubview.cpp | 1 - apps/opencs/view/tools/subviews.cpp | 1 - apps/opencs/view/widget/modebutton.cpp | 1 - apps/opencs/view/widget/pushbutton.cpp | 1 - apps/opencs/view/widget/scenetool.cpp | 1 - apps/opencs/view/widget/scenetoolbar.cpp | 1 - apps/opencs/view/widget/scenetoolmode.cpp | 1 - apps/opencs/view/widget/scenetoolrun.cpp | 1 - apps/opencs/view/widget/scenetooltoggle.cpp | 1 - apps/opencs/view/widget/scenetooltoggle2.cpp | 1 - apps/opencs/view/world/cellcreator.cpp | 1 - apps/opencs/view/world/creator.cpp | 1 - apps/opencs/view/world/dialoguecreator.cpp | 1 - apps/opencs/view/world/enumdelegate.cpp | 1 - apps/opencs/view/world/genericcreator.cpp | 1 - apps/opencs/view/world/idvalidator.cpp | 1 - apps/opencs/view/world/infocreator.cpp | 1 - apps/opencs/view/world/previewsubview.cpp | 1 - apps/opencs/view/world/recordbuttonbar.cpp | 1 - apps/opencs/view/world/referenceablecreator.cpp | 1 - apps/opencs/view/world/referencecreator.cpp | 1 - apps/opencs/view/world/regionmap.cpp | 1 - apps/opencs/view/world/regionmapsubview.cpp | 1 - apps/opencs/view/world/scenesubview.cpp | 1 - apps/opencs/view/world/scripterrortable.cpp | 1 - apps/opencs/view/world/scripthighlighter.cpp | 1 - apps/opencs/view/world/subviews.cpp | 1 - apps/opencs/view/world/table.cpp | 1 - apps/opencs/view/world/tablebottombox.cpp | 1 - apps/opencs/view/world/tablesubview.cpp | 1 - apps/opencs/view/world/util.cpp | 1 - apps/opencs/view/world/vartypedelegate.cpp | 1 - apps/openmw/android_commandLine.h | 1 - apps/openmw/mwbase/environment.cpp | 1 - apps/openmw/mwclass/activator.cpp | 1 - apps/openmw/mwclass/apparatus.cpp | 1 - apps/openmw/mwclass/armor.cpp | 1 - apps/openmw/mwclass/classes.cpp | 1 - apps/openmw/mwclass/clothing.cpp | 1 - apps/openmw/mwclass/container.cpp | 1 - apps/openmw/mwclass/creature.cpp | 1 - apps/openmw/mwclass/creaturelevlist.cpp | 1 - apps/openmw/mwclass/door.cpp | 1 - apps/openmw/mwclass/ingredient.cpp | 1 - apps/openmw/mwclass/itemlevlist.cpp | 1 - apps/openmw/mwclass/light.cpp | 1 - apps/openmw/mwclass/lockpick.cpp | 1 - apps/openmw/mwclass/misc.cpp | 1 - apps/openmw/mwclass/npc.cpp | 1 - apps/openmw/mwclass/potion.cpp | 1 - apps/openmw/mwclass/probe.cpp | 1 - apps/openmw/mwclass/repair.cpp | 1 - apps/openmw/mwclass/static.cpp | 1 - apps/openmw/mwclass/weapon.cpp | 1 - apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 1 - apps/openmw/mwdialogue/filter.cpp | 1 - apps/openmw/mwdialogue/journalentry.cpp | 1 - apps/openmw/mwdialogue/journalimp.cpp | 1 - apps/openmw/mwdialogue/quest.cpp | 1 - apps/openmw/mwdialogue/selectwrapper.cpp | 1 - apps/openmw/mwdialogue/topic.cpp | 1 - apps/openmw/mwgui/tooltips.hpp | 1 - apps/openmw/mwmechanics/alchemy.cpp | 1 - apps/openmw/mwmechanics/magiceffects.cpp | 1 - apps/openmw/mwmechanics/npcstats.cpp | 1 - apps/openmw/mwmechanics/spells.cpp | 1 - apps/openmw/mwscript/aiextensions.cpp | 1 - apps/openmw/mwscript/animationextensions.cpp | 1 - apps/openmw/mwscript/compilercontext.cpp | 1 - apps/openmw/mwscript/consoleextensions.cpp | 1 - apps/openmw/mwscript/containerextensions.cpp | 1 - apps/openmw/mwscript/controlextensions.cpp | 1 - apps/openmw/mwscript/dialogueextensions.cpp | 1 - apps/openmw/mwscript/extensions.cpp | 1 - apps/openmw/mwscript/globalscripts.cpp | 1 - apps/openmw/mwscript/guiextensions.cpp | 1 - apps/openmw/mwscript/interpretercontext.cpp | 1 - apps/openmw/mwscript/miscextensions.cpp | 1 - apps/openmw/mwscript/scriptmanagerimp.cpp | 1 - apps/openmw/mwscript/skyextensions.cpp | 1 - apps/openmw/mwscript/soundextensions.cpp | 1 - apps/openmw/mwscript/userextensions.cpp | 1 - apps/openmw/mwstate/character.cpp | 1 - apps/openmw/mwstate/charactermanager.cpp | 1 - apps/openmw/mwstate/statemanagerimp.cpp | 1 - apps/openmw/mwworld/action.cpp | 1 - apps/openmw/mwworld/actionapply.cpp | 1 - apps/openmw/mwworld/actioneat.cpp | 1 - apps/openmw/mwworld/actionopen.hpp | 1 - apps/openmw/mwworld/actiontake.cpp | 1 - apps/openmw/mwworld/actiontalk.cpp | 1 - apps/openmw/mwworld/class.cpp | 1 - apps/openmw/mwworld/containerstore.cpp | 1 - apps/openmw/mwworld/globals.cpp | 1 - apps/openmw/mwworld/inventorystore.cpp | 1 - apps/openmw/mwworld/ptr.cpp | 1 - apps/openmw/mwworld/refdata.cpp | 1 - components/compiler/controlparser.cpp | 1 - components/compiler/declarationparser.cpp | 1 - components/compiler/discardparser.cpp | 1 - components/compiler/errorhandler.cpp | 1 - components/compiler/errorhandler.hpp | 1 - components/compiler/exprparser.cpp | 1 - components/compiler/extensions.cpp | 1 - components/compiler/generator.cpp | 1 - components/compiler/junkparser.cpp | 1 - components/compiler/lineparser.cpp | 1 - components/compiler/literals.cpp | 1 - components/compiler/locals.cpp | 1 - components/compiler/nullerrorhandler.cpp | 1 - components/compiler/nullerrorhandler.hpp | 1 - components/compiler/output.cpp | 1 - components/compiler/parser.cpp | 1 - components/compiler/quickfileparser.cpp | 1 - components/compiler/scanner.cpp | 1 - components/compiler/scriptparser.cpp | 1 - components/compiler/skipparser.cpp | 1 - components/compiler/streamerrorhandler.cpp | 1 - components/compiler/streamerrorhandler.hpp | 1 - components/compiler/stringparser.cpp | 1 - components/esm/cellid.cpp | 1 - components/esm/cellref.cpp | 1 - components/esm/cellstate.cpp | 1 - components/esm/containerstate.cpp | 1 - components/esm/creaturestate.cpp | 1 - components/esm/debugprofile.cpp | 1 - components/esm/dialoguestate.cpp | 1 - components/esm/filter.cpp | 1 - components/esm/globalscript.cpp | 1 - components/esm/inventorystate.cpp | 1 - components/esm/journalentry.cpp | 1 - components/esm/loadtes3.cpp | 1 - components/esm/locals.cpp | 1 - components/esm/npcstate.cpp | 1 - components/esm/objectstate.cpp | 1 - components/esm/player.cpp | 1 - components/esm/queststate.cpp | 1 - components/esm/savedgame.cpp | 1 - components/esm/variantimp.cpp | 1 - components/files/multidircollection.cpp | 1 - components/interpreter/installopcodes.cpp | 1 - components/interpreter/interpreter.cpp | 1 - components/interpreter/runtime.cpp | 1 - files/mygui/CMakeLists.txt | 1 - 229 files changed, 229 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 9450aa4bf..e4c65907e 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -1,4 +1,3 @@ - #include "editor.hpp" #include diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index fd7370a40..de2e6e83e 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -1,4 +1,3 @@ - #include "editor.hpp" #include diff --git a/apps/opencs/model/doc/blacklist.cpp b/apps/opencs/model/doc/blacklist.cpp index 083726412..b1d402c69 100644 --- a/apps/opencs/model/doc/blacklist.cpp +++ b/apps/opencs/model/doc/blacklist.cpp @@ -1,4 +1,3 @@ - #include "blacklist.hpp" #include diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 5a5f50159..3a31e8687 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -1,4 +1,3 @@ - #include "documentmanager.hpp" #include diff --git a/apps/opencs/model/doc/loader.cpp b/apps/opencs/model/doc/loader.cpp index 33725a6f9..cb3ff2cd0 100644 --- a/apps/opencs/model/doc/loader.cpp +++ b/apps/opencs/model/doc/loader.cpp @@ -1,4 +1,3 @@ - #include "loader.hpp" #include diff --git a/apps/opencs/model/doc/messages.cpp b/apps/opencs/model/doc/messages.cpp index c8d26d39b..86e96a88d 100644 --- a/apps/opencs/model/doc/messages.cpp +++ b/apps/opencs/model/doc/messages.cpp @@ -1,4 +1,3 @@ - #include "messages.hpp" CSMDoc::Message::Message() {} diff --git a/apps/opencs/model/doc/operation.cpp b/apps/opencs/model/doc/operation.cpp index 8b2717086..cb9b7ec29 100644 --- a/apps/opencs/model/doc/operation.cpp +++ b/apps/opencs/model/doc/operation.cpp @@ -1,4 +1,3 @@ - #include "operation.hpp" #include diff --git a/apps/opencs/model/doc/operationholder.cpp b/apps/opencs/model/doc/operationholder.cpp index 25fc6fc26..db0d1a9a4 100644 --- a/apps/opencs/model/doc/operationholder.cpp +++ b/apps/opencs/model/doc/operationholder.cpp @@ -1,4 +1,3 @@ - #include "operationholder.hpp" #include "../settings/usersettings.hpp" diff --git a/apps/opencs/model/doc/runner.cpp b/apps/opencs/model/doc/runner.cpp index 14fe0cda8..5a0bc39be 100644 --- a/apps/opencs/model/doc/runner.cpp +++ b/apps/opencs/model/doc/runner.cpp @@ -1,4 +1,3 @@ - #include "runner.hpp" #include diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 9f6e469b8..25372f1a6 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -1,4 +1,3 @@ - #include "saving.hpp" #include "../world/data.hpp" diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index f78c57ecd..ef3b23ec8 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -1,4 +1,3 @@ - #include "savingstages.hpp" #include diff --git a/apps/opencs/model/doc/savingstate.cpp b/apps/opencs/model/doc/savingstate.cpp index e7ad551b2..10539c1b5 100644 --- a/apps/opencs/model/doc/savingstate.cpp +++ b/apps/opencs/model/doc/savingstate.cpp @@ -1,4 +1,3 @@ - #include "savingstate.hpp" #include "operation.hpp" diff --git a/apps/opencs/model/doc/stage.cpp b/apps/opencs/model/doc/stage.cpp index 78aa14574..c8da86069 100644 --- a/apps/opencs/model/doc/stage.cpp +++ b/apps/opencs/model/doc/stage.cpp @@ -1,4 +1,3 @@ - #include "stage.hpp" CSMDoc::Stage::~Stage() {} diff --git a/apps/opencs/model/filter/andnode.cpp b/apps/opencs/model/filter/andnode.cpp index 4249fc228..908662799 100644 --- a/apps/opencs/model/filter/andnode.cpp +++ b/apps/opencs/model/filter/andnode.cpp @@ -1,4 +1,3 @@ - #include "andnode.hpp" #include diff --git a/apps/opencs/model/filter/booleannode.cpp b/apps/opencs/model/filter/booleannode.cpp index 35fc98e08..ee7ddc1c0 100644 --- a/apps/opencs/model/filter/booleannode.cpp +++ b/apps/opencs/model/filter/booleannode.cpp @@ -1,4 +1,3 @@ - #include "booleannode.hpp" CSMFilter::BooleanNode::BooleanNode (bool true_) : mTrue (true_) {} diff --git a/apps/opencs/model/filter/leafnode.cpp b/apps/opencs/model/filter/leafnode.cpp index 055a1747c..6745e165e 100644 --- a/apps/opencs/model/filter/leafnode.cpp +++ b/apps/opencs/model/filter/leafnode.cpp @@ -1,4 +1,3 @@ - #include "leafnode.hpp" std::vector CSMFilter::LeafNode::getReferencedColumns() const diff --git a/apps/opencs/model/filter/narynode.cpp b/apps/opencs/model/filter/narynode.cpp index 98f706c87..f2e0e5cb2 100644 --- a/apps/opencs/model/filter/narynode.cpp +++ b/apps/opencs/model/filter/narynode.cpp @@ -1,4 +1,3 @@ - #include "narynode.hpp" #include diff --git a/apps/opencs/model/filter/node.cpp b/apps/opencs/model/filter/node.cpp index 091dc4698..e25610675 100644 --- a/apps/opencs/model/filter/node.cpp +++ b/apps/opencs/model/filter/node.cpp @@ -1,4 +1,3 @@ - #include "node.hpp" CSMFilter::Node::Node() {} diff --git a/apps/opencs/model/filter/notnode.cpp b/apps/opencs/model/filter/notnode.cpp index b5d9da7b7..ba5302bbe 100644 --- a/apps/opencs/model/filter/notnode.cpp +++ b/apps/opencs/model/filter/notnode.cpp @@ -1,4 +1,3 @@ - #include "notnode.hpp" CSMFilter::NotNode::NotNode (boost::shared_ptr child) : UnaryNode (child, "not") {} diff --git a/apps/opencs/model/filter/ornode.cpp b/apps/opencs/model/filter/ornode.cpp index c5d15a384..41ec7b5cf 100644 --- a/apps/opencs/model/filter/ornode.cpp +++ b/apps/opencs/model/filter/ornode.cpp @@ -1,4 +1,3 @@ - #include "ornode.hpp" #include diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp index 51338dfc9..7936a1ae2 100644 --- a/apps/opencs/model/filter/parser.cpp +++ b/apps/opencs/model/filter/parser.cpp @@ -1,4 +1,3 @@ - #include "parser.hpp" #include diff --git a/apps/opencs/model/filter/textnode.cpp b/apps/opencs/model/filter/textnode.cpp index 73c378f11..246ebae24 100644 --- a/apps/opencs/model/filter/textnode.cpp +++ b/apps/opencs/model/filter/textnode.cpp @@ -1,4 +1,3 @@ - #include "textnode.hpp" #include diff --git a/apps/opencs/model/filter/unarynode.cpp b/apps/opencs/model/filter/unarynode.cpp index c40d191b6..cbdadf6fc 100644 --- a/apps/opencs/model/filter/unarynode.cpp +++ b/apps/opencs/model/filter/unarynode.cpp @@ -1,4 +1,3 @@ - #include "unarynode.hpp" CSMFilter::UnaryNode::UnaryNode (boost::shared_ptr child, const std::string& name) diff --git a/apps/opencs/model/filter/valuenode.cpp b/apps/opencs/model/filter/valuenode.cpp index 6fdb5cb02..85c5a8e27 100644 --- a/apps/opencs/model/filter/valuenode.cpp +++ b/apps/opencs/model/filter/valuenode.cpp @@ -1,4 +1,3 @@ - #include "valuenode.hpp" #include diff --git a/apps/opencs/model/tools/birthsigncheck.cpp b/apps/opencs/model/tools/birthsigncheck.cpp index 4e6da4631..9898352f1 100644 --- a/apps/opencs/model/tools/birthsigncheck.cpp +++ b/apps/opencs/model/tools/birthsigncheck.cpp @@ -1,4 +1,3 @@ - #include "birthsigncheck.hpp" #include diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index be57a3729..e4964d4e3 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -1,4 +1,3 @@ - #include "classcheck.hpp" #include diff --git a/apps/opencs/model/tools/factioncheck.cpp b/apps/opencs/model/tools/factioncheck.cpp index 0dfdee775..621b28070 100644 --- a/apps/opencs/model/tools/factioncheck.cpp +++ b/apps/opencs/model/tools/factioncheck.cpp @@ -1,4 +1,3 @@ - #include "factioncheck.hpp" #include diff --git a/apps/opencs/model/tools/mandatoryid.cpp b/apps/opencs/model/tools/mandatoryid.cpp index 4c97d2266..23adb9d37 100644 --- a/apps/opencs/model/tools/mandatoryid.cpp +++ b/apps/opencs/model/tools/mandatoryid.cpp @@ -1,4 +1,3 @@ - #include "mandatoryid.hpp" #include "../world/collectionbase.hpp" diff --git a/apps/opencs/model/tools/racecheck.cpp b/apps/opencs/model/tools/racecheck.cpp index 3b2c8d290..b30088620 100644 --- a/apps/opencs/model/tools/racecheck.cpp +++ b/apps/opencs/model/tools/racecheck.cpp @@ -1,4 +1,3 @@ - #include "racecheck.hpp" #include diff --git a/apps/opencs/model/tools/regioncheck.cpp b/apps/opencs/model/tools/regioncheck.cpp index 42abc35c9..2fdff5f38 100644 --- a/apps/opencs/model/tools/regioncheck.cpp +++ b/apps/opencs/model/tools/regioncheck.cpp @@ -1,4 +1,3 @@ - #include "regioncheck.hpp" #include diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 4bf7d1581..77a14de84 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -1,4 +1,3 @@ - #include "reportmodel.hpp" #include diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index 665edd7a3..d7c41cfcf 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -1,4 +1,3 @@ - #include "scriptcheck.hpp" #include diff --git a/apps/opencs/model/tools/search.cpp b/apps/opencs/model/tools/search.cpp index 449df2c63..0409199af 100644 --- a/apps/opencs/model/tools/search.cpp +++ b/apps/opencs/model/tools/search.cpp @@ -1,4 +1,3 @@ - #include "search.hpp" #include diff --git a/apps/opencs/model/tools/searchoperation.cpp b/apps/opencs/model/tools/searchoperation.cpp index 8cbc5dc8e..8fba1cc1e 100644 --- a/apps/opencs/model/tools/searchoperation.cpp +++ b/apps/opencs/model/tools/searchoperation.cpp @@ -1,4 +1,3 @@ - #include "searchoperation.hpp" #include "../doc/state.hpp" diff --git a/apps/opencs/model/tools/searchstage.cpp b/apps/opencs/model/tools/searchstage.cpp index 17859d930..3db10b0c3 100644 --- a/apps/opencs/model/tools/searchstage.cpp +++ b/apps/opencs/model/tools/searchstage.cpp @@ -1,4 +1,3 @@ - #include "searchstage.hpp" #include "../world/idtablebase.hpp" diff --git a/apps/opencs/model/tools/skillcheck.cpp b/apps/opencs/model/tools/skillcheck.cpp index 2b55526e0..77ba8d4a2 100644 --- a/apps/opencs/model/tools/skillcheck.cpp +++ b/apps/opencs/model/tools/skillcheck.cpp @@ -1,4 +1,3 @@ - #include "skillcheck.hpp" #include diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp index f78932a32..6a059bee2 100644 --- a/apps/opencs/model/tools/soundcheck.cpp +++ b/apps/opencs/model/tools/soundcheck.cpp @@ -1,4 +1,3 @@ - #include "soundcheck.hpp" #include diff --git a/apps/opencs/model/tools/spellcheck.cpp b/apps/opencs/model/tools/spellcheck.cpp index bd076d2a5..91aed37ed 100644 --- a/apps/opencs/model/tools/spellcheck.cpp +++ b/apps/opencs/model/tools/spellcheck.cpp @@ -1,4 +1,3 @@ - #include "spellcheck.hpp" #include diff --git a/apps/opencs/model/tools/startscriptcheck.cpp b/apps/opencs/model/tools/startscriptcheck.cpp index e3c01368b..220751797 100644 --- a/apps/opencs/model/tools/startscriptcheck.cpp +++ b/apps/opencs/model/tools/startscriptcheck.cpp @@ -1,4 +1,3 @@ - #include "startscriptcheck.hpp" #include diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 97943b1fb..0c6e36a61 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -1,4 +1,3 @@ - #include "tools.hpp" #include diff --git a/apps/opencs/model/world/cell.cpp b/apps/opencs/model/world/cell.cpp index 40520a9ba..91becdb74 100644 --- a/apps/opencs/model/world/cell.cpp +++ b/apps/opencs/model/world/cell.cpp @@ -1,4 +1,3 @@ - #include "cell.hpp" #include diff --git a/apps/opencs/model/world/cellcoordinates.cpp b/apps/opencs/model/world/cellcoordinates.cpp index b1c8441e6..95e206e2d 100644 --- a/apps/opencs/model/world/cellcoordinates.cpp +++ b/apps/opencs/model/world/cellcoordinates.cpp @@ -1,4 +1,3 @@ - #include "cellcoordinates.hpp" #include diff --git a/apps/opencs/model/world/cellselection.cpp b/apps/opencs/model/world/cellselection.cpp index 73b5196f1..c6988e488 100644 --- a/apps/opencs/model/world/cellselection.cpp +++ b/apps/opencs/model/world/cellselection.cpp @@ -1,4 +1,3 @@ - #include "cellselection.hpp" #include diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index b8eed4192..6134dc172 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -1,4 +1,3 @@ - #include "collectionbase.hpp" #include diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 177fb59ce..1fcf0ae41 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -1,4 +1,3 @@ - #include "columns.hpp" #include diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index b9d5bd7fe..0b1af0e84 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -1,4 +1,3 @@ - #include "commanddispatcher.hpp" #include diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 25a04715d..12ff1a38c 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -1,4 +1,3 @@ - #include "data.hpp" #include diff --git a/apps/opencs/model/world/idtablebase.cpp b/apps/opencs/model/world/idtablebase.cpp index 389f5396e..274446b79 100644 --- a/apps/opencs/model/world/idtablebase.cpp +++ b/apps/opencs/model/world/idtablebase.cpp @@ -1,4 +1,3 @@ - #include "idtablebase.hpp" CSMWorld::IdTableBase::IdTableBase (unsigned int features) : mFeatures (features) {} diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 757285412..fbf7b6cf3 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -1,4 +1,3 @@ - #include "idtableproxymodel.hpp" #include diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index 560be8131..60c613041 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -1,4 +1,3 @@ - #include "infocollection.hpp" #include diff --git a/apps/opencs/model/world/metadata.cpp b/apps/opencs/model/world/metadata.cpp index 40b8e9519..960fdc9e4 100644 --- a/apps/opencs/model/world/metadata.cpp +++ b/apps/opencs/model/world/metadata.cpp @@ -1,4 +1,3 @@ - #include "metadata.hpp" #include diff --git a/apps/opencs/model/world/record.cpp b/apps/opencs/model/world/record.cpp index ef2f4d320..f13a36afc 100644 --- a/apps/opencs/model/world/record.cpp +++ b/apps/opencs/model/world/record.cpp @@ -1,4 +1,3 @@ - #include "record.hpp" CSMWorld::RecordBase::~RecordBase() {} diff --git a/apps/opencs/model/world/ref.cpp b/apps/opencs/model/world/ref.cpp index 13706c950..638f7ec9c 100644 --- a/apps/opencs/model/world/ref.cpp +++ b/apps/opencs/model/world/ref.cpp @@ -1,4 +1,3 @@ - #include "ref.hpp" #include diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index ff30dafae..f8818807b 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -1,4 +1,3 @@ - #include "refcollection.hpp" #include diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index 7f5c25f36..c391201e6 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -1,4 +1,3 @@ - #include "refiddata.hpp" #include diff --git a/apps/opencs/model/world/regionmap.cpp b/apps/opencs/model/world/regionmap.cpp index 42bde9c81..10c67c909 100644 --- a/apps/opencs/model/world/regionmap.cpp +++ b/apps/opencs/model/world/regionmap.cpp @@ -1,4 +1,3 @@ - #include "regionmap.hpp" #include diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index 4dd480e77..b31e211ee 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -1,4 +1,3 @@ - #include "resources.hpp" #include diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 3e2f72d93..2ec661cb1 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -1,4 +1,3 @@ - #include "resourcesmanager.hpp" #include diff --git a/apps/opencs/model/world/resourcetable.cpp b/apps/opencs/model/world/resourcetable.cpp index 2cd44781a..5227ec3e6 100644 --- a/apps/opencs/model/world/resourcetable.cpp +++ b/apps/opencs/model/world/resourcetable.cpp @@ -1,4 +1,3 @@ - #include "resourcetable.hpp" #include diff --git a/apps/opencs/model/world/scope.cpp b/apps/opencs/model/world/scope.cpp index 6e4ce4c02..b026c34c3 100644 --- a/apps/opencs/model/world/scope.cpp +++ b/apps/opencs/model/world/scope.cpp @@ -1,4 +1,3 @@ - #include "scope.hpp" #include diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index a8c2c9452..bcbca4b28 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -1,4 +1,3 @@ - #include "scriptcontext.hpp" #include diff --git a/apps/opencs/model/world/tablemimedata.hpp b/apps/opencs/model/world/tablemimedata.hpp index 06d252435..a42e97561 100644 --- a/apps/opencs/model/world/tablemimedata.hpp +++ b/apps/opencs/model/world/tablemimedata.hpp @@ -1,4 +1,3 @@ - #ifndef TABLEMIMEDATA_H #define TABLEMIMEDATA_H diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 73d893a26..77db2be10 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -1,4 +1,3 @@ - #include "universalid.hpp" #include diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 6571ad7c8..ba5dd90f8 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -1,4 +1,3 @@ - #include "adjusterwidget.hpp" #include diff --git a/apps/opencs/view/doc/filewidget.cpp b/apps/opencs/view/doc/filewidget.cpp index f18fe695a..bbb824823 100644 --- a/apps/opencs/view/doc/filewidget.cpp +++ b/apps/opencs/view/doc/filewidget.cpp @@ -1,4 +1,3 @@ - #include "filewidget.hpp" #include diff --git a/apps/opencs/view/doc/globaldebugprofilemenu.cpp b/apps/opencs/view/doc/globaldebugprofilemenu.cpp index b88381385..f0d9655dd 100644 --- a/apps/opencs/view/doc/globaldebugprofilemenu.cpp +++ b/apps/opencs/view/doc/globaldebugprofilemenu.cpp @@ -1,4 +1,3 @@ - #include "globaldebugprofilemenu.hpp" #include diff --git a/apps/opencs/view/doc/loader.cpp b/apps/opencs/view/doc/loader.cpp index 30235d0f5..713295d70 100644 --- a/apps/opencs/view/doc/loader.cpp +++ b/apps/opencs/view/doc/loader.cpp @@ -1,4 +1,3 @@ - #include "loader.hpp" #include diff --git a/apps/opencs/view/doc/newgame.cpp b/apps/opencs/view/doc/newgame.cpp index 32b483728..b3e2a4f63 100644 --- a/apps/opencs/view/doc/newgame.cpp +++ b/apps/opencs/view/doc/newgame.cpp @@ -1,4 +1,3 @@ - #include "newgame.hpp" #include diff --git a/apps/opencs/view/doc/runlogsubview.cpp b/apps/opencs/view/doc/runlogsubview.cpp index 129396999..2b7182228 100644 --- a/apps/opencs/view/doc/runlogsubview.cpp +++ b/apps/opencs/view/doc/runlogsubview.cpp @@ -1,4 +1,3 @@ - #include "runlogsubview.hpp" #include diff --git a/apps/opencs/view/doc/startup.cpp b/apps/opencs/view/doc/startup.cpp index 58a46c603..a9d697f1c 100644 --- a/apps/opencs/view/doc/startup.cpp +++ b/apps/opencs/view/doc/startup.cpp @@ -1,4 +1,3 @@ - #include "startup.hpp" #include diff --git a/apps/opencs/view/doc/subviewfactory.cpp b/apps/opencs/view/doc/subviewfactory.cpp index 3137f7e32..82a8aeb05 100644 --- a/apps/opencs/view/doc/subviewfactory.cpp +++ b/apps/opencs/view/doc/subviewfactory.cpp @@ -1,4 +1,3 @@ - #include "subviewfactory.hpp" #include diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 7914d2d8c..7c9686277 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -1,4 +1,3 @@ - #include "viewmanager.hpp" #include diff --git a/apps/opencs/view/filter/editwidget.cpp b/apps/opencs/view/filter/editwidget.cpp index bc7f9b5a1..657a47750 100644 --- a/apps/opencs/view/filter/editwidget.cpp +++ b/apps/opencs/view/filter/editwidget.cpp @@ -1,4 +1,3 @@ - #include "editwidget.hpp" #include diff --git a/apps/opencs/view/filter/filterbox.cpp b/apps/opencs/view/filter/filterbox.cpp index 7a42ef0a5..c6c6cc6cc 100644 --- a/apps/opencs/view/filter/filterbox.cpp +++ b/apps/opencs/view/filter/filterbox.cpp @@ -1,4 +1,3 @@ - #include "filterbox.hpp" #include diff --git a/apps/opencs/view/filter/recordfilterbox.cpp b/apps/opencs/view/filter/recordfilterbox.cpp index 97490d508..2bf589215 100644 --- a/apps/opencs/view/filter/recordfilterbox.cpp +++ b/apps/opencs/view/filter/recordfilterbox.cpp @@ -1,4 +1,3 @@ - #include "recordfilterbox.hpp" #include diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index fe2eab066..77bcff4fd 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -1,4 +1,3 @@ - #include "cell.hpp" #include diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 9361030a3..8a99ba049 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -1,4 +1,3 @@ - #include "editmode.hpp" #include "worldspacewidget.hpp" diff --git a/apps/opencs/view/render/lightingbright.cpp b/apps/opencs/view/render/lightingbright.cpp index 00c4fb815..07900d6b0 100644 --- a/apps/opencs/view/render/lightingbright.cpp +++ b/apps/opencs/view/render/lightingbright.cpp @@ -1,4 +1,3 @@ - #include "lightingbright.hpp" #include diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 2b53483ad..274c77620 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -1,4 +1,3 @@ - #include "pagedworldspacewidget.hpp" #include diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index f512a8bb6..a03b277d3 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -1,4 +1,3 @@ - #include "previewwidget.hpp" #include diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 8e6e72cba..a5733ad10 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -1,4 +1,3 @@ - #include "unpagedworldspacewidget.hpp" #include diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 39ce09f31..d45fc45a8 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -1,4 +1,3 @@ - #include "worldspacewidget.hpp" #include diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp index e29447f25..a7316359e 100644 --- a/apps/opencs/view/tools/reportsubview.cpp +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -1,4 +1,3 @@ - #include "reportsubview.hpp" #include "reporttable.hpp" diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 550c53969..d4cecc971 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -1,4 +1,3 @@ - #include "reporttable.hpp" #include diff --git a/apps/opencs/view/tools/searchbox.cpp b/apps/opencs/view/tools/searchbox.cpp index 1307c1aab..d98044760 100644 --- a/apps/opencs/view/tools/searchbox.cpp +++ b/apps/opencs/view/tools/searchbox.cpp @@ -1,4 +1,3 @@ - #include "searchbox.hpp" #include diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 8b35db6ae..d3fdbbf5d 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -1,4 +1,3 @@ - #include "searchsubview.hpp" #include diff --git a/apps/opencs/view/tools/subviews.cpp b/apps/opencs/view/tools/subviews.cpp index 8a343ebe8..8c3d6d50e 100644 --- a/apps/opencs/view/tools/subviews.cpp +++ b/apps/opencs/view/tools/subviews.cpp @@ -1,4 +1,3 @@ - #include "subviews.hpp" #include "../doc/subviewfactoryimp.hpp" diff --git a/apps/opencs/view/widget/modebutton.cpp b/apps/opencs/view/widget/modebutton.cpp index 56896b422..7c62f6bb1 100644 --- a/apps/opencs/view/widget/modebutton.cpp +++ b/apps/opencs/view/widget/modebutton.cpp @@ -1,4 +1,3 @@ - #include "modebutton.hpp" CSVWidget::ModeButton::ModeButton (const QIcon& icon, const QString& tooltip, QWidget *parent) diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp index 1baeb7ca2..424aaf68a 100644 --- a/apps/opencs/view/widget/pushbutton.cpp +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -1,4 +1,3 @@ - #include "pushbutton.hpp" #include diff --git a/apps/opencs/view/widget/scenetool.cpp b/apps/opencs/view/widget/scenetool.cpp index b8e9f895f..796b98567 100644 --- a/apps/opencs/view/widget/scenetool.cpp +++ b/apps/opencs/view/widget/scenetool.cpp @@ -1,4 +1,3 @@ - #include "scenetool.hpp" #include diff --git a/apps/opencs/view/widget/scenetoolbar.cpp b/apps/opencs/view/widget/scenetoolbar.cpp index f7023b31f..b2e988dc9 100644 --- a/apps/opencs/view/widget/scenetoolbar.cpp +++ b/apps/opencs/view/widget/scenetoolbar.cpp @@ -1,4 +1,3 @@ - #include "scenetoolbar.hpp" #include diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 39e051c48..9f963873c 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -1,4 +1,3 @@ - #include "scenetoolmode.hpp" #include diff --git a/apps/opencs/view/widget/scenetoolrun.cpp b/apps/opencs/view/widget/scenetoolrun.cpp index 4c9eb676e..1e2d44e7a 100644 --- a/apps/opencs/view/widget/scenetoolrun.cpp +++ b/apps/opencs/view/widget/scenetoolrun.cpp @@ -1,4 +1,3 @@ - #include "scenetoolrun.hpp" #include diff --git a/apps/opencs/view/widget/scenetooltoggle.cpp b/apps/opencs/view/widget/scenetooltoggle.cpp index 07c448e45..d7251882a 100644 --- a/apps/opencs/view/widget/scenetooltoggle.cpp +++ b/apps/opencs/view/widget/scenetooltoggle.cpp @@ -1,4 +1,3 @@ - #include "scenetooltoggle.hpp" #include diff --git a/apps/opencs/view/widget/scenetooltoggle2.cpp b/apps/opencs/view/widget/scenetooltoggle2.cpp index 313e519cb..e0431476e 100644 --- a/apps/opencs/view/widget/scenetooltoggle2.cpp +++ b/apps/opencs/view/widget/scenetooltoggle2.cpp @@ -1,4 +1,3 @@ - #include "scenetooltoggle2.hpp" #include diff --git a/apps/opencs/view/world/cellcreator.cpp b/apps/opencs/view/world/cellcreator.cpp index c7d909f4c..2a710a940 100644 --- a/apps/opencs/view/world/cellcreator.cpp +++ b/apps/opencs/view/world/cellcreator.cpp @@ -1,4 +1,3 @@ - #include "cellcreator.hpp" #include diff --git a/apps/opencs/view/world/creator.cpp b/apps/opencs/view/world/creator.cpp index 7a8c8d48f..7a93339c5 100644 --- a/apps/opencs/view/world/creator.cpp +++ b/apps/opencs/view/world/creator.cpp @@ -1,4 +1,3 @@ - #include "creator.hpp" #include diff --git a/apps/opencs/view/world/dialoguecreator.cpp b/apps/opencs/view/world/dialoguecreator.cpp index 3d451ed2d..7c6fb2e81 100644 --- a/apps/opencs/view/world/dialoguecreator.cpp +++ b/apps/opencs/view/world/dialoguecreator.cpp @@ -1,4 +1,3 @@ - #include "dialoguecreator.hpp" #include diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 2190a62c6..e582e3356 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -1,4 +1,3 @@ - #include "enumdelegate.hpp" #include diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index 5f04d9a7a..8ed52bf80 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -1,4 +1,3 @@ - #include "genericcreator.hpp" #include diff --git a/apps/opencs/view/world/idvalidator.cpp b/apps/opencs/view/world/idvalidator.cpp index 13b05d2d1..1092d7217 100644 --- a/apps/opencs/view/world/idvalidator.cpp +++ b/apps/opencs/view/world/idvalidator.cpp @@ -1,4 +1,3 @@ - #include "idvalidator.hpp" #include diff --git a/apps/opencs/view/world/infocreator.cpp b/apps/opencs/view/world/infocreator.cpp index 268a82a28..1139afd69 100644 --- a/apps/opencs/view/world/infocreator.cpp +++ b/apps/opencs/view/world/infocreator.cpp @@ -1,4 +1,3 @@ - #include "infocreator.hpp" #include diff --git a/apps/opencs/view/world/previewsubview.cpp b/apps/opencs/view/world/previewsubview.cpp index 756e79fe6..f3312bb20 100644 --- a/apps/opencs/view/world/previewsubview.cpp +++ b/apps/opencs/view/world/previewsubview.cpp @@ -1,4 +1,3 @@ - #include "previewsubview.hpp" #include diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 9cae0d0c9..1a838a3b3 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -1,4 +1,3 @@ - #include "recordbuttonbar.hpp" #include diff --git a/apps/opencs/view/world/referenceablecreator.cpp b/apps/opencs/view/world/referenceablecreator.cpp index e8055ed31..1357ca46f 100644 --- a/apps/opencs/view/world/referenceablecreator.cpp +++ b/apps/opencs/view/world/referenceablecreator.cpp @@ -1,4 +1,3 @@ - #include "referenceablecreator.hpp" #include diff --git a/apps/opencs/view/world/referencecreator.cpp b/apps/opencs/view/world/referencecreator.cpp index 2b0d44df0..73ca62e02 100644 --- a/apps/opencs/view/world/referencecreator.cpp +++ b/apps/opencs/view/world/referencecreator.cpp @@ -1,4 +1,3 @@ - #include "referencecreator.hpp" #include diff --git a/apps/opencs/view/world/regionmap.cpp b/apps/opencs/view/world/regionmap.cpp index bc96b0952..49764bd17 100644 --- a/apps/opencs/view/world/regionmap.cpp +++ b/apps/opencs/view/world/regionmap.cpp @@ -1,4 +1,3 @@ - #include "regionmap.hpp" #include diff --git a/apps/opencs/view/world/regionmapsubview.cpp b/apps/opencs/view/world/regionmapsubview.cpp index 411e24e75..996d1dc8b 100644 --- a/apps/opencs/view/world/regionmapsubview.cpp +++ b/apps/opencs/view/world/regionmapsubview.cpp @@ -1,4 +1,3 @@ - #include "regionmapsubview.hpp" #include "regionmap.hpp" diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index b7a795e23..2ca2548c0 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -1,4 +1,3 @@ - #include "scenesubview.hpp" #include diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index 415e6c9dc..b44e1c0bd 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -1,4 +1,3 @@ - #include "scripterrortable.hpp" #include diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp index 4923a44d8..487b5b139 100644 --- a/apps/opencs/view/world/scripthighlighter.cpp +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -1,4 +1,3 @@ - #include "scripthighlighter.hpp" #include diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index b8a6ba429..299ac6ebe 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -1,4 +1,3 @@ - #include "subviews.hpp" #include "../doc/subviewfactoryimp.hpp" diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 41c33761e..72e0c82d0 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -1,4 +1,3 @@ - #include "table.hpp" #include diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index 7e66106fc..eed522227 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -1,4 +1,3 @@ - #include "tablebottombox.hpp" #include diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 5fd094506..81b269993 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -1,4 +1,3 @@ - #include "tablesubview.hpp" #include diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index f21658581..2654644c4 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -1,4 +1,3 @@ - #include "util.hpp" #include diff --git a/apps/opencs/view/world/vartypedelegate.cpp b/apps/opencs/view/world/vartypedelegate.cpp index 90a686a67..a63e6028c 100644 --- a/apps/opencs/view/world/vartypedelegate.cpp +++ b/apps/opencs/view/world/vartypedelegate.cpp @@ -1,4 +1,3 @@ - #include "vartypedelegate.hpp" #include diff --git a/apps/openmw/android_commandLine.h b/apps/openmw/android_commandLine.h index 21d1064c6..5ca79c2d0 100644 --- a/apps/openmw/android_commandLine.h +++ b/apps/openmw/android_commandLine.h @@ -1,5 +1,4 @@ - /* DO NOT EDIT THIS FILE - it is machine generated */ #include #ifndef _Included_ui_activity_GameActivity_commandLine diff --git a/apps/openmw/mwbase/environment.cpp b/apps/openmw/mwbase/environment.cpp index a90eec5bf..4efa7c273 100644 --- a/apps/openmw/mwbase/environment.cpp +++ b/apps/openmw/mwbase/environment.cpp @@ -1,4 +1,3 @@ - #include "environment.hpp" #include diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 4cf33ceb8..3a0f1b951 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -1,4 +1,3 @@ - #include "activator.hpp" #include diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 6f11a36c7..f93556ef9 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -1,4 +1,3 @@ - #include "apparatus.hpp" #include diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 04c98e437..2ba8ba03b 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -1,4 +1,3 @@ - #include "armor.hpp" #include diff --git a/apps/openmw/mwclass/classes.cpp b/apps/openmw/mwclass/classes.cpp index e9538a6cb..c303b23af 100644 --- a/apps/openmw/mwclass/classes.cpp +++ b/apps/openmw/mwclass/classes.cpp @@ -1,4 +1,3 @@ - #include "classes.hpp" #include "activator.hpp" diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 8964b65e0..cea30d561 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -1,4 +1,3 @@ - #include "clothing.hpp" #include diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 830493627..f785797c1 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -1,4 +1,3 @@ - #include "container.hpp" #include diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 8b7bcf6b9..60874bb5e 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -1,4 +1,3 @@ - #include "creature.hpp" #include diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index dbc4b6af7..433e5fcea 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -1,4 +1,3 @@ - #include "creaturelevlist.hpp" #include diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 5062cc557..6749afa6b 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -1,4 +1,3 @@ - #include "door.hpp" #include diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index fb409cb55..c9e6e70f2 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -1,4 +1,3 @@ - #include "ingredient.hpp" #include diff --git a/apps/openmw/mwclass/itemlevlist.cpp b/apps/openmw/mwclass/itemlevlist.cpp index d31080bb2..a70f31115 100644 --- a/apps/openmw/mwclass/itemlevlist.cpp +++ b/apps/openmw/mwclass/itemlevlist.cpp @@ -1,4 +1,3 @@ - #include "itemlevlist.hpp" #include diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 1e882b568..c532b5d65 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -1,4 +1,3 @@ - #include "light.hpp" #include diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 8f22c3fa1..5cffdf13a 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -1,4 +1,3 @@ - #include "lockpick.hpp" #include diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 0c80209f2..98b4faab9 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -1,4 +1,3 @@ - #include "misc.hpp" #include diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 75b612dad..e2b714a64 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1,4 +1,3 @@ - #include "npc.hpp" #include diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 647f83f67..cf6b0919b 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -1,4 +1,3 @@ - #include "potion.hpp" #include diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index cb43ccce6..ff717c506 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -1,4 +1,3 @@ - #include "probe.hpp" #include diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 0bc64a99e..e6baea2e0 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -1,4 +1,3 @@ - #include "repair.hpp" #include diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 6438046de..9755df28e 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -1,4 +1,3 @@ - #include "static.hpp" #include diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 8c3d7fb10..da4c7deb2 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -1,4 +1,3 @@ - #include "weapon.hpp" #include diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 042267ebe..35f205eb8 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -1,4 +1,3 @@ - #include "dialoguemanagerimp.hpp" #include diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 29fac1c67..5e6b83b50 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -1,4 +1,3 @@ - #include "filter.hpp" #include diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index 9f07f7b6f..2f5f02b01 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -1,4 +1,3 @@ - #include "journalentry.hpp" #include diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 99dab0cf8..e6ffe22ab 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -1,4 +1,3 @@ - #include "journalimp.hpp" #include diff --git a/apps/openmw/mwdialogue/quest.cpp b/apps/openmw/mwdialogue/quest.cpp index a9e39b379..846597886 100644 --- a/apps/openmw/mwdialogue/quest.cpp +++ b/apps/openmw/mwdialogue/quest.cpp @@ -1,4 +1,3 @@ - #include "quest.hpp" #include diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index fa0fbfe13..a4eba30ae 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -1,4 +1,3 @@ - #include "selectwrapper.hpp" #include diff --git a/apps/openmw/mwdialogue/topic.cpp b/apps/openmw/mwdialogue/topic.cpp index c1a45f841..eb7fbdc1d 100644 --- a/apps/openmw/mwdialogue/topic.cpp +++ b/apps/openmw/mwdialogue/topic.cpp @@ -1,4 +1,3 @@ - #include "topic.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index b2f172076..384bccfea 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -1,4 +1,3 @@ - #ifndef MWGUI_TOOLTIPS_H #define MWGUI_TOOLTIPS_H diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index dd25e5a55..38d85a7cd 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -1,4 +1,3 @@ - #include "alchemy.hpp" #include diff --git a/apps/openmw/mwmechanics/magiceffects.cpp b/apps/openmw/mwmechanics/magiceffects.cpp index 0b19df0a8..021691d6a 100644 --- a/apps/openmw/mwmechanics/magiceffects.cpp +++ b/apps/openmw/mwmechanics/magiceffects.cpp @@ -1,4 +1,3 @@ - #include "magiceffects.hpp" #include diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index b9aa8b301..10d603ff1 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -1,4 +1,3 @@ - #include "npcstats.hpp" #include diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index fe0f892db..6d7673a59 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -1,4 +1,3 @@ - #include "spells.hpp" #include diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 4a7952c44..78c84141a 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -1,4 +1,3 @@ - #include "aiextensions.hpp" #include diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index c43cdf565..07a8a300a 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -1,4 +1,3 @@ - #include "animationextensions.hpp" #include diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index 3ff75eeae..083f463bc 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -1,4 +1,3 @@ - #include "compilercontext.hpp" #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwscript/consoleextensions.cpp b/apps/openmw/mwscript/consoleextensions.cpp index 30956d429..d2e07d3e1 100644 --- a/apps/openmw/mwscript/consoleextensions.cpp +++ b/apps/openmw/mwscript/consoleextensions.cpp @@ -1,4 +1,3 @@ - #include "consoleextensions.hpp" #include diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index ba18d8e37..674973978 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -1,4 +1,3 @@ - #include "containerextensions.hpp" #include diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index 904e0ee85..626fafb5a 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -1,4 +1,3 @@ - #include "controlextensions.hpp" #include diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 8b6805264..c305fb81f 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -1,4 +1,3 @@ - #include "dialogueextensions.hpp" #include diff --git a/apps/openmw/mwscript/extensions.cpp b/apps/openmw/mwscript/extensions.cpp index 2170ba4fb..12bf3413a 100644 --- a/apps/openmw/mwscript/extensions.cpp +++ b/apps/openmw/mwscript/extensions.cpp @@ -1,4 +1,3 @@ - #include "extensions.hpp" #include diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 44d96e949..f339fa520 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -1,4 +1,3 @@ - #include "globalscripts.hpp" #include diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 40c555f50..f48360c04 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -1,4 +1,3 @@ - #include "guiextensions.hpp" #include diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index df675aebb..b0d4d3f2d 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -1,4 +1,3 @@ - #include "interpretercontext.hpp" #include diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 9a9127977..faf574993 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1,4 +1,3 @@ - #include "miscextensions.hpp" #include diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 5f755e542..084beb812 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -1,4 +1,3 @@ - #include "scriptmanagerimp.hpp" #include diff --git a/apps/openmw/mwscript/skyextensions.cpp b/apps/openmw/mwscript/skyextensions.cpp index d28d01b63..e0fccd16d 100644 --- a/apps/openmw/mwscript/skyextensions.cpp +++ b/apps/openmw/mwscript/skyextensions.cpp @@ -1,4 +1,3 @@ - #include "skyextensions.hpp" #include diff --git a/apps/openmw/mwscript/soundextensions.cpp b/apps/openmw/mwscript/soundextensions.cpp index 606de7aa0..a9896d203 100644 --- a/apps/openmw/mwscript/soundextensions.cpp +++ b/apps/openmw/mwscript/soundextensions.cpp @@ -1,4 +1,3 @@ - #include "extensions.hpp" #include diff --git a/apps/openmw/mwscript/userextensions.cpp b/apps/openmw/mwscript/userextensions.cpp index 538133c65..165a93062 100644 --- a/apps/openmw/mwscript/userextensions.cpp +++ b/apps/openmw/mwscript/userextensions.cpp @@ -1,4 +1,3 @@ - #include "userextensions.hpp" #include diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index fcd1ca19e..733ac1171 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -1,4 +1,3 @@ - #include "character.hpp" #include diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp index 70e9f0925..22192c355 100644 --- a/apps/openmw/mwstate/charactermanager.cpp +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -1,4 +1,3 @@ - #include "charactermanager.hpp" #include diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index ac8dc863a..f4a7ee9f2 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -1,4 +1,3 @@ - #include "statemanagerimp.hpp" #include diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index 5e1fb41a6..fb2059de9 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -1,4 +1,3 @@ - #include "action.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/actionapply.cpp b/apps/openmw/mwworld/actionapply.cpp index bfd64c85d..00c9628ce 100644 --- a/apps/openmw/mwworld/actionapply.cpp +++ b/apps/openmw/mwworld/actionapply.cpp @@ -1,4 +1,3 @@ - #include "actionapply.hpp" #include "class.hpp" diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 8bb80b564..d9ca4aaf5 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -1,4 +1,3 @@ - #include "actioneat.hpp" #include diff --git a/apps/openmw/mwworld/actionopen.hpp b/apps/openmw/mwworld/actionopen.hpp index 8578995ae..454cc09f1 100644 --- a/apps/openmw/mwworld/actionopen.hpp +++ b/apps/openmw/mwworld/actionopen.hpp @@ -1,4 +1,3 @@ - #ifndef GAME_MWWORLD_ACTIONOPEN_H #define GAME_MWWORLD_ACTIONOPEN_H diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index 269d941dc..4e6135764 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -1,4 +1,3 @@ - #include "actiontake.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index 905497f85..051380ff5 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -1,4 +1,3 @@ - #include "actiontalk.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 18200e33b..4c73c603b 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -1,4 +1,3 @@ - #include "class.hpp" #include diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 3a7c02332..05ae4f134 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -1,4 +1,3 @@ - #include "containerstore.hpp" #include diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index e7cb04590..dcd7924a2 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -1,4 +1,3 @@ - #include "globals.hpp" #include diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 2fe914a4e..2dbc22234 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -1,4 +1,3 @@ - #include "inventorystore.hpp" #include diff --git a/apps/openmw/mwworld/ptr.cpp b/apps/openmw/mwworld/ptr.cpp index 1cf22744a..4d74c3c58 100644 --- a/apps/openmw/mwworld/ptr.cpp +++ b/apps/openmw/mwworld/ptr.cpp @@ -1,4 +1,3 @@ - #include "ptr.hpp" #include diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index c4f63137a..2062e78d9 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -1,4 +1,3 @@ - #include "refdata.hpp" #include diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index aefe6d16d..b202467db 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -1,4 +1,3 @@ - #include "controlparser.hpp" #include diff --git a/components/compiler/declarationparser.cpp b/components/compiler/declarationparser.cpp index 7961b8f41..ffac252d5 100644 --- a/components/compiler/declarationparser.cpp +++ b/components/compiler/declarationparser.cpp @@ -1,4 +1,3 @@ - #include "declarationparser.hpp" #include diff --git a/components/compiler/discardparser.cpp b/components/compiler/discardparser.cpp index 6028968bb..da114fb3d 100644 --- a/components/compiler/discardparser.cpp +++ b/components/compiler/discardparser.cpp @@ -1,4 +1,3 @@ - #include "discardparser.hpp" #include "scanner.hpp" diff --git a/components/compiler/errorhandler.cpp b/components/compiler/errorhandler.cpp index bcd30ef2d..a987a86da 100644 --- a/components/compiler/errorhandler.cpp +++ b/components/compiler/errorhandler.cpp @@ -1,4 +1,3 @@ - #include "errorhandler.hpp" namespace Compiler diff --git a/components/compiler/errorhandler.hpp b/components/compiler/errorhandler.hpp index c92e7bb8d..ea904e385 100644 --- a/components/compiler/errorhandler.hpp +++ b/components/compiler/errorhandler.hpp @@ -1,4 +1,3 @@ - #ifndef COMPILER_ERRORHANDLER_H_INCLUDED #define COMPILER_ERRORHANDLER_H_INCLUDED diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 1818d04df..b588b6196 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -1,4 +1,3 @@ - #include "exprparser.hpp" #include diff --git a/components/compiler/extensions.cpp b/components/compiler/extensions.cpp index c2b11c615..dbb953e20 100644 --- a/components/compiler/extensions.cpp +++ b/components/compiler/extensions.cpp @@ -1,4 +1,3 @@ - #include "extensions.hpp" #include diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index ead0c7290..7e6437e20 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -1,4 +1,3 @@ - #include "generator.hpp" #include diff --git a/components/compiler/junkparser.cpp b/components/compiler/junkparser.cpp index cfa94044e..7608e9bab 100644 --- a/components/compiler/junkparser.cpp +++ b/components/compiler/junkparser.cpp @@ -1,4 +1,3 @@ - #include "junkparser.hpp" #include "scanner.hpp" diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 4d6e147fc..032af7d65 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -1,4 +1,3 @@ - #include "lineparser.hpp" #include diff --git a/components/compiler/literals.cpp b/components/compiler/literals.cpp index 626b03afb..ee2c4d345 100644 --- a/components/compiler/literals.cpp +++ b/components/compiler/literals.cpp @@ -1,4 +1,3 @@ - #include "literals.hpp" #include diff --git a/components/compiler/locals.cpp b/components/compiler/locals.cpp index 60a5704bf..768fc077c 100644 --- a/components/compiler/locals.cpp +++ b/components/compiler/locals.cpp @@ -1,4 +1,3 @@ - #include "locals.hpp" #include diff --git a/components/compiler/nullerrorhandler.cpp b/components/compiler/nullerrorhandler.cpp index ee2884705..a0db53a00 100644 --- a/components/compiler/nullerrorhandler.cpp +++ b/components/compiler/nullerrorhandler.cpp @@ -1,4 +1,3 @@ - #include "nullerrorhandler.hpp" void Compiler::NullErrorHandler::report (const std::string& message, const TokenLoc& loc, Type type) {} diff --git a/components/compiler/nullerrorhandler.hpp b/components/compiler/nullerrorhandler.hpp index bb4db99a2..3dcff9250 100644 --- a/components/compiler/nullerrorhandler.hpp +++ b/components/compiler/nullerrorhandler.hpp @@ -1,4 +1,3 @@ - #ifndef COMPILER_NULLERRORHANDLER_H_INCLUDED #define COMPILER_NULLERRORHANDLER_H_INCLUDED diff --git a/components/compiler/output.cpp b/components/compiler/output.cpp index 46e04b8dc..785b2ce84 100644 --- a/components/compiler/output.cpp +++ b/components/compiler/output.cpp @@ -1,4 +1,3 @@ - #include "output.hpp" #include diff --git a/components/compiler/parser.cpp b/components/compiler/parser.cpp index 0f442c350..fe019718a 100644 --- a/components/compiler/parser.cpp +++ b/components/compiler/parser.cpp @@ -1,4 +1,3 @@ - #include "parser.hpp" #include diff --git a/components/compiler/quickfileparser.cpp b/components/compiler/quickfileparser.cpp index 4e9f76e13..53aaf96e5 100644 --- a/components/compiler/quickfileparser.cpp +++ b/components/compiler/quickfileparser.cpp @@ -1,4 +1,3 @@ - #include "quickfileparser.hpp" #include "skipparser.hpp" diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index de7f7e1e1..5af396d27 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -1,4 +1,3 @@ - #include "scanner.hpp" #include diff --git a/components/compiler/scriptparser.cpp b/components/compiler/scriptparser.cpp index ea11be5f0..a3bf23288 100644 --- a/components/compiler/scriptparser.cpp +++ b/components/compiler/scriptparser.cpp @@ -1,4 +1,3 @@ - #include "scriptparser.hpp" #include "scanner.hpp" diff --git a/components/compiler/skipparser.cpp b/components/compiler/skipparser.cpp index c7cb31f58..3e704253d 100644 --- a/components/compiler/skipparser.cpp +++ b/components/compiler/skipparser.cpp @@ -1,4 +1,3 @@ - #include "skipparser.hpp" #include "scanner.hpp" diff --git a/components/compiler/streamerrorhandler.cpp b/components/compiler/streamerrorhandler.cpp index fc1a05943..9ca8aa74b 100644 --- a/components/compiler/streamerrorhandler.cpp +++ b/components/compiler/streamerrorhandler.cpp @@ -1,4 +1,3 @@ - #include "streamerrorhandler.hpp" #include "tokenloc.hpp" diff --git a/components/compiler/streamerrorhandler.hpp b/components/compiler/streamerrorhandler.hpp index 96e02b588..85de1833a 100644 --- a/components/compiler/streamerrorhandler.hpp +++ b/components/compiler/streamerrorhandler.hpp @@ -1,4 +1,3 @@ - #ifndef COMPILER_STREAMERRORHANDLER_H_INCLUDED #define COMPILER_STREAMERRORHANDLER_H_INCLUDED diff --git a/components/compiler/stringparser.cpp b/components/compiler/stringparser.cpp index 7a2098fb3..f8798eccd 100644 --- a/components/compiler/stringparser.cpp +++ b/components/compiler/stringparser.cpp @@ -1,4 +1,3 @@ - #include "stringparser.hpp" #include diff --git a/components/esm/cellid.cpp b/components/esm/cellid.cpp index c77b27b22..f77e2eb55 100644 --- a/components/esm/cellid.cpp +++ b/components/esm/cellid.cpp @@ -1,4 +1,3 @@ - #include "cellid.hpp" #include "esmreader.hpp" diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index c3b889df5..33ac4a91e 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -1,4 +1,3 @@ - #include "cellref.hpp" #include "esmreader.hpp" diff --git a/components/esm/cellstate.cpp b/components/esm/cellstate.cpp index 4df04d0e5..83b130dcd 100644 --- a/components/esm/cellstate.cpp +++ b/components/esm/cellstate.cpp @@ -1,4 +1,3 @@ - #include "cellstate.hpp" #include "esmreader.hpp" diff --git a/components/esm/containerstate.cpp b/components/esm/containerstate.cpp index 80ad5cbdc..301549d59 100644 --- a/components/esm/containerstate.cpp +++ b/components/esm/containerstate.cpp @@ -1,4 +1,3 @@ - #include "containerstate.hpp" void ESM::ContainerState::load (ESMReader &esm) diff --git a/components/esm/creaturestate.cpp b/components/esm/creaturestate.cpp index c15becd98..bffa4e5e4 100644 --- a/components/esm/creaturestate.cpp +++ b/components/esm/creaturestate.cpp @@ -1,4 +1,3 @@ - #include "creaturestate.hpp" void ESM::CreatureState::load (ESMReader &esm) diff --git a/components/esm/debugprofile.cpp b/components/esm/debugprofile.cpp index 6c05fac2a..9d605a6af 100644 --- a/components/esm/debugprofile.cpp +++ b/components/esm/debugprofile.cpp @@ -1,4 +1,3 @@ - #include "debugprofile.hpp" #include "esmreader.hpp" diff --git a/components/esm/dialoguestate.cpp b/components/esm/dialoguestate.cpp index f302e36dc..2b1887e4e 100644 --- a/components/esm/dialoguestate.cpp +++ b/components/esm/dialoguestate.cpp @@ -1,4 +1,3 @@ - #include "dialoguestate.hpp" #include "esmreader.hpp" diff --git a/components/esm/filter.cpp b/components/esm/filter.cpp index a80427bbe..5bc768f72 100644 --- a/components/esm/filter.cpp +++ b/components/esm/filter.cpp @@ -1,4 +1,3 @@ - #include "filter.hpp" #include "esmreader.hpp" diff --git a/components/esm/globalscript.cpp b/components/esm/globalscript.cpp index 0129f8eb7..a42cdc230 100644 --- a/components/esm/globalscript.cpp +++ b/components/esm/globalscript.cpp @@ -1,4 +1,3 @@ - #include "globalscript.hpp" #include "esmreader.hpp" diff --git a/components/esm/inventorystate.cpp b/components/esm/inventorystate.cpp index 4eaaa9f9f..e7257ae53 100644 --- a/components/esm/inventorystate.cpp +++ b/components/esm/inventorystate.cpp @@ -1,4 +1,3 @@ - #include "inventorystate.hpp" #include "esmreader.hpp" diff --git a/components/esm/journalentry.cpp b/components/esm/journalentry.cpp index 445213de4..93011e581 100644 --- a/components/esm/journalentry.cpp +++ b/components/esm/journalentry.cpp @@ -1,4 +1,3 @@ - #include "journalentry.hpp" #include "esmreader.hpp" diff --git a/components/esm/loadtes3.cpp b/components/esm/loadtes3.cpp index 7d749c4d9..df35a2579 100644 --- a/components/esm/loadtes3.cpp +++ b/components/esm/loadtes3.cpp @@ -1,4 +1,3 @@ - #include "loadtes3.hpp" #include "esmcommon.hpp" diff --git a/components/esm/locals.cpp b/components/esm/locals.cpp index f0cfd49f0..bd51be08f 100644 --- a/components/esm/locals.cpp +++ b/components/esm/locals.cpp @@ -1,4 +1,3 @@ - #include "locals.hpp" #include "esmreader.hpp" diff --git a/components/esm/npcstate.cpp b/components/esm/npcstate.cpp index 724d67326..6c9988d50 100644 --- a/components/esm/npcstate.cpp +++ b/components/esm/npcstate.cpp @@ -1,4 +1,3 @@ - #include "npcstate.hpp" void ESM::NpcState::load (ESMReader &esm) diff --git a/components/esm/objectstate.cpp b/components/esm/objectstate.cpp index 0ae690ee8..62aa0452a 100644 --- a/components/esm/objectstate.cpp +++ b/components/esm/objectstate.cpp @@ -1,4 +1,3 @@ - #include "objectstate.hpp" #include "esmreader.hpp" diff --git a/components/esm/player.cpp b/components/esm/player.cpp index e64cefc30..9ec53240a 100644 --- a/components/esm/player.cpp +++ b/components/esm/player.cpp @@ -1,4 +1,3 @@ - #include "player.hpp" #include "esmreader.hpp" diff --git a/components/esm/queststate.cpp b/components/esm/queststate.cpp index c8cff7adc..5408cd2ff 100644 --- a/components/esm/queststate.cpp +++ b/components/esm/queststate.cpp @@ -1,4 +1,3 @@ - #include "queststate.hpp" #include "esmreader.hpp" diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index 9cdb28766..2e5509b7a 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -1,4 +1,3 @@ - #include "savedgame.hpp" #include "esmreader.hpp" diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp index eeb0bf04f..aeea5017e 100644 --- a/components/esm/variantimp.cpp +++ b/components/esm/variantimp.cpp @@ -1,4 +1,3 @@ - #include "variantimp.hpp" #include diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index 1abbae3ae..7b3b0c440 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -1,4 +1,3 @@ - #include "multidircollection.hpp" #include diff --git a/components/interpreter/installopcodes.cpp b/components/interpreter/installopcodes.cpp index d705a109c..31e911f8b 100644 --- a/components/interpreter/installopcodes.cpp +++ b/components/interpreter/installopcodes.cpp @@ -1,4 +1,3 @@ - #include "installopcodes.hpp" #include diff --git a/components/interpreter/interpreter.cpp b/components/interpreter/interpreter.cpp index f5dee0dba..263cea9a5 100644 --- a/components/interpreter/interpreter.cpp +++ b/components/interpreter/interpreter.cpp @@ -1,4 +1,3 @@ - #include "interpreter.hpp" #include diff --git a/components/interpreter/runtime.cpp b/components/interpreter/runtime.cpp index dc3da07a8..6599882f1 100644 --- a/components/interpreter/runtime.cpp +++ b/components/interpreter/runtime.cpp @@ -1,4 +1,3 @@ - #include "runtime.hpp" #include diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 602397743..dc9e8ea84 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -1,4 +1,3 @@ - # Copy resource files into the build directory set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) set(DDIR ${OpenMW_BINARY_DIR}/resources/mygui) From 681183df31a1b695b119a6ab6049a4083b796aaf Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 19 Aug 2015 01:13:14 +0200 Subject: [PATCH 275/419] Restore handling of fog depth == 0 values (Bug #1549) --- apps/openmw/mwrender/renderingmanager.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b01095f12..bac8fca6c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -379,8 +379,17 @@ namespace MWRender else { setFogColor(mFogColor); - mStateUpdater->setFogStart(mViewDistance * (1 - mFogDepth)); - mStateUpdater->setFogEnd(mViewDistance); + + if (mFogDepth == 0.f) + { + mStateUpdater->setFogStart(0.f); + mStateUpdater->setFogEnd(FLT_MAX); + } + else + { + mStateUpdater->setFogStart(mViewDistance * (1 - mFogDepth)); + mStateUpdater->setFogEnd(mViewDistance); + } } } From 232dfdc07e978a690d0320915684af403ce9b7d2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 19 Aug 2015 01:24:54 +0200 Subject: [PATCH 276/419] Make an error message slightly more helpful --- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/objects.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 83931ba15..9efb866d4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1255,7 +1255,7 @@ namespace MWMechanics } else { - std::cerr<< "Error in Actors::playAnimationGroup: Unable to find " << ptr.getTypeName() << std::endl; + std::cerr<< "Error in Actors::playAnimationGroup: Unable to find " << ptr.getCellRef().getRefId() << std::endl; return false; } } diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp index a0e9cd242..94b552a38 100644 --- a/apps/openmw/mwmechanics/objects.cpp +++ b/apps/openmw/mwmechanics/objects.cpp @@ -88,7 +88,7 @@ bool Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& gro } else { - std::cerr<< "Error in Objects::playAnimationGroup: Unable to find " << ptr.getTypeName() << std::endl; + std::cerr<< "Error in Objects::playAnimationGroup: Unable to find " << ptr.getCellRef().getRefId() << std::endl; return false; } } From e1baf1ea48526c8b5e5d1ffe005573ca3b70676f Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 09:51:04 -0400 Subject: [PATCH 277/419] NPCs scream when they die --- apps/openmw/mwmechanics/actors.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 9efb866d4..f6ad5906b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -18,6 +18,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -1175,6 +1176,12 @@ namespace MWMechanics if (iter->second->getCharacterController()->kill()) { + // TODO: It's not known whether the soundgen tags scream, roar, and moan are reliable + // for NPCs since some of the npc death animation files are missing them. + + // Play dying words + MWBase::Environment::get().getDialogueManager()->say(iter->first, "hit"); + iter->first.getClass().getCreatureStats(iter->first).notifyDied(); ++mDeathCount[Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId())]; From e86891d6e16508229732dfb55dd9bae27780ceb7 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 10:05:08 -0400 Subject: [PATCH 278/419] Time played displayed in save/load menus --- apps/openmw/mwgui/savegamedialog.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 82dd0d8a9..4559fc695 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -1,5 +1,8 @@ #include "savegamedialog.hpp" +#include +#include + #include #include #include @@ -309,6 +312,21 @@ namespace MWGui onSlotSelected(mSaveList, MyGUI::ITEM_NONE); } + std::string formatTimeplayed(const long int timePlayed) + { + int days = timePlayed / 60 / 60 / 24; + int hours = (timePlayed / 60 / 60) % 24; + int minutes = (timePlayed / 60) % 60; + int seconds = timePlayed % 60; + + std::stringstream stream; + stream << std::setfill('0') << std::setw(2) << days << ":"; + stream << std::setfill('0') << std::setw(2) << hours << ":"; + stream << std::setfill('0') << std::setw(2) << minutes << ":"; + stream << std::setfill('0') << std::setw(2) << seconds; + return stream.str(); + } + void SaveGameDialog::onSlotSelected(MyGUI::ListBox *sender, size_t pos) { mOkButton->setEnabled(pos != MyGUI::ITEM_NONE || mSaving); @@ -349,7 +367,6 @@ namespace MWGui text << buffer << "\n"; text << "#{sLevel} " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; text << "#{sCell=" << mCurrentSlot->mProfile.mPlayerCell << "}\n"; - // text << "Time played: " << slot->mProfile.mTimePlayed << "\n"; int hour = int(mCurrentSlot->mProfile.mInGameTime.mGameHour); bool pm = hour >= 12; @@ -359,7 +376,9 @@ namespace MWGui text << mCurrentSlot->mProfile.mInGameTime.mDay << " " << MWBase::Environment::get().getWorld()->getMonthName(mCurrentSlot->mProfile.mInGameTime.mMonth) - << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); + << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}")<< "\n"; + + text << "Time played: " << formatTimeplayed((int)floor(mCurrentSlot->mProfile.mTimePlayed)); mInfoText->setCaptionWithReplacing(text.str()); From 69729046bf669235e69f0de7b750358da1b9f769 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 10:11:40 -0400 Subject: [PATCH 279/419] Updated parameter name to reflect units --- apps/openmw/mwgui/savegamedialog.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 4559fc695..83b458a2b 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -312,12 +312,12 @@ namespace MWGui onSlotSelected(mSaveList, MyGUI::ITEM_NONE); } - std::string formatTimeplayed(const long int timePlayed) + std::string formatTimeplayed(const long int timeInSeconds) { - int days = timePlayed / 60 / 60 / 24; - int hours = (timePlayed / 60 / 60) % 24; - int minutes = (timePlayed / 60) % 60; - int seconds = timePlayed % 60; + int days = timeInSeconds / 60 / 60 / 24; + int hours = (timeInSeconds / 60 / 60) % 24; + int minutes = (timeInSeconds / 60) % 60; + int seconds = timeInSeconds % 60; std::stringstream stream; stream << std::setfill('0') << std::setw(2) << days << ":"; From d91f197119ac6cfb1ed6002c48ff1c50f83674c3 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 11:31:43 -0400 Subject: [PATCH 280/419] Time played display setting --- apps/openmw/mwgui/savegamedialog.cpp | 7 +++++-- files/settings-default.cfg | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 83b458a2b..0375bfda3 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -376,9 +376,12 @@ namespace MWGui text << mCurrentSlot->mProfile.mInGameTime.mDay << " " << MWBase::Environment::get().getWorld()->getMonthName(mCurrentSlot->mProfile.mInGameTime.mMonth) - << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}")<< "\n"; + << " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); - text << "Time played: " << formatTimeplayed((int)floor(mCurrentSlot->mProfile.mTimePlayed)); + if (Settings::Manager::getBool("timeplayed","Saves")) + { + text << "\n" << "Time played: " << formatTimeplayed((int)floor(mCurrentSlot->mProfile.mTimePlayed)); + } mInfoText->setCaptionWithReplacing(text.str()); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 0f7349eb9..f2b6aa34f 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -177,6 +177,8 @@ show owned = 0 character = # Save when resting autosave = true +# display time played +timeplayed = false [Windows] inventory x = 0 From 4a68ceaeb7561f6d00cd25d80b075956c8f6fd39 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 19 Aug 2015 19:06:24 +0200 Subject: [PATCH 281/419] Restrict the OS X cursor workaround to Intel graphics systems --- components/sdlutil/sdlcursormanager.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 70a159306..b64b68132 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -127,11 +127,13 @@ namespace glViewport(0, 0, width, height); #if defined(__APPLE__) - // FIXME: why are the extra flips needed on Mac? glReadPixels bug? - osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,1,0), osg::Vec3(2,0,0), osg::Vec3(0,-2,0)); -#else - osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); + // Extra flip needed on Intel graphics OS X systems due to a driver bug + std::string vendorString = (const char*)glGetString(GL_VENDOR); + if (vendorString.find("Intel") != std::string::npos) + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,1,0), osg::Vec3(2,0,0), osg::Vec3(0,-2,0)); + else #endif + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); geom->drawImplementation(renderInfo); From 61bb55aff40d9efb594ced44799b7bda98d2ca23 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 13:23:40 -0400 Subject: [PATCH 282/419] Removed long int parameter --- apps/openmw/mwgui/savegamedialog.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 0375bfda3..3d509e9fd 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -1,5 +1,6 @@ #include "savegamedialog.hpp" +#include #include #include @@ -312,12 +313,13 @@ namespace MWGui onSlotSelected(mSaveList, MyGUI::ITEM_NONE); } - std::string formatTimeplayed(const long int timeInSeconds) + std::string formatTimeplayed(const double timeInSeconds) { - int days = timeInSeconds / 60 / 60 / 24; - int hours = (timeInSeconds / 60 / 60) % 24; - int minutes = (timeInSeconds / 60) % 60; - int seconds = timeInSeconds % 60; + int timePlayed = (int)floor(timeInSeconds); + int days = timePlayed / 60 / 60 / 24; + int hours = (timePlayed / 60 / 60) % 24; + int minutes = (timePlayed / 60) % 60; + int seconds = timePlayed % 60; std::stringstream stream; stream << std::setfill('0') << std::setw(2) << days << ":"; @@ -380,7 +382,7 @@ namespace MWGui if (Settings::Manager::getBool("timeplayed","Saves")) { - text << "\n" << "Time played: " << formatTimeplayed((int)floor(mCurrentSlot->mProfile.mTimePlayed)); + text << "\n" << "Time played: " << formatTimeplayed(mCurrentSlot->mProfile.mTimePlayed); } mInfoText->setCaptionWithReplacing(text.str()); From f94d3237fcb9bae1a51e8f442029b2d4496060cb Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 19 Aug 2015 13:28:01 -0400 Subject: [PATCH 283/419] Removed unused cmake import --- apps/openmw/mwgui/savegamedialog.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 3d509e9fd..be9ef2139 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -1,6 +1,5 @@ #include "savegamedialog.hpp" -#include #include #include From 166df28906dcfa1e7758d9e97e5e4e0b6de781f7 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Wed, 19 Aug 2015 21:23:16 +0200 Subject: [PATCH 284/419] OS X cursor workaround build fix --- components/sdlutil/sdlcursormanager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index b64b68132..e1a67aff8 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -126,14 +126,16 @@ namespace glViewport(0, 0, width, height); + osg::ref_ptr geom; + #if defined(__APPLE__) // Extra flip needed on Intel graphics OS X systems due to a driver bug std::string vendorString = (const char*)glGetString(GL_VENDOR); if (vendorString.find("Intel") != std::string::npos) - osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,1,0), osg::Vec3(2,0,0), osg::Vec3(0,-2,0)); + geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,1,0), osg::Vec3(2,0,0), osg::Vec3(0,-2,0)); else #endif - osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); + geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0)); geom->drawImplementation(renderInfo); From ff5ef7055e843797a65d5174b9cd8f14d389ef4f Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 20 Aug 2015 18:12:37 +1200 Subject: [PATCH 285/419] extracted function CreatureStats::isParalyzed() --- apps/openmw/engine.cpp | 4 ++-- apps/openmw/mwmechanics/actors.cpp | 5 ++--- apps/openmw/mwmechanics/combat.cpp | 6 +++--- apps/openmw/mwmechanics/creaturestats.cpp | 5 +++++ apps/openmw/mwmechanics/creaturestats.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 5 ++--- 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 95851b75f..6b393ebcb 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -704,8 +704,8 @@ void OMW::Engine::activate() return; MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr(); - if (player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0 - || player.getClass().getCreatureStats(player).getKnockedDown()) + const MWMechanics::NpcStats &playerStats = player.getClass().getNpcStats(player); + if (playerStats.isParalyzed() || playerStats.getKnockedDown()) return; MWWorld::Ptr ptr = mEnvironment.getWorld()->getFacedObject(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 9efb866d4..2abd94eb3 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1037,8 +1037,7 @@ namespace MWMechanics > sqrProcessingDistance) continue; - if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get( - ESM::MagicEffect::Paralyze).getMagnitude() > 0) + if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed()) iter->second->getCharacterController()->skipAnim(); // Handle player last, in case a cell transition occurs by casting a teleportation spell @@ -1426,7 +1425,7 @@ namespace MWMechanics MWWorld::Ptr ptr = it->first; if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() || !isConscious(ptr) - || ptr.getClass().getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) + || ptr.getClass().getCreatureStats(ptr).isParalyzed()) continue; MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); seq.fastForward(ptr, it->second->getAiState()); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 097dcadc2..11619e4c3 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -60,7 +60,7 @@ namespace MWMechanics if (blockerStats.getKnockedDown() // Used for both knockout or knockdown || blockerStats.getHitRecovery() - || blockerStats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) + || blockerStats.isParalyzed()) return false; if (!MWBase::Environment::get().getMechanicsManager()->isReadyToBlock(blocker)) @@ -250,7 +250,7 @@ namespace MWMechanics && (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) && (!MWBase::Environment::get().getMechanicsManager()->awarenessCheck(attacker, victim)); if (!(victimStats.getKnockedDown() || - victimStats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0 + victimStats.isParalyzed() || unaware )) { defenseTerm = victimStats.getEvasion(); @@ -375,7 +375,7 @@ namespace MWMechanics damage *= minstrike + ((maxstrike-minstrike)*attackStrength); MWMechanics::CreatureStats& otherstats = victim.getClass().getCreatureStats(victim); - healthdmg = (otherstats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) + healthdmg = otherstats.isParalyzed() || otherstats.getKnockedDown(); bool isWerewolf = (attacker.getClass().isNpc() && attacker.getClass().getNpcStats(attacker).isWerewolf()); if(isWerewolf) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 48374c173..0638637fa 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -221,6 +221,11 @@ namespace MWMechanics setAiSetting(index, stat); } + bool CreatureStats::isParalyzed() const + { + return mMagicEffects.get(ESM::MagicEffect::Paralyze).getMagnitude() > 0; + } + bool CreatureStats::isDead() const { return mDead; diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 5d22da7cc..46c5bab31 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -155,6 +155,8 @@ namespace MWMechanics float getFatigueTerm() const; ///< Return effective fatigue + bool isParalyzed() const; + bool isDead() const; void notifyDied(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1eed841bd..4c9074eee 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1927,16 +1927,15 @@ namespace MWWorld bool World::isFlying(const MWWorld::Ptr &ptr) const { const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); - bool isParalyzed = (stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0); if(!ptr.getClass().isActor()) return false; - if (ptr.getClass().getCreatureStats(ptr).isDead()) + if (stats.isDead()) return false; if (ptr.getClass().canFly(ptr)) - return !isParalyzed; + return !stats.isParalyzed(); if(stats.getMagicEffects().get(ESM::MagicEffect::Levitate).getMagnitude() > 0 && isLevitationEnabled()) From 0ee7407101aedf4a0fa3910d437842399b7a452a Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 20 Aug 2015 18:17:02 +1200 Subject: [PATCH 286/419] extracted common sub-expressions. --- apps/openmw/mwclass/creature.cpp | 8 +++----- apps/openmw/mwmechanics/actors.cpp | 16 ++++++++-------- apps/openmw/mwmechanics/combat.cpp | 10 +++++----- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 11 ++++++----- apps/openmw/mwmechanics/spellcasting.cpp | 7 ++++--- apps/openmw/mwscript/statsextensions.cpp | 14 +++++++------- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 60874bb5e..5604aa783 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -603,11 +603,9 @@ namespace MWClass { float weight = getContainerStore (ptr).getWeight(); - const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); - - weight -= stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Feather)).getMagnitude(); - - weight += stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Burden)).getMagnitude(); + const MWMechanics::MagicEffects& effects = getCreatureStats(ptr).getMagicEffects(); + weight -= effects.get(ESM::MagicEffect::Feather).getMagnitude(); + weight += effects.get(ESM::MagicEffect::Burden).getMagnitude(); if (weight<0) weight = 0; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 2abd94eb3..584c4c320 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -538,19 +538,19 @@ namespace MWMechanics if (!creature || ptr.get()->mBase->mData.mType == ESM::Creature::Creatures) { Stat stat = creatureStats.getAiSetting(CreatureStats::AI_Fight); - stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::FrenzyHumanoid + creature).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid+creature).getMagnitude())); + stat.setModifier(static_cast(effects.get(ESM::MagicEffect::FrenzyHumanoid + creature).getMagnitude() + - effects.get(ESM::MagicEffect::CalmHumanoid+creature).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Fight, stat); stat = creatureStats.getAiSetting(CreatureStats::AI_Flee); - stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::DemoralizeHumanoid + creature).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::RallyHumanoid+creature).getMagnitude())); + stat.setModifier(static_cast(effects.get(ESM::MagicEffect::DemoralizeHumanoid + creature).getMagnitude() + - effects.get(ESM::MagicEffect::RallyHumanoid+creature).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Flee, stat); } if (creature && ptr.get()->mBase->mData.mType == ESM::Creature::Undead) { Stat stat = creatureStats.getAiSetting(CreatureStats::AI_Flee); - stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::TurnUndead).getMagnitude())); + stat.setModifier(static_cast(effects.get(ESM::MagicEffect::TurnUndead).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Flee, stat); } @@ -596,8 +596,8 @@ namespace MWMechanics // TODO: dirty flag for magic effects to avoid some unnecessary work below? // any value of calm > 0 will stop the actor from fighting - if ((creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid).getMagnitude() > 0 && ptr.getClass().isNpc()) - || (creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmCreature).getMagnitude() > 0 && !ptr.getClass().isNpc())) + if ((effects.get(ESM::MagicEffect::CalmHumanoid).getMagnitude() > 0 && ptr.getClass().isNpc()) + || (effects.get(ESM::MagicEffect::CalmCreature).getMagnitude() > 0 && !ptr.getClass().isNpc())) { for (std::list::const_iterator it = creatureStats.getAiSequence().begin(); it != creatureStats.getAiSequence().end(); ) { @@ -630,7 +630,7 @@ namespace MWMechanics for (std::map::iterator it = boundItemsMap.begin(); it != boundItemsMap.end(); ++it) { bool found = creatureStats.mBoundItems.find(it->first) != creatureStats.mBoundItems.end(); - float magnitude = creatureStats.getMagicEffects().get(it->first).getMagnitude(); + float magnitude = effects.get(it->first).getMagnitude(); if (found != (magnitude > 0)) { std::string itemGmst = it->second; diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 11619e4c3..2e20d0e1f 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -147,9 +147,9 @@ namespace MWMechanics void resistNormalWeapon(const MWWorld::Ptr &actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr &weapon, float &damage) { - MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); - float resistance = std::min(100.f, stats.getMagicEffects().get(ESM::MagicEffect::ResistNormalWeapons).getMagnitude() - - stats.getMagicEffects().get(ESM::MagicEffect::WeaknessToNormalWeapons).getMagnitude()); + const MWMechanics::MagicEffects& effects = actor.getClass().getCreatureStats(actor).getMagicEffects(); + float resistance = std::min(100.f, effects.get(ESM::MagicEffect::ResistNormalWeapons).getMagnitude() + - effects.get(ESM::MagicEffect::WeaknessToNormalWeapons).getMagnitude()); float multiplier = 1.f - resistance / 100.f; @@ -242,9 +242,9 @@ namespace MWMechanics const MWWorld::Store &gmst = world->getStore().get(); float defenseTerm = 0; - if (victim.getClass().getCreatureStats(victim).getFatigue().getCurrent() >= 0) + MWMechanics::CreatureStats& victimStats = victim.getClass().getCreatureStats(victim); + if (victimStats.getFatigue().getCurrent() >= 0) { - MWMechanics::CreatureStats& victimStats = victim.getClass().getCreatureStats(victim); // Maybe we should keep an aware state for actors updated every so often instead of testing every time bool unaware = (!victimStats.getAiSequence().isInCombat()) && (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 9436e35d2..075747ffe 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1310,11 +1310,12 @@ namespace MWMechanics return false; std::list followers = getActorsFollowing(attacker); + MWMechanics::CreatureStats& targetStats = ptr.getClass().getCreatureStats(ptr); if (std::find(followers.begin(), followers.end(), ptr) != followers.end()) { - ptr.getClass().getCreatureStats(ptr).friendlyHit(); + targetStats.friendlyHit(); - if (ptr.getClass().getCreatureStats(ptr).getFriendlyHits() < 4) + if (targetStats.getFriendlyHits() < 4) { MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); return false; @@ -1322,7 +1323,7 @@ namespace MWMechanics } // Attacking an NPC that is already in combat with any other NPC is not a crime - AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); + AiSequence& seq = targetStats.getAiSequence(); bool isFightingNpc = false; for (std::list::const_iterator it = seq.begin(); it != seq.end(); ++it) { @@ -1334,13 +1335,13 @@ namespace MWMechanics } } - if (ptr.getClass().isNpc() && !attacker.isEmpty() && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker) + if (ptr.getClass().isNpc() && !attacker.isEmpty() && !seq.isInCombat(attacker) && !isAggressive(ptr, attacker) && !isFightingNpc) commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault); if (!attacker.isEmpty() && (attacker.getClass().getCreatureStats(attacker).getAiSequence().isInCombat(ptr) || attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) - && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker)) + && !seq.isInCombat(attacker)) { // Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back. // Note: accidental or collateral damage attacks are ignored. diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index b98bf9f96..12ed04428 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -332,9 +332,10 @@ namespace MWMechanics const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search (mId); if (spell && (spell->mData.mType == ESM::Spell::ST_Disease || spell->mData.mType == ESM::Spell::ST_Blight)) { - float x = (spell->mData.mType == ESM::Spell::ST_Disease) ? - target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistCommonDisease).getMagnitude() - : target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistBlightDisease).getMagnitude(); + int requiredResistance = (spell->mData.mType == ESM::Spell::ST_Disease) ? + ESM::MagicEffect::ResistCommonDisease + : ESM::MagicEffect::ResistBlightDisease; + float x = target.getClass().getCreatureStats(target).getMagicEffects().get(requiredResistance).getMagnitude(); if (Misc::Rng::roll0to99() <= x) { diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 61a31e115..112e7c77f 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1159,10 +1159,10 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); - float currentValue = stats.getMagicEffects().get(mPositiveEffect).getMagnitude(); + const MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects(); + float currentValue = effects.get(mPositiveEffect).getMagnitude(); if (mNegativeEffect != -1) - currentValue -= stats.getMagicEffects().get(mNegativeEffect).getMagnitude(); + currentValue -= effects.get(mNegativeEffect).getMagnitude(); int ret = static_cast(currentValue); runtime.push(ret); @@ -1185,14 +1185,14 @@ namespace MWScript virtual void execute(Interpreter::Runtime &runtime) { MWWorld::Ptr ptr = R()(runtime); - MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); - float currentValue = stats.getMagicEffects().get(mPositiveEffect).getMagnitude(); + MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects(); + float currentValue = effects.get(mPositiveEffect).getMagnitude(); if (mNegativeEffect != -1) - currentValue -= stats.getMagicEffects().get(mNegativeEffect).getMagnitude(); + currentValue -= effects.get(mNegativeEffect).getMagnitude(); int arg = runtime[0].mInteger; runtime.pop(); - stats.getMagicEffects().modifyBase(mPositiveEffect, (arg - static_cast(currentValue))); + effects.modifyBase(mPositiveEffect, (arg - static_cast(currentValue))); } }; From c0d3804b4f3371d4498b771943121a1d249d4c62 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 20 Aug 2015 21:50:58 +1200 Subject: [PATCH 287/419] Correctly handle disjoint pathgrid (Fixes #2871) Bugfix: When 1. Cell has multiple subgrids (i.e. path grid is disjoint) 2. Distance between destination and pathgrid point 0 is less than distance to points of subgrid closest to start point Then getClosestReachablePoint() returns pathgrid point 0 as the end point. This is invalid, this end point cannot be reached from the start point. --- apps/openmw/mwmechanics/pathfinding.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 798a0ea21..9013d3269 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -53,7 +53,8 @@ namespace { assert(grid && !grid->mPoints.empty()); - float distanceBetween = distanceSquared(grid->mPoints[0], pos); + float closestDistanceBetween = distanceSquared(grid->mPoints[0], pos); + float closestDistanceReachable = closestDistanceBetween; int closestIndex = 0; int closestReachableIndex = 0; // TODO: if this full scan causes performance problems mapping pathgrid @@ -61,17 +62,25 @@ namespace for(unsigned int counter = 1; counter < grid->mPoints.size(); counter++) { float potentialDistBetween = distanceSquared(grid->mPoints[counter], pos); - if(potentialDistBetween < distanceBetween) + if (potentialDistBetween < closestDistanceReachable) { // found a closer one - distanceBetween = potentialDistBetween; - closestIndex = counter; if (cell->isPointConnected(start, counter)) { + closestDistanceReachable = potentialDistBetween; closestReachableIndex = counter; } + if (potentialDistBetween < closestDistanceBetween) + { + closestDistanceBetween = potentialDistBetween; + closestIndex = counter; + } } } + + // invariant: start and endpoint must be connected + assert(cell->isPointConnected(start, closestReachableIndex)); + // AiWander has logic that depends on whether a path was created, deleting // allowed nodes if not. Hence a path needs to be created even if the start // and the end points are the same. From 3b231b85bb1c7ed8c00cf7f1a5a583299e23e3bc Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 21 Aug 2015 06:55:54 +1200 Subject: [PATCH 288/419] removed incorrect optimization. Now it fixes #2871 --- apps/openmw/mwmechanics/pathfinding.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 9013d3269..9c9c11106 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -53,13 +53,13 @@ namespace { assert(grid && !grid->mPoints.empty()); - float closestDistanceBetween = distanceSquared(grid->mPoints[0], pos); - float closestDistanceReachable = closestDistanceBetween; + float closestDistanceBetween = FLT_MAX; + float closestDistanceReachable = FLT_MAX; int closestIndex = 0; int closestReachableIndex = 0; // TODO: if this full scan causes performance problems mapping pathgrid // points to a quadtree may help - for(unsigned int counter = 1; counter < grid->mPoints.size(); counter++) + for(unsigned int counter = 0; counter < grid->mPoints.size(); counter++) { float potentialDistBetween = distanceSquared(grid->mPoints[counter], pos); if (potentialDistBetween < closestDistanceReachable) From af3b0cd883f784d111d65b2ed33871ddeb260e18 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 21 Aug 2015 00:31:43 +0200 Subject: [PATCH 289/419] Improve some error messages --- apps/essimporter/converter.cpp | 2 +- apps/openmw/engine.cpp | 4 ++-- apps/openmw/mwgui/savegamedialog.cpp | 2 +- apps/openmw/mwrender/globalmap.cpp | 4 ++-- apps/openmw/mwrender/localmap.cpp | 4 ++-- apps/openmw/mwstate/statemanagerimp.cpp | 2 +- components/resource/texturemanager.cpp | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 2ef10ee34..6267ef91e 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -143,7 +143,7 @@ namespace ESSImport osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*image2, ostream); if (!result.success()) { - std::cerr << "can't write global map image: " << result.message() << std::endl; + std::cerr << "can't write global map image: " << result.message() << " code " << result.status() << std::endl; return; } diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 95851b75f..d0a993b73 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -425,7 +425,7 @@ void OMW::Engine::setWindowIcon() } osgDB::ReaderWriter::ReadResult result = reader->readImage(windowIconStream); if (!result.success()) - std::cerr << "Failed to read " << windowIcon << ": " << result.message() << std::endl; + std::cerr << "Failed to read " << windowIcon << ": " << result.message() << " code " << result.status() << std::endl; else { osg::ref_ptr image = result.getImage(); @@ -602,7 +602,7 @@ public: osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(image, outStream); if (!result.success()) { - std::cerr << "Can't write screenshot: " << result.message() << std::endl; + std::cerr << "Can't write screenshot: " << result.message() << " code " << result.status() << std::endl; } } diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index be9ef2139..816fc0fa8 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -401,7 +401,7 @@ namespace MWGui osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(instream); if (!result.success()) { - std::cerr << "Failed to read savegame screenshot: " << result.message() << std::endl; + std::cerr << "Failed to read savegame screenshot: " << result.message() << " code " << result.status() << std::endl; return; } diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 890c8444a..f6fb83c94 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -361,7 +361,7 @@ namespace MWRender osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*mOverlayImage, ostream); if (!result.success()) { - std::cerr << "Can't write map overlay: " << result.message() << std::endl; + std::cerr << "Can't write map overlay: " << result.message() << " code " << result.status() << std::endl; return; } @@ -411,7 +411,7 @@ namespace MWRender osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(istream); if (!result.success()) { - std::cerr << "Can't read map overlay: " << result.message() << std::endl; + std::cerr << "Can't read map overlay: " << result.message() << " code " << result.status() << std::endl; return; } diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index d307e990a..02ca0cb4c 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -645,7 +645,7 @@ void LocalMap::MapSegment::loadFogOfWar(const ESM::FogTexture &esm) osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(in); if (!result.success()) { - std::cerr << "Failed to read fog: " << result.message() << std::endl; + std::cerr << "Failed to read fog: " << result.message() << " code " << result.status() << std::endl; return; } @@ -677,7 +677,7 @@ void LocalMap::MapSegment::saveFogOfWar(ESM::FogTexture &fog) const osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*mFogOfWarImage, ostream); if (!result.success()) { - std::cerr << "Unable to write fog: " << result.message() << std::endl; + std::cerr << "Unable to write fog: " << result.message() << " code " << result.status() << std::endl; return; } mFogOfWarImage->flipVertical(); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index f4a7ee9f2..df433ad6a 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -606,7 +606,7 @@ void MWState::StateManager::writeScreenshot(std::vector &imageData) const osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*screenshot, ostream); if (!result.success()) { - std::cerr << "Unable to write screenshot: " << result.message() << std::endl; + std::cerr << "Unable to write screenshot: " << result.message() << " code " << result.status() << std::endl; return; } diff --git a/components/resource/texturemanager.cpp b/components/resource/texturemanager.cpp index d29aa2812..c2f76a527 100644 --- a/components/resource/texturemanager.cpp +++ b/components/resource/texturemanager.cpp @@ -182,7 +182,7 @@ namespace Resource osgDB::ReaderWriter::ReadResult result = reader->readImage(*stream, opts); if (!result.success()) { - std::cerr << "Error loading " << filename << ": " << result.message() << std::endl; + std::cerr << "Error loading " << filename << ": " << result.message() << " code " << result.status() << std::endl; return mWarningTexture; } From 85bc41dedb9db07da2c4609ea39be95b508bb5e2 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 21 Aug 2015 19:34:28 +1200 Subject: [PATCH 290/419] replaced FLT_MAX with numeric_limits. --- apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwmechanics/autocalcspell.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 6 +++--- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index afe34218e..7b846cb97 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -806,7 +806,7 @@ namespace MWMechanics void AiWander::SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos) { - float distanceToClosestNode = FLT_MAX; + float distanceToClosestNode = std::numeric_limits::max(); unsigned int index = 0; for (unsigned int counterThree = 0; counterThree < mAllowedNodes.size(); counterThree++) { diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index e4b143826..5dfe388a8 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -181,7 +181,7 @@ namespace MWMechanics void calcWeakestSchool (const ESM::Spell* spell, const int* actorSkills, int& effectiveSchool, float& skillTerm) { - float minChance = FLT_MAX; + float minChance = std::numeric_limits::max(); const ESM::EffectList& effects = spell->mEffects; for (std::vector::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 9c9c11106..f40624ae8 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -53,8 +53,8 @@ namespace { assert(grid && !grid->mPoints.empty()); - float closestDistanceBetween = FLT_MAX; - float closestDistanceReachable = FLT_MAX; + float closestDistanceBetween = std::numeric_limits::max(); + float closestDistanceReachable = std::numeric_limits::max(); int closestIndex = 0; int closestReachableIndex = 0; // TODO: if this full scan causes performance problems mapping pathgrid @@ -78,7 +78,7 @@ namespace } } - // invariant: start and endpoint must be connected + // post-condition: start and endpoint must be connected assert(cell->isPointConnected(start, closestReachableIndex)); // AiWander has logic that depends on whether a path was created, deleting diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index b98bf9f96..59410001f 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -92,7 +92,7 @@ namespace MWMechanics if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude()) return 0; - float y = FLT_MAX; + float y = std::numeric_limits::max(); float lowestSkill = 0; for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != spell->mEffects.mList.end(); ++it) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index bac8fca6c..1a1b04d18 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -383,7 +383,7 @@ namespace MWRender if (mFogDepth == 0.f) { mStateUpdater->setFogStart(0.f); - mStateUpdater->setFogEnd(FLT_MAX); + mStateUpdater->setFogEnd(std::numeric_limits::max()); } else { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1eed841bd..36f275cf4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2659,8 +2659,8 @@ namespace MWWorld MWRender::RenderingManager::RayResult result2 = mRendering->castRay(origin, dest, true, true); - float dist1 = FLT_MAX; - float dist2 = FLT_MAX; + float dist1 = std::numeric_limits::max(); + float dist2 = std::numeric_limits::max(); if (result1.mHit) dist1 = (origin - result1.mHitPos).length(); @@ -2853,7 +2853,7 @@ namespace MWWorld MWWorld::Ptr World::getClosestMarkerFromExteriorPosition( const osg::Vec3f& worldPos, const std::string &id ) { MWWorld::Ptr closestMarker; - float closestDistance = FLT_MAX; + float closestDistance = std::numeric_limits::max(); std::vector markers; mCells.getExteriorPtrs(id, markers); From 77a1d947cc6796d3878f96af8d618a692957c381 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 21 Aug 2015 21:12:39 +1200 Subject: [PATCH 291/419] extracted MWMechanics::getPlayer() --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwclass/armor.cpp | 3 +- apps/openmw/mwclass/creature.cpp | 3 +- apps/openmw/mwclass/door.cpp | 4 ++- apps/openmw/mwclass/npc.cpp | 15 +++++----- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 +- apps/openmw/mwdialogue/filter.cpp | 13 +++++---- apps/openmw/mwgui/alchemywindow.cpp | 7 +++-- apps/openmw/mwgui/bookwindow.cpp | 4 ++- apps/openmw/mwgui/charactercreation.cpp | 5 ++-- apps/openmw/mwgui/container.cpp | 7 +++-- apps/openmw/mwgui/dialogue.cpp | 3 +- apps/openmw/mwgui/enchantingdialog.cpp | 10 ++++--- apps/openmw/mwgui/hud.cpp | 7 +++-- apps/openmw/mwgui/inventorywindow.cpp | 16 +++++----- apps/openmw/mwgui/jailscreen.cpp | 5 ++-- apps/openmw/mwgui/levelupdialog.cpp | 3 +- apps/openmw/mwgui/merchantrepair.cpp | 5 ++-- apps/openmw/mwgui/quickkeysmenu.cpp | 9 +++--- apps/openmw/mwgui/recharge.cpp | 5 ++-- apps/openmw/mwgui/referenceinterface.cpp | 4 ++- apps/openmw/mwgui/repair.cpp | 4 ++- apps/openmw/mwgui/scrollwindow.cpp | 4 ++- apps/openmw/mwgui/spellbuyingwindow.cpp | 9 +++--- apps/openmw/mwgui/spellcreationdialog.cpp | 7 +++-- apps/openmw/mwgui/spellicons.cpp | 3 +- apps/openmw/mwgui/spellwindow.cpp | 11 +++---- apps/openmw/mwgui/statswindow.cpp | 7 +++-- apps/openmw/mwgui/tooltips.cpp | 5 ++-- apps/openmw/mwgui/tradewindow.cpp | 5 ++-- apps/openmw/mwgui/trainingwindow.cpp | 3 +- apps/openmw/mwgui/travelwindow.cpp | 3 +- apps/openmw/mwgui/waitdialog.cpp | 5 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 5 ++-- apps/openmw/mwinput/inputmanagerimp.cpp | 5 ++-- apps/openmw/mwmechanics/actors.cpp | 23 ++++++++------- apps/openmw/mwmechanics/actorutil.cpp | 12 ++++++++ apps/openmw/mwmechanics/actorutil.hpp | 14 +++++++++ apps/openmw/mwmechanics/aiavoiddoor.cpp | 3 +- apps/openmw/mwmechanics/aipackage.cpp | 3 +- apps/openmw/mwmechanics/aisequence.cpp | 5 ++-- apps/openmw/mwmechanics/aiwander.cpp | 5 ++-- apps/openmw/mwmechanics/character.cpp | 21 +++++++------- apps/openmw/mwmechanics/combat.cpp | 13 +++++---- apps/openmw/mwmechanics/difficultyscaling.cpp | 4 ++- apps/openmw/mwmechanics/disease.hpp | 8 +++-- apps/openmw/mwmechanics/enchanting.cpp | 7 +++-- apps/openmw/mwmechanics/levelledlist.hpp | 5 ++-- .../mwmechanics/mechanicsmanagerimp.cpp | 29 ++++++++++--------- apps/openmw/mwmechanics/repair.cpp | 9 +++--- apps/openmw/mwmechanics/spellcasting.cpp | 29 ++++++++++--------- apps/openmw/mwphysics/physicssystem.cpp | 3 +- apps/openmw/mwrender/characterpreview.cpp | 4 ++- apps/openmw/mwrender/npcanimation.cpp | 3 +- apps/openmw/mwrender/ripplesimulation.cpp | 4 ++- apps/openmw/mwscript/cellextensions.cpp | 22 +++++++------- apps/openmw/mwscript/containerextensions.cpp | 6 ++-- apps/openmw/mwscript/guiextensions.cpp | 4 ++- apps/openmw/mwscript/miscextensions.cpp | 7 +++-- apps/openmw/mwscript/statsextensions.cpp | 29 ++++++++++--------- .../mwscript/transformationextensions.cpp | 18 +++++++----- apps/openmw/mwsound/soundmanagerimp.cpp | 6 ++-- apps/openmw/mwstate/statemanagerimp.cpp | 5 ++-- apps/openmw/mwworld/action.cpp | 4 ++- apps/openmw/mwworld/actionequip.cpp | 4 ++- apps/openmw/mwworld/containerstore.cpp | 5 ++-- apps/openmw/mwworld/failedaction.cpp | 3 +- apps/openmw/mwworld/inventorystore.cpp | 9 +++--- apps/openmw/mwworld/projectilemanager.cpp | 3 +- apps/openmw/mwworld/weather.cpp | 4 ++- 70 files changed, 327 insertions(+), 215 deletions(-) create mode 100644 apps/openmw/mwmechanics/actorutil.cpp create mode 100644 apps/openmw/mwmechanics/actorutil.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c33b711e6..a0f9e8e13 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -78,7 +78,7 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanagerimp stat creaturestats magiceffects movement + mechanicsmanagerimp stat creaturestats magiceffects movement actorutil drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 2ba8ba03b..324dd32ee 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -20,6 +20,7 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwgui/tooltips.hpp" @@ -244,7 +245,7 @@ namespace MWClass typeText = "#{sHeavy}"; text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(getEffectiveArmorRating(ptr, - MWBase::Environment::get().getWorld()->getPlayerPtr())); + MWMechanics::getPlayer())); int remainingHealth = getItemHealth(ptr); text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/" diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 5604aa783..ff09282c1 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -36,6 +36,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/combat.hpp" +#include "../mwmechanics/actorutil.hpp" namespace { @@ -344,7 +345,7 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitAttemptObject(object.getClass().getId(object)); - if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWMechanics::getPlayer()) { const std::string &script = ptr.get()->mBase->mScript; /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 6749afa6b..18c381e13 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -26,6 +26,8 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwmechanics/actorutil.hpp" + namespace { struct DoorCustomData : public MWWorld::CustomData @@ -126,7 +128,7 @@ namespace MWClass if (needKey && hasKey) { - if(actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(actor == MWMechanics::getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox(keyName + " #{sKeyUsed}"); unlock(ptr); //Call the function here. because that makes sense. // using a key disarms the trap diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index e2b714a64..5f166b3e3 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -24,6 +24,7 @@ #include "../mwmechanics/autocalcspell.hpp" #include "../mwmechanics/difficultyscaling.hpp" #include "../mwmechanics/character.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontalk.hpp" @@ -503,7 +504,7 @@ namespace MWClass if(otherstats.isDead()) // Can't hit dead actors return; - if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(ptr == MWMechanics::getPlayer()) MWBase::Environment::get().getWindowManager()->setEnemy(victim); int weapskill = ESM::Skill::HandToHand; @@ -542,7 +543,7 @@ namespace MWClass { MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg, attackStrength); } - if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(ptr == MWMechanics::getPlayer()) { skillUsageSucceeded(ptr, weapskill, 0); @@ -608,7 +609,7 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitAttemptObject(object.getClass().getId(object)); - if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWMechanics::getPlayer()) { const std::string &script = ptr.getClass().getScript(ptr); /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ @@ -700,7 +701,7 @@ namespace MWClass if (armorhealth == 0) armor = *inv.unequipItem(armor, ptr); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) skillUsageSucceeded(ptr, armor.getClass().getEquipmentSkill(armor), 0); switch(armor.getClass().getEquipmentSkill(armor)) @@ -716,7 +717,7 @@ namespace MWClass break; } } - else if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + else if(ptr == MWMechanics::getPlayer()) skillUsageSucceeded(ptr, ESM::Skill::Unarmored, 0); } } @@ -729,7 +730,7 @@ namespace MWClass if(damage > 0.0f) { sndMgr->playSound3D(ptr, "Health Damage", 1.0f, 1.0f); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(); } MWMechanics::DynamicStat health(getCreatureStats(ptr).getHealth()); @@ -783,7 +784,7 @@ namespace MWClass const MWWorld::Ptr& actor) const { // player got activated by another NPC - if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(ptr == MWMechanics::getPlayer()) return boost::shared_ptr(new MWWorld::ActionTalk(actor)); // Werewolfs can't activate NPCs diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 35f205eb8..993dde6e4 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -41,6 +41,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "filter.hpp" #include "hypertextparser.hpp" @@ -532,7 +533,7 @@ namespace MWDialogue else if (curDisp + mTemporaryDispositionChange > 100) mTemporaryDispositionChange = 100 - curDisp; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().skillUsageSucceeded(player, ESM::Skill::Speechcraft, success ? 0 : 1); if (success) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 5e6b83b50..e3a773b05 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -17,6 +17,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/magiceffects.hpp" +#include "../mwmechanics/actorutil.hpp" #include "selectwrapper.hpp" @@ -97,7 +98,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const { - const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr player = MWMechanics::getPlayer(); // check player faction if (!info.mPcFaction.empty()) @@ -219,7 +220,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c case SelectWrapper::Function_PcHealthPercent: { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); float ratio = player.getClass().getCreatureStats (player).getHealth().getCurrent() / player.getClass().getCreatureStats (player).getHealth().getModified(); @@ -229,7 +230,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c case SelectWrapper::Function_PcDynamicStat: { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); float value = player.getClass().getCreatureStats (player). getDynamic (select.getArgument()).getCurrent(); @@ -253,7 +254,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) const { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); switch (select.getFunction()) { @@ -429,7 +430,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) const { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); switch (select.getFunction()) { @@ -532,7 +533,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co case SelectWrapper::Function_ShouldAttack: return MWBase::Environment::get().getMechanicsManager()->isAggressive(mActor, - MWBase::Environment::get().getWorld()->getPlayerPtr()); + MWMechanics::getPlayer()); case SelectWrapper::Function_Werewolf: diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 768ad82e4..60bd70c04 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -11,6 +11,7 @@ #include "../mwmechanics/magiceffects.hpp" #include "../mwmechanics/alchemy.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -124,9 +125,9 @@ namespace MWGui void AlchemyWindow::open() { - mAlchemy->setAlchemist (MWBase::Environment::get().getWorld()->getPlayerPtr()); + mAlchemy->setAlchemist (MWMechanics::getPlayer()); - InventoryItemModel* model = new InventoryItemModel(MWBase::Environment::get().getWorld()->getPlayerPtr()); + InventoryItemModel* model = new InventoryItemModel(MWMechanics::getPlayer()); mSortModel = new SortFilterItemModel(model); mSortModel->setFilter(SortFilterItemModel::Filter_OnlyIngredients); mItemView->setModel (mSortModel); @@ -136,7 +137,7 @@ namespace MWGui int index = 0; - mAlchemy->setAlchemist (MWBase::Environment::get().getWorld()->getPlayerPtr()); + mAlchemy->setAlchemist (MWMechanics::getPlayer()); for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy->beginTools()); iter!=mAlchemy->endTools() && index (mApparatus.size()); ++iter, ++index) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 44a988523..f3cefb787 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -9,6 +9,8 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "../mwworld/actiontake.hpp" #include "formatting.hpp" @@ -123,7 +125,7 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->playSound("Item Book Up", 1.0, 1.0); MWWorld::ActionTake take(mBook); - take.execute (MWBase::Environment::get().getWorld()->getPlayerPtr()); + take.execute (MWMechanics::getPlayer()); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); } diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 6585a0dd0..d2ce35509 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -7,6 +7,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" #include "../mwworld/fallback.hpp" @@ -51,7 +52,7 @@ namespace void updatePlayerHealth() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player); npcStats.updateHealth(); } @@ -228,7 +229,7 @@ namespace MWGui mReviewDialog->setBirthSign(mPlayerBirthSignId); { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); mReviewDialog->setHealth ( stats.getHealth() ); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index b2cc09b43..5d71fc445 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -9,6 +9,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" @@ -137,7 +138,7 @@ namespace MWGui if (mPtr.getTypeName() == typeid(ESM::NPC).name() && !loot) { // we are stealing stuff - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); mModel = new PickpocketItemModel(player, new InventoryItemModel(container), !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown()); } @@ -183,7 +184,7 @@ namespace MWGui && !mPickpocketDetected ) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::Pickpocket pickpocket(player, mPtr); if (pickpocket.finish()) { @@ -260,7 +261,7 @@ namespace MWGui bool ContainerWindow::onTakeItem(const ItemStack &item, int count) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); // TODO: move to ItemModels if (dynamic_cast(mModel) && !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown()) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index ce33a74dd..a6000a739 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -21,6 +21,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "widgets.hpp" #include "bookpage.hpp" @@ -89,7 +90,7 @@ namespace MWGui WindowModal::open(); center(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); mBribe10Button->setEnabled (playerGold >= 10); diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 61a935a6f..c182a0a52 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -18,6 +18,8 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "itemselection.hpp" #include "itemwidget.hpp" @@ -160,7 +162,7 @@ namespace MWGui void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); mEnchanting.setSelfEnchanting(true); mEnchanting.setEnchanter(player); @@ -208,7 +210,7 @@ namespace MWGui mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onItemSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onItemCancel); mItemSelectionDialog->setVisible(true); - mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr()); + mItemSelectionDialog->openContainer(MWMechanics::getPlayer()); mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyEnchantable); } else @@ -263,7 +265,7 @@ namespace MWGui mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onSoulSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onSoulCancel); mItemSelectionDialog->setVisible(true); - mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr()); + mItemSelectionDialog->openContainer(MWMechanics::getPlayer()); mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyChargedSoulstones); //MWBase::Environment::get().getWindowManager()->messageBox("#{sInventorySelectNoSoul}"); @@ -324,7 +326,7 @@ namespace MWGui mEnchanting.setNewItemName(mName->getCaption()); mEnchanting.setEffect(mEffectList); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); if (mPtr != player && mEnchanting.getEnchantPrice() > playerGold) { diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 1acbea6d7..a93bb47e9 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -18,6 +18,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "inventorywindow.hpp" #include "spellicons.hpp" @@ -259,7 +260,7 @@ namespace MWGui { // drop item into the gameworld MWBase::Environment::get().getWorld()->breakInvisibility( - MWBase::Environment::get().getWorld()->getPlayerPtr()); + MWMechanics::getPlayer()); MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); @@ -338,7 +339,7 @@ namespace MWGui void HUD::onWeaponClicked(MyGUI::Widget* _sender) { - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = MWMechanics::getPlayer(); if (player.getClass().getNpcStats(player).isWerewolf()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}"); @@ -350,7 +351,7 @@ namespace MWGui void HUD::onMagicClicked(MyGUI::Widget* _sender) { - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = MWMechanics::getPlayer(); if (player.getClass().getNpcStats(player).isWerewolf()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}"); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 580e583c9..f5a5f023f 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -29,6 +29,8 @@ #include "../mwscript/interpretercontext.hpp" #include "../mwrender/characterpreview.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "itemview.hpp" #include "inventoryitemmodel.hpp" #include "sortfilteritemmodel.hpp" @@ -63,7 +65,7 @@ namespace MWGui , mGuiMode(GM_Inventory) , mLastXSize(0) , mLastYSize(0) - , mPreview(new MWRender::InventoryPreview(viewer, resourceSystem, MWBase::Environment::get().getWorld()->getPlayerPtr())) + , mPreview(new MWRender::InventoryPreview(viewer, resourceSystem, MWMechanics::getPlayer())) , mTrading(false) { mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture())); @@ -333,7 +335,7 @@ namespace MWGui void InventoryWindow::open() { - mPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + mPtr = MWMechanics::getPlayer(); updateEncumbranceBar(); @@ -439,7 +441,7 @@ namespace MWGui { const std::string& script = ptr.getClass().getScript(ptr); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); // early-out for items that need to be equipped, but can't be equipped: we don't want to set OnPcEquip in that case if (!ptr.getClass().getEquipmentSlots(ptr).first.empty()) @@ -549,7 +551,7 @@ namespace MWGui void InventoryWindow::updateEncumbranceBar() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); float capacity = player.getClass().getCapacity(player); float encumbrance = player.getClass().getEncumbrance(player); @@ -583,7 +585,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->updateSpellWindow(); MWBase::Environment::get().getMechanicsManager()->updateMagicEffects( - MWBase::Environment::get().getWorld()->getPlayerPtr()); + MWMechanics::getPlayer()); dirtyPreview(); } @@ -614,7 +616,7 @@ namespace MWGui int count = object.getRefData().getCount(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getWorld()->breakInvisibility(player); MWBase::Environment::get().getMechanicsManager()->itemTaken(player, object, MWWorld::Ptr(), count); @@ -644,7 +646,7 @@ namespace MWGui { ItemModel::ModelIndex selected = -1; // not using mSortFilterModel as we only need sorting, not filtering - SortFilterItemModel model(new InventoryItemModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); + SortFilterItemModel model(new InventoryItemModel(MWMechanics::getPlayer())); model.setSortByType(false); model.update(); if (model.getItemCount() == 0) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index e4a3a3147..7eaf5eb30 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -8,6 +8,7 @@ #include "../mwbase/environment.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/store.hpp" @@ -57,7 +58,7 @@ namespace MWGui if (mFadeTimeRemaining <= 0) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getWorld()->teleportToClosestMarker(player, "prisonmarker"); setVisible(true); @@ -76,7 +77,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Jail); MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getWorld()->advanceTime(mDays * 24); for (int i=0; igetPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats (player); if (mSpentAttributes.size() < mCoinCount) diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 862b719d4..481e1ceb4 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -13,6 +13,7 @@ #include "../mwbase/soundmanager.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -40,7 +41,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) int currentY = 0; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); @@ -125,7 +126,7 @@ void MerchantRepair::exit() void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int price = MyGUI::utility::parseInt(sender->getUserString("Price")); if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId)) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 3f896bae2..d25151816 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -19,6 +19,7 @@ #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwgui/inventorywindow.hpp" @@ -147,7 +148,7 @@ namespace MWGui mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItemCancel); } mItemSelectionDialog->setVisible(true); - mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr()); + mItemSelectionDialog->openContainer(MWMechanics::getPlayer()); mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyUsableItems); mAssignDialog->setVisible (false); @@ -262,7 +263,7 @@ namespace MWGui QuickKeyType type = mAssigned[index-1]; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); if (type == Type_Item || type == Type_MagicItem) @@ -473,7 +474,7 @@ namespace MWGui case Type_MagicItem: { // Find the item by id - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); MWWorld::Ptr item; for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) @@ -543,7 +544,7 @@ namespace MWGui { WindowModal::open(); - mMagicList->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); + mMagicList->setModel(new SpellModel(MWMechanics::getPlayer())); mMagicList->resetScrollbars(); } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 69c5c61c4..1dac7138f 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -17,6 +17,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "widgets.hpp" #include "itemwidget.hpp" @@ -92,7 +93,7 @@ void Recharge::updateView() int currentY = 0; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) @@ -147,7 +148,7 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) MWWorld::Ptr item = *sender->getUserData(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player); diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index 2ea0db64a..76bb4f53f 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -3,6 +3,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" +#include "../mwmechanics/actorutil.hpp" + namespace MWGui { ReferenceInterface::ReferenceInterface() @@ -16,7 +18,7 @@ namespace MWGui void ReferenceInterface::checkReferenceAvailable() { - MWWorld::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); + MWWorld::CellStore* playerCell = MWMechanics::getPlayer().getCell(); // check if player has changed cell, or count of the reference has become 0 if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL) diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 534226aeb..49d5735a4 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -9,6 +9,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" @@ -94,7 +96,7 @@ void Repair::updateRepairView() int currentY = 0; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); int categories = MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Armor; for (MWWorld::ContainerStoreIterator iter (store.begin(categories)); diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 01ce7767e..ccc07174d 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -10,6 +10,8 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "../mwworld/actiontake.hpp" #include "formatting.hpp" @@ -103,7 +105,7 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->playSound("Item Book Up", 1.0, 1.0); MWWorld::ActionTake take(mScroll); - take.execute (MWBase::Environment::get().getWorld()->getPlayerPtr()); + take.execute (MWMechanics::getPlayer()); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); } diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 61dd599e7..8c4520662 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -15,6 +15,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWGui { @@ -48,7 +49,7 @@ namespace MWGui int price = static_cast(spell->mData.mCost*store.get().find("fSpellValueMult")->getFloat()); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); // TODO: refactor to use MyGUI::ListBox @@ -125,7 +126,7 @@ namespace MWGui bool SpellBuyingWindow::playerHasSpell(const std::string &id) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); return player.getClass().getCreatureStats(player).getSpells().hasSpell(id); } @@ -133,7 +134,7 @@ namespace MWGui { int price = *_sender->getUserData(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId)) return; @@ -158,7 +159,7 @@ namespace MWGui void SpellBuyingWindow::updateLabels() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 57563be22..ff5a27abe 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -19,6 +19,7 @@ #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/spells.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "tooltips.hpp" #include "class.hpp" @@ -376,7 +377,7 @@ namespace MWGui return; } - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); if (MyGUI::utility::parseInt(mPriceLabel->getCaption()) > playerGold) @@ -474,7 +475,7 @@ namespace MWGui mPriceLabel->setCaption(MyGUI::utility::toString(int(price))); - float chance = MWMechanics::getSpellSuccessChance(&mSpell, MWBase::Environment::get().getWorld()->getPlayerPtr()); + float chance = MWMechanics::getSpellSuccessChance(&mSpell, MWMechanics::getPlayer()); mSuccessChance->setCaption(MyGUI::utility::toString(int(chance))); } @@ -507,7 +508,7 @@ namespace MWGui { // get the list of magic effects that are known to the player - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::Spells& spells = stats.getSpells(); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index db0453623..b2995af3c 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -16,6 +16,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "tooltips.hpp" @@ -43,7 +44,7 @@ namespace MWGui { // TODO: Tracking add/remove/expire would be better than force updating every frame - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index d2ea67ea9..68a604256 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -15,6 +15,7 @@ #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/spells.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "spellicons.hpp" #include "inventorywindow.hpp" @@ -79,12 +80,12 @@ namespace MWGui { mSpellIcons->updateWidgets(mEffectBox, false); - mSpellView->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); + mSpellView->setModel(new SpellModel(MWMechanics::getPlayer())); } void SpellWindow::onEnchantedItemSelected(MWWorld::Ptr item, bool alreadyEquipped) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); // retrieve ContainerStoreIterator to the item @@ -159,7 +160,7 @@ namespace MWGui void SpellWindow::onSpellSelected(const std::string& spellId) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); store.setSelectedEnchantItem(store.end()); MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); @@ -169,7 +170,7 @@ namespace MWGui void SpellWindow::onDeleteSpellAccept() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::Spells& spells = stats.getSpells(); @@ -183,7 +184,7 @@ namespace MWGui void SpellWindow::cycle(bool next) { - mSpellView->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr())); + mSpellView->setModel(new SpellModel(MWMechanics::getPlayer())); SpellModel::ModelIndex selected = 0; for (SpellModel::ModelIndex i = 0; igetModel()->getItemCount()); ++i) diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index cb1bf6f37..efbbeb29a 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -15,6 +15,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "tooltips.hpp" @@ -234,7 +235,7 @@ namespace MWGui NoDrop::onFrame(dt); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWMechanics::NpcStats &PCstats = player.getClass().getNpcStats(player); // level progress @@ -383,7 +384,7 @@ namespace MWGui int base = stat.getBase(); int modified = stat.getModified(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); @@ -493,7 +494,7 @@ namespace MWGui if (!mFactions.empty()) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWMechanics::NpcStats &PCstats = player.getClass().getNpcStats(player); const std::set &expelled = PCstats.getExpelled(); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index dbf27ad91..7c7f951af 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -17,6 +17,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/actorutil.hpp" #include "mapwindow.hpp" #include "inventorywindow.hpp" @@ -234,7 +235,7 @@ namespace MWGui } if (MWMechanics::spellIncreasesSkill(spell)) // display school of spells that contribute to skill progress { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int school = MWMechanics::getSpellSchool(spell, player); info.text = "#{sSchool}: " + sSchoolNames[school]; } @@ -355,7 +356,7 @@ namespace MWGui if(!mFocusObject.isEmpty()) { const MWWorld::CellRef& cellref = mFocusObject.getCellRef(); - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr ptr = MWMechanics::getPlayer(); MWWorld::Ptr victim; MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 0ae661eb3..6f45ed005 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -20,6 +20,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "inventorywindow.hpp" #include "itemview.hpp" @@ -282,7 +283,7 @@ namespace MWGui return; } - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); // check if the player can afford this @@ -490,7 +491,7 @@ namespace MWGui void TradeWindow::updateLabels() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); mPlayerGold->setCaptionWithReplacing("#{sYourGold} " + MyGUI::utility::toString(playerGold)); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 6376ced57..30ad27e46 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -13,6 +13,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "tooltips.hpp" @@ -68,7 +69,7 @@ namespace MWGui { mPtr = actor; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 6ea6301ad..8c55c3732 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -12,6 +12,7 @@ #include "../mwbase/dialoguemanager.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -144,7 +145,7 @@ namespace MWGui int price; iss >> price; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); if (playerGoldgetPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); const MWMechanics::NpcStats &pcstats = player.getClass().getNpcStats(player); // trigger levelup if possible @@ -213,7 +214,7 @@ namespace MWGui void WaitDialog::setCanRest (bool canRest) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); bool full = (stats.getHealth().getCurrent() >= stats.getHealth().getModified()) && (stats.getMagicka().getCurrent() >= stats.getMagicka().getModified()); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index db5593704..01bf2e7c6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -56,6 +56,7 @@ #include "../mwmechanics/stat.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwrender/localmap.hpp" @@ -903,7 +904,7 @@ namespace MWGui if (!mLocalMapRender) return; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); osg::Vec3f playerPosition = player.getRefData().getPosition().asVec3(); osg::Quat playerOrientation (-player.getRefData().getPosition().rot[2], osg::Vec3(0,0,1)); @@ -1547,7 +1548,7 @@ namespace MWGui { mInventoryWindow->updatePlayer(); - const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr player = MWMechanics::getPlayer(); if (player.getClass().getNpcStats(player).isWerewolf()) { setWerewolfOverlay(true); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 2d767c6f5..74842e3e3 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -28,6 +28,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" using namespace ICS; @@ -1012,7 +1013,7 @@ namespace MWInput { if (!mControlSwitch["playercontrols"]) return; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if (player.getClass().getNpcStats(player).isWerewolf()) { // Cannot use items or spells while in werewolf form @@ -1029,7 +1030,7 @@ namespace MWInput if (!MWBase::Environment::get().getWindowManager()->isGuiMode () && MWBase::Environment::get().getWorld()->getGlobalFloat ("chargenstate")==-1) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if (player.getClass().getNpcStats(player).isWerewolf()) { // Cannot use items or spells while in werewolf form diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 584c4c320..a323028c0 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -33,6 +33,7 @@ #include "actor.hpp" #include "summoning.hpp" #include "combat.hpp" +#include "actorutil.hpp" namespace { @@ -55,7 +56,7 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a action.execute(actor); MWWorld::ContainerStoreIterator rightHand = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); // change draw state only if the item is in player's right hand - if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr() + if (actor == MWMechanics::getPlayer() && rightHand != store.end() && newPtr == *rightHand) { MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); @@ -81,7 +82,7 @@ public: const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if ( ((key.mId == ESM::MagicEffect::CommandHumanoid && mActor.getClass().isNpc()) || (key.mId == ESM::MagicEffect::CommandCreature && mActor.getTypeName() == typeid(ESM::Creature).name())) && casterActorId == player.getClass().getCreatureStats(player).getActorId() @@ -202,7 +203,7 @@ namespace MWMechanics gem->getContainerStore()->unstack(*gem, caster); gem->getCellRef().setSoul(mCreature.getCellRef().getRefId()); - if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (caster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sSoultrapSuccess}"); const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() @@ -400,7 +401,7 @@ namespace MWMechanics int intelligence = creatureStats.getAttribute(ESM::Attribute::Intelligence).getModified(); float base = 1.f; - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == getPlayer()) base = MWBase::Environment::get().getWorld()->getStore().get().find("fPCbaseMagickaMult")->getFloat(); else base = MWBase::Environment::get().getWorld()->getStore().get().find("fNPCbaseMagickaMult")->getFloat(); @@ -511,7 +512,7 @@ namespace MWMechanics { spells.worsenCorprus(it->first); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicCorprusWorsens}"); } } @@ -559,7 +560,7 @@ namespace MWMechanics // The actor was killed by a magic effect. Figure out if the player was responsible for it. const ActiveSpells& spells = creatureStats.getActiveSpells(); bool killedByPlayer = false; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); for (ActiveSpells::TIterator it = spells.begin(); it != spells.end(); ++it) { const ActiveSpells::ActiveSpellParams& spell = it->second; @@ -726,7 +727,7 @@ namespace MWMechanics void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration) { - bool isPlayer = (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()); + bool isPlayer = (ptr == getPlayer()); MWWorld::InventoryStore &inventoryStore = ptr.getClass().getInventoryStore(ptr); MWWorld::ContainerStoreIterator heldIter = @@ -823,7 +824,7 @@ namespace MWMechanics void Actors::updateCrimePersuit(const MWWorld::Ptr& ptr, float duration) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); if (ptr != player && ptr.getClass().isNpc()) { // get stats of witness @@ -945,7 +946,7 @@ namespace MWMechanics if (timerUpdateAITargets >= 1.0f) timerUpdateAITargets = 0; if (timerUpdateHeadTrack >= 0.3f) timerUpdateHeadTrack = 0; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); int hostilesCount = 0; // need to know this to play Battle music @@ -1042,7 +1043,7 @@ namespace MWMechanics // Handle player last, in case a cell transition occurs by casting a teleportation spell // (would invalidate the iterator) - if (iter->first == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (iter->first == getPlayer()) { playerCharacter = iter->second->getCharacterController(); continue; @@ -1423,7 +1424,7 @@ namespace MWMechanics for (PtrActorMap::iterator it = map.begin(); it != map.end(); ++it) { MWWorld::Ptr ptr = it->first; - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() + if (ptr == getPlayer() || !isConscious(ptr) || ptr.getClass().getCreatureStats(ptr).isParalyzed()) continue; diff --git a/apps/openmw/mwmechanics/actorutil.cpp b/apps/openmw/mwmechanics/actorutil.cpp new file mode 100644 index 000000000..dc3770556 --- /dev/null +++ b/apps/openmw/mwmechanics/actorutil.cpp @@ -0,0 +1,12 @@ +#include "actorutil.hpp" + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" + +namespace MWMechanics +{ + MWWorld::Ptr getPlayer() + { + return MWBase::Environment::get().getWorld()->getPlayerPtr(); + } +} diff --git a/apps/openmw/mwmechanics/actorutil.hpp b/apps/openmw/mwmechanics/actorutil.hpp new file mode 100644 index 000000000..95172b9f9 --- /dev/null +++ b/apps/openmw/mwmechanics/actorutil.hpp @@ -0,0 +1,14 @@ +#ifndef OPENMW_MWMECHANICS_ACTORUTIL_H +#define OPENMW_MWMECHANICS_ACTORUTIL_H + +namespace MWWorld +{ + class Ptr; +} + +namespace MWMechanics +{ + MWWorld::Ptr getPlayer(); +} + +#endif diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index b3aa346ce..409f7b9c4 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -6,6 +6,7 @@ #include "../mwworld/class.hpp" #include "creaturestats.hpp" #include "movement.hpp" +#include "actorutil.hpp" #include "steering.hpp" @@ -63,7 +64,7 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont std::vector actors; MWBase::Environment::get().getMechanicsManager()->getActorsInRange(pos.asVec3(),100,actors); for(std::vector::iterator it = actors.begin(); it != actors.end(); ++it) { - if(*it != MWBase::Environment::get().getWorld()->getPlayerPtr()) { //Not the player + if(*it != getPlayer()) { //Not the player MWMechanics::AiSequence& seq = it->getClass().getCreatureStats(*it).getAiSequence(); if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) { //Only add it once seq.stack(MWMechanics::AiAvoidDoor(mDoorPtr),*it); diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 1ab3264b7..2c8c57c56 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -15,6 +15,7 @@ #include "../mwworld/action.hpp" #include "steering.hpp" +#include "actorutil.hpp" MWMechanics::AiPackage::~AiPackage() {} @@ -34,7 +35,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po /// Stops the actor when it gets too close to a unloaded cell const ESM::Cell *cell = actor.getCell()->getCell(); { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); Movement &movement = actor.getClass().getMovementSettings(actor); //Ensure pursuer doesn't leave loaded cells diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index a750860ca..a1c5ab14f 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -12,6 +12,7 @@ #include "aiactivate.hpp" #include "aicombat.hpp" #include "aipursue.hpp" +#include "actorutil.hpp" #include @@ -150,7 +151,7 @@ bool AiSequence::isPackageDone() const void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { - if(actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(actor != getPlayer()) { if (!mPackages.empty()) { @@ -242,7 +243,7 @@ void AiSequence::clear() void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) { - if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor == getPlayer()) throw std::runtime_error("Can't add AI packages to player"); if (package.getTypeId() == AiPackage::TypeIdCombat || package.getTypeId() == AiPackage::TypeIdPursue) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index afe34218e..f3f808a2e 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -21,6 +21,7 @@ #include "steering.hpp" #include "movement.hpp" #include "coordinateconverter.hpp" +#include "actorutil.hpp" @@ -462,7 +463,7 @@ namespace MWMechanics if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor) && MWBase::Environment::get().getSoundManager()->sayDone(actor)) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() .get().find("fVoiceIdleOdds")->getFloat(); @@ -496,7 +497,7 @@ namespace MWMechanics helloDistance *= iGreetDistanceMultiplier; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); osg::Vec3f playerPos(player.getRefData().getPosition().asVec3()); osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); float playerDistSqr = (playerPos - actorPos).length2(); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3959c413a..3837e9a75 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -27,6 +27,7 @@ #include "npcstats.hpp" #include "creaturestats.hpp" #include "security.hpp" +#include "actorutil.hpp" #include @@ -619,7 +620,7 @@ void CharacterController::playDeath(float startpoint, CharacterState death) void CharacterController::playRandomDeath(float startpoint) { - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) { // The first-person animations do not include death, so we need to // force-switch to third person before playing the death animation. @@ -1167,7 +1168,7 @@ bool CharacterController::updateWeaponState() // Unset casting flag, otherwise pressing the mouse button down would // continue casting every frame if there is no animation mAttackingOrSpell = false; - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) { MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false); } @@ -1177,7 +1178,7 @@ bool CharacterController::updateWeaponState() // For the player, set the spell we want to cast // This has to be done at the start of the casting animation, // *not* when selecting a spell in the GUI (otherwise you could change the spell mid-animation) - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) { std::string selectedSpell = MWBase::Environment::get().getWindowManager()->getSelectedSpell(); stats.getSpells().setSelectedSpell(selectedSpell); @@ -1257,7 +1258,7 @@ bool CharacterController::updateWeaponState() mAttackType = "shoot"; else { - if(isWeapon && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() && + if(isWeapon && mPtr == getPlayer() && Settings::Manager::getBool("best attack", "Game")) { MWWorld::ContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight); @@ -1563,7 +1564,7 @@ void CharacterController::update(float duration) // advance athletics - if(mHasMovedInXY && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(mHasMovedInXY && mPtr == getPlayer()) { if(inwater) { @@ -1664,7 +1665,7 @@ void CharacterController::update(float duration) } // advance acrobatics - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0); // decrease fatigue @@ -1707,7 +1708,7 @@ void CharacterController::update(float duration) else { // report acrobatics progression - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 1); } } @@ -1949,7 +1950,7 @@ bool CharacterController::kill() { if( isDead() ) { - if( mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() && !isAnimPlaying(mCurrentDeath) ) + if( mPtr == getPlayer() && !isAnimPlaying(mCurrentDeath) ) { //player's death animation is over MWBase::Environment::get().getStateManager()->askLoadRecent(); @@ -1965,7 +1966,7 @@ bool CharacterController::kill() mCurrentIdle.clear(); // Play Death Music if it was the player dying - if(mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(mPtr == getPlayer()) MWBase::Environment::get().getSoundManager()->streamMusic("Special/MW_Death.mp3"); return true; @@ -2006,7 +2007,7 @@ void CharacterController::updateMagicEffects() float alpha = 1.f; if (mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude()) { - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == getPlayer()) alpha = 0.4f; else alpha = 0.f; diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 2e20d0e1f..f11e6bcfd 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -19,6 +19,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwbase/windowmanager.hpp" +#include "actorutil.hpp" namespace { @@ -137,7 +138,7 @@ namespace MWMechanics blockerStats.setBlock(true); - if (blocker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (blocker == getPlayer()) blocker.getClass().skillUsageSucceeded(blocker, ESM::Skill::Block, 0); return true; @@ -161,7 +162,7 @@ namespace MWMechanics && actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) damage *= MWBase::Environment::get().getWorld()->getStore().get().find("fWereWolfSilverWeaponDamageMult")->getFloat(); - if (damage == 0 && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (damage == 0 && attacker == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}"); } @@ -178,7 +179,7 @@ namespace MWMechanics return; } - if(attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(attacker == getPlayer()) MWBase::Environment::get().getWindowManager()->setEnemy(victim); int weapskill = ESM::Skill::Marksman; @@ -207,7 +208,7 @@ namespace MWMechanics adjustWeaponDamage(damage, weapon, attacker); reduceWeaponCondition(damage, true, weapon, attacker); - if(attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(attacker == getPlayer()) attacker.getClass().skillUsageSucceeded(attacker, weapskill, 0); if (victim.getClass().getCreatureStats(victim).getKnockedDown()) @@ -222,7 +223,7 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition); // Non-enchanted arrows shot at enemies have a chance to turn up in their inventory - if (victim != MWBase::Environment::get().getWorld()->getPlayerPtr() + if (victim != getPlayer() && !appliedEnchantment) { float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->getFloat(); @@ -247,7 +248,7 @@ namespace MWMechanics { // Maybe we should keep an aware state for actors updated every so often instead of testing every time bool unaware = (!victimStats.getAiSequence().isInCombat()) - && (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + && (attacker == getPlayer()) && (!MWBase::Environment::get().getMechanicsManager()->awarenessCheck(attacker, victim)); if (!(victimStats.getKnockedDown() || victimStats.isParalyzed() diff --git a/apps/openmw/mwmechanics/difficultyscaling.cpp b/apps/openmw/mwmechanics/difficultyscaling.cpp index 05ab12ccd..950fe33cf 100644 --- a/apps/openmw/mwmechanics/difficultyscaling.cpp +++ b/apps/openmw/mwmechanics/difficultyscaling.cpp @@ -6,9 +6,11 @@ #include +#include "actorutil.hpp" + float scaleDamage(float damage, const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim) { - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = MWMechanics::getPlayer(); // [-100, 100] int difficultySetting = Settings::Manager::getInt("difficulty", "Game"); diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index cf21f3806..27c19364f 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -9,8 +9,10 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwmechanics/spells.hpp" -#include "../mwmechanics/creaturestats.hpp" +#include "spells.hpp" +#include "creaturestats.hpp" +#include "actorutil.hpp" + namespace MWMechanics { @@ -20,7 +22,7 @@ namespace MWMechanics /// @param carrier The disease carrier. inline void diseaseContact (MWWorld::Ptr actor, MWWorld::Ptr carrier) { - if (!carrier.getClass().isActor() || actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (!carrier.getClass().isActor() || actor != getPlayer()) return; float fDiseaseXferChance = diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 2cb963e28..102e3787a 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -11,6 +11,7 @@ #include "creaturestats.hpp" #include "npcstats.hpp" #include "spellcasting.hpp" +#include "actorutil.hpp" namespace MWMechanics { @@ -54,7 +55,7 @@ namespace MWMechanics bool Enchanting::create() { - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = getPlayer(); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); ESM::Enchantment enchantment; enchantment.mData.mCharge = getGemCharge(); @@ -217,7 +218,7 @@ namespace MWMechanics int Enchanting::getEffectiveCastCost() const { int baseCost = getBaseCastCost(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); return getEffectiveEnchantmentCastCost(static_cast(baseCost), player); } @@ -291,7 +292,7 @@ namespace MWMechanics void Enchanting::payForEnchantment() const { - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = getPlayer(); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); store.remove(MWWorld::ContainerStore::sGoldId, getEnchantPrice(), player); diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index f2f0c7cab..edfef5358 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -11,7 +11,8 @@ #include "../mwworld/class.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" -#include "../mwmechanics/creaturestats.hpp" +#include "creaturestats.hpp" +#include "actorutil.hpp" namespace MWMechanics { @@ -21,7 +22,7 @@ namespace MWMechanics { const std::vector& items = levItem->mList; - const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Ptr& player = getPlayer(); int playerLevel = player.getClass().getCreatureStats(player).getLevel(); failChance += levItem->mChanceNone; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 075747ffe..711ecdbd2 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -26,6 +26,7 @@ #include "spellcasting.hpp" #include "autocalcspell.hpp" #include "npcstats.hpp" +#include "actorutil.hpp" namespace { @@ -83,7 +84,7 @@ namespace MWMechanics { void MechanicsManager::buildPlayer() { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr ptr = getPlayer(); MWMechanics::CreatureStats& creatureStats = ptr.getClass().getCreatureStats (ptr); MWMechanics::NpcStats& npcStats = ptr.getClass().getNpcStats (ptr); @@ -361,7 +362,7 @@ namespace MWMechanics { // Uses ingame time, but scaled to real time duration /= MWBase::Environment::get().getWorld()->getTimeScaleFactor(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); player.getClass().getInventoryStore(player).rechargeItems(duration); } @@ -489,7 +490,7 @@ namespace MWMechanics // HACK? The player has been changed, so a new Animation object may // have been made for them. Make sure they're properly updated. - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr ptr = getPlayer(); mActors.removeActor(ptr); mActors.addActor(ptr, true); } @@ -586,7 +587,7 @@ namespace MWMechanics float x = static_cast(npcSkill.getBaseDisposition()); MWWorld::LiveCellRef* npc = ptr.get(); - MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr playerPtr = getPlayer(); MWWorld::LiveCellRef* player = playerPtr.get(); const MWMechanics::NpcStats &playerStats = playerPtr.getClass().getNpcStats(playerPtr); @@ -663,7 +664,7 @@ namespace MWMechanics const MWMechanics::NpcStats &sellerStats = ptr.getClass().getNpcStats(ptr); - MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr playerPtr = getPlayer(); const MWMechanics::NpcStats &playerStats = playerPtr.getClass().getNpcStats(playerPtr); // I suppose the temporary disposition change _has_ to be considered here, @@ -707,7 +708,7 @@ namespace MWMechanics MWMechanics::NpcStats& npcStats = npc.getClass().getNpcStats(npc); - MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr playerPtr = getPlayer(); const MWMechanics::NpcStats &playerStats = playerPtr.getClass().getNpcStats(playerPtr); float npcRating1, npcRating2, npcRating3; @@ -1010,7 +1011,7 @@ namespace MWMechanics void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container, int count) { - if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr != getPlayer()) return; MWWorld::Ptr victim; @@ -1067,7 +1068,7 @@ namespace MWMechanics // NOTE: victim may be empty // Only player can commit crime - if (player != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (player != getPlayer()) return false; // Find all the actors within the alarm radius @@ -1306,7 +1307,7 @@ namespace MWMechanics bool MechanicsManager::actorAttacked(const MWWorld::Ptr &ptr, const MWWorld::Ptr &attacker) { - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == getPlayer()) return false; std::list followers = getActorsFollowing(attacker); @@ -1340,7 +1341,7 @@ namespace MWMechanics commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault); if (!attacker.isEmpty() && (attacker.getClass().getCreatureStats(attacker).getAiSequence().isInCombat(ptr) - || attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + || attacker == getPlayer()) && !seq.isInCombat(attacker)) { // Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back. @@ -1353,7 +1354,7 @@ namespace MWMechanics void MechanicsManager::actorKilled(const MWWorld::Ptr &victim, const MWWorld::Ptr &attacker) { - if (attacker.isEmpty() || attacker != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (attacker.isEmpty() || attacker != getPlayer()) return; if (victim == attacker) @@ -1450,7 +1451,7 @@ namespace MWMechanics if (ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(target)) return; ptr.getClass().getCreatureStats(ptr).getAiSequence().stack(MWMechanics::AiCombat(target), ptr); - if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (target == getPlayer()) { // if guard starts combat with player, guards pursuing player should do the same if (ptr.getClass().isClass(ptr, "Guard")) @@ -1547,7 +1548,7 @@ namespace MWMechanics if (ptr.getClass().isNpc() && target.getClass().isNpc()) { if (target.getClass().getNpcStats(target).isWerewolf() || - (target == MWBase::Environment::get().getWorld()->getPlayerPtr() && + (target == getPlayer() && MWBase::Environment::get().getWorld()->getGlobalInt("pcknownwerewolf"))) { const ESM::GameSetting * iWerewolfFightMod = MWBase::Environment::get().getWorld()->getStore().get().search("iWerewolfFightMod"); @@ -1560,7 +1561,7 @@ namespace MWMechanics void MechanicsManager::keepPlayerAlive() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); CreatureStats& stats = player.getClass().getCreatureStats(player); if (stats.isDead()) { diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index fa429bbee..581ba3a84 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -14,15 +14,16 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwmechanics/creaturestats.hpp" -#include "../mwmechanics/npcstats.hpp" +#include "creaturestats.hpp" +#include "npcstats.hpp" +#include "actorutil.hpp" namespace MWMechanics { void Repair::repair(const MWWorld::Ptr &itemToRepair) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); MWWorld::LiveCellRef *ref = mTool.get(); @@ -82,7 +83,7 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) // tool used up? if (mTool.getCellRef().getCharge() == 0) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = getPlayer(); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); store.remove(mTool, 1, player); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 12ed04428..cbd0b8731 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -26,6 +26,7 @@ #include "magiceffects.hpp" #include "npcstats.hpp" #include "summoning.hpp" +#include "actorutil.hpp" namespace { @@ -133,7 +134,7 @@ namespace MWMechanics int actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified(); float castChance = (lowestSkill - spell->mData.mCost + castBonus + 0.2f * actorWillpower + 0.1f * actorLuck) * stats.getFatigueTerm(); - if (MWBase::Environment::get().getWorld()->getGodModeState() && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (MWBase::Environment::get().getWorld()->getGodModeState() && actor == getPlayer()) castChance = 100; if (!cap) @@ -340,7 +341,7 @@ namespace MWMechanics if (Misc::Rng::roll0to99() <= x) { // Fully resisted, show message - if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (target == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}"); return; } @@ -358,7 +359,7 @@ namespace MWMechanics if (target.getClass().isActor()) targetEffects += target.getClass().getCreatureStats(target).getMagicEffects(); - bool castByPlayer = (!caster.isEmpty() && caster == MWBase::Environment::get().getWorld()->getPlayerPtr()); + bool castByPlayer = (!caster.isEmpty() && caster == getPlayer()); // Try absorbing if it's a spell // NOTE: Vanilla does this once per effect source instead of adding the % from all sources together, not sure @@ -433,7 +434,7 @@ namespace MWMechanics if (magnitudeMult == 0) { // Fully resisted, show message - if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (target == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}"); else if (castByPlayer) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResisted}"); @@ -569,7 +570,7 @@ namespace MWMechanics { if (target.getCellRef().getLockLevel() < magnitude) //If the door is not already locked to a higher value, lock it to spell magnitude { - if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (caster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicLockSuccess}"); target.getClass().lock(target, static_cast(magnitude)); } @@ -585,7 +586,7 @@ namespace MWMechanics if (!caster.isEmpty() && caster.getClass().isActor()) MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target); - if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (caster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicOpenSuccess}"); } target.getClass().unlock(target); @@ -622,7 +623,7 @@ namespace MWMechanics return true; } - if (target != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (target != getPlayer()) return false; if (effectId == ESM::MagicEffect::DivineIntervention) @@ -701,7 +702,7 @@ namespace MWMechanics if (item.getCellRef().getEnchantmentCharge() < castCost) { - if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mCaster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}"); // Failure sound @@ -725,14 +726,14 @@ namespace MWMechanics if (enchantment->mData.mType == ESM::Enchantment::WhenUsed) { - if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mCaster == getPlayer()) mCaster.getClass().skillUsageSucceeded (mCaster, ESM::Skill::Enchant, 1); } if (enchantment->mData.mType == ESM::Enchantment::CastOnce) item.getContainerStore()->remove(item, 1, mCaster); else if (enchantment->mData.mType != ESM::Enchantment::WhenStrikes) { - if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mCaster == getPlayer()) { mCaster.getClass().skillUsageSucceeded (mCaster, ESM::Skill::Enchant, 3); } @@ -799,7 +800,7 @@ namespace MWMechanics float successChance = getSpellSuccessChance(spell, mCaster); if (Misc::Rng::roll0to99() >= successChance) { - if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mCaster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); fail = true; } @@ -817,7 +818,7 @@ namespace MWMechanics } } - if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr() && spellIncreasesSkill(spell)) + if (mCaster == getPlayer() && spellIncreasesSkill(spell)) mCaster.getClass().skillUsageSucceeded(mCaster, spellSchoolToSkill(school), 0); @@ -962,7 +963,7 @@ namespace MWMechanics if (charge == 0) { // Will unequip the broken item and try to find a replacement - if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr != getPlayer()) inv.autoEquip(ptr); else inv.unequipItem(*item, ptr); @@ -1097,7 +1098,7 @@ namespace MWMechanics } - if (receivedMagicDamage && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (receivedMagicDamage && actor == getPlayer()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); } diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 2cb261851..77e2f6803 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -30,6 +30,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/movement.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" @@ -1091,7 +1092,7 @@ namespace MWPhysics bool PhysicsSystem::toggleCollisionMode() { - ActorMap::iterator found = mActors.find(MWBase::Environment::get().getWorld()->getPlayerPtr()); + ActorMap::iterator found = mActors.find(MWMechanics::getPlayer()); if (found != mActors.end()) { bool cmode = found->second->getCollisionMode(); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index b4e1189f7..93afeda25 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -17,6 +17,8 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "npcanimation.hpp" #include "vismask.hpp" @@ -295,7 +297,7 @@ namespace MWRender // -------------------------------------------------------------------------------------------------- RaceSelectionPreview::RaceSelectionPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem) - : CharacterPreview(viewer, resourceSystem, MWBase::Environment::get().getWorld()->getPlayerPtr(), + : CharacterPreview(viewer, resourceSystem, MWMechanics::getPlayer(), 512, 512, osg::Vec3f(0, 125, 8), osg::Vec3f(0,0,8)) , mBase (*mCharacter.get()->mBase) , mRef(&mBase) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index c5a107837..66a3d3ec6 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -21,6 +21,7 @@ #include "../mwworld/class.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -1039,7 +1040,7 @@ void NpcAnimation::setVampire(bool vampire) return; if ((mNpcType == Type_Vampire) != vampire) { - if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mPtr == MWMechanics::getPlayer()) MWBase::Environment::get().getWorld()->reattachPlayerCamera(); else rebuild(); diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index a3e96a5b1..a7637f2e1 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -22,6 +22,8 @@ #include "../mwworld/fallback.hpp" +#include "../mwmechanics/actorutil.hpp" + namespace { void createWaterRippleStateSet(Resource::ResourceSystem* resourceSystem, const MWWorld::Fallback* fallback, osg::Node* node) @@ -177,7 +179,7 @@ void RippleSimulation::removeCell(const MWWorld::CellStore *store) { for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end();) { - if (it->mPtr.getCell() == store && it->mPtr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (it->mPtr.getCell() == store && it->mPtr != MWMechanics::getPlayer()) { it = mEmitters.erase(it); } diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 8af2e5ef3..5dd3cf411 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -16,6 +16,8 @@ #include "../mwworld/player.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "interpretercontext.hpp" namespace MWScript @@ -91,14 +93,14 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + if (!MWMechanics::getPlayer().isInCell()) { runtime.push (0); return; } bool interior = - !MWBase::Environment::get().getWorld()->getPlayerPtr().getCell()->getCell()->isExterior(); + !MWMechanics::getPlayer().getCell()->getCell()->isExterior(); runtime.push (interior ? 1 : 0); } @@ -113,12 +115,12 @@ namespace MWScript std::string name = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + if (!MWMechanics::getPlayer().isInCell()) { runtime.push(0); return; } - const MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); + const MWWorld::CellStore *cell = MWMechanics::getPlayer().getCell(); std::string current = MWBase::Environment::get().getWorld()->getCellName(cell); Misc::StringUtils::toLower(current); @@ -136,12 +138,12 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + if (!MWMechanics::getPlayer().isInCell()) { runtime.push(0.f); return; } - MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); + MWWorld::CellStore *cell = MWMechanics::getPlayer().getCell(); if (cell->getCell()->hasWater()) runtime.push (cell->getWaterLevel()); else @@ -157,12 +159,12 @@ namespace MWScript { Interpreter::Type_Float level = runtime[0].mFloat; - if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + if (!MWMechanics::getPlayer().isInCell()) { return; } - MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); + MWWorld::CellStore *cell = MWMechanics::getPlayer().getCell(); if (cell->getCell()->isExterior()) throw std::runtime_error("Can't set water level in exterior cell"); @@ -180,12 +182,12 @@ namespace MWScript { Interpreter::Type_Float level = runtime[0].mFloat; - if (!MWBase::Environment::get().getWorld()->getPlayerPtr().isInCell()) + if (!MWMechanics::getPlayer().isInCell()) { return; } - MWWorld::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(); + MWWorld::CellStore *cell = MWMechanics::getPlayer().getCell(); if (cell->getCell()->isExterior()) throw std::runtime_error("Can't set water level in exterior cell"); diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 674973978..20ca2b580 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -26,6 +26,8 @@ #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "interpretercontext.hpp" #include "ref.hpp" @@ -147,7 +149,7 @@ namespace MWScript // Spawn a messagebox (only for items removed from player's inventory) if ((numRemoved > 0) - && (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())) + && (ptr == MWMechanics::getPlayer())) { // The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory std::string msgBox; @@ -192,7 +194,7 @@ namespace MWScript MWWorld::ActionEquip action (*it); action.execute(ptr); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() && !ptr.getClass().getScript(ptr).empty()) + if (ptr == MWMechanics::getPlayer() && !ptr.getClass().getScript(ptr).empty()) ptr.getRefData().getLocals().setVarByInt(ptr.getClass().getScript(ptr), "onpcequip", 1); } }; diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index f48360c04..397e0cac5 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -14,6 +14,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "interpretercontext.hpp" #include "ref.hpp" @@ -53,7 +55,7 @@ namespace MWScript { MWWorld::Ptr bed = R()(runtime, false); - if (bed.isEmpty() || !MWBase::Environment::get().getMechanicsManager()->sleepInBed(MWBase::Environment::get().getWorld()->getPlayerPtr(), + if (bed.isEmpty() || !MWBase::Environment::get().getMechanicsManager()->sleepInBed(MWMechanics::getPlayer(), bed)) MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_RestBed); } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index faf574993..32d86f55a 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -27,6 +27,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/actorutil.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -156,7 +157,7 @@ namespace MWScript MWWorld::Ptr ptr = R()(runtime); - context.executeActivation(ptr, MWBase::Environment::get().getWorld()->getPlayerPtr()); + context.executeActivation(ptr, MWMechanics::getPlayer()); } }; @@ -976,7 +977,7 @@ namespace MWScript public: virtual void execute(Interpreter::Runtime &runtime) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats(player).setBounty(0); MWBase::Environment::get().getWorld()->confiscateStolenItems(player); MWBase::Environment::get().getWorld()->getPlayer().recordCrimeId(); @@ -988,7 +989,7 @@ namespace MWScript public: virtual void execute(Interpreter::Runtime &runtime) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats(player).setBounty(0); MWBase::Environment::get().getWorld()->getPlayer().recordCrimeId(); } diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 112e7c77f..4debb24fe 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -25,6 +25,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -460,7 +461,7 @@ namespace MWScript MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() && + if (ptr == MWMechanics::getPlayer() && id == wm->getSelectedSpell()) { wm->unsetSelectedSpell(); @@ -548,7 +549,7 @@ namespace MWScript if(factionID != "") { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats(player).joinFaction(factionID); } } @@ -580,7 +581,7 @@ namespace MWScript if(factionID != "") { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if(player.getClass().getNpcStats(player).getFactionRanks().find(factionID) == player.getClass().getNpcStats(player).getFactionRanks().end()) { player.getClass().getNpcStats(player).joinFaction(factionID); @@ -619,7 +620,7 @@ namespace MWScript if(factionID != "") { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats(player).lowerRank(factionID); } } @@ -648,7 +649,7 @@ namespace MWScript // Make sure this faction exists MWBase::Environment::get().getWorld()->getStore().get().find(factionID); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if(factionID!="") { if(player.getClass().getNpcStats(player).getFactionRanks().find(factionID) != player.getClass().getNpcStats(player).getFactionRanks().end()) @@ -757,7 +758,7 @@ namespace MWScript ::Misc::StringUtils::toLower (factionId); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); runtime.push ( player.getClass().getNpcStats (player).getFactionReputation (factionId)); } @@ -792,7 +793,7 @@ namespace MWScript ::Misc::StringUtils::toLower (factionId); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats (player).setFactionReputation (factionId, value); } }; @@ -826,7 +827,7 @@ namespace MWScript ::Misc::StringUtils::toLower (factionId); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); player.getClass().getNpcStats (player).setFactionReputation (factionId, player.getClass().getNpcStats (player).getFactionReputation (factionId)+ value); @@ -911,7 +912,7 @@ namespace MWScript factionID = ptr.getClass().getPrimaryFaction(ptr); } ::Misc::StringUtils::toLower(factionID); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if(factionID!="") { runtime.push(player.getClass().getNpcStats(player).getExpelled(factionID)); @@ -942,7 +943,7 @@ namespace MWScript { factionID = ptr.getClass().getPrimaryFaction(ptr); } - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if(factionID!="") { player.getClass().getNpcStats(player).expell(factionID); @@ -969,7 +970,7 @@ namespace MWScript { factionID = ptr.getClass().getPrimaryFaction(ptr); } - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if(factionID!="") player.getClass().getNpcStats(player).clearExpelled(factionID); } @@ -988,7 +989,7 @@ namespace MWScript if(factionID.empty()) return; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); // no-op when executed on the player if (ptr == player) @@ -1011,7 +1012,7 @@ namespace MWScript if(factionID.empty()) return; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); // no-op when executed on the player if (ptr == player) @@ -1120,7 +1121,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) ptr.getClass().getCreatureStats(ptr).resurrect(); else if (ptr.getClass().getCreatureStats(ptr).isDead()) { diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 0f9faa11a..679a8d2de 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -20,6 +20,8 @@ #include "../mwworld/player.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "interpretercontext.hpp" #include "ref.hpp" @@ -214,7 +216,7 @@ namespace MWScript if (!ptr.isInCell()) return; - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -289,7 +291,7 @@ namespace MWScript if (ptr.getContainerStore()) return; - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -333,7 +335,7 @@ namespace MWScript // Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200) // except for when you position the player, then degrees must be used. // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. - if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(ptr != MWMechanics::getPlayer()) zRot = zRot/60.0f; MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); @@ -354,7 +356,7 @@ namespace MWScript if (!ptr.isInCell()) return; - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -372,7 +374,7 @@ namespace MWScript // another morrowind oddity: player will be moved to the exterior cell at this location, // non-player actors will move within the cell they are in. - if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (ptr == MWMechanics::getPlayer()) { MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); MWBase::Environment::get().getWorld()->moveObject(ptr,cell,x,y,z); @@ -389,7 +391,7 @@ namespace MWScript // Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200) // except for when you position the player, then degrees must be used. // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. - if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if(ptr != MWMechanics::getPlayer()) zRot = zRot/60.0f; MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); ptr.getClass().adjustPosition(ptr, false); @@ -469,7 +471,7 @@ namespace MWScript Interpreter::Type_Float zRot = runtime[0].mFloat; runtime.pop(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::CellStore* store = NULL; if (player.getCell()->isExterior()) { @@ -501,7 +503,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr actor = pc - ? MWBase::Environment::get().getWorld()->getPlayerPtr() + ? MWMechanics::getPlayer() : R()(runtime); std::string itemID = runtime.getStringLiteral (runtime[0].mInteger); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 1f73fc1fc..bc97f1601 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -15,6 +15,8 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "sound_output.hpp" #include "sound_decoder.hpp" #include "sound.hpp" @@ -490,7 +492,7 @@ namespace MWSound while(snditer != mActiveSounds.end()) { if(snditer->second.first != MWWorld::Ptr() && - snditer->second.first != MWBase::Environment::get().getWorld()->getPlayerPtr() && + snditer->second.first != MWMechanics::getPlayer() && snditer->second.first.getCell() == cell) { snditer->first->stop(); @@ -735,7 +737,7 @@ namespace MWSound mListenerUp = up; MWWorld::Ptr player = - MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWMechanics::getPlayer(); const MWWorld::CellStore *cell = player.getCell(); mListenerUnderwater = ((cell->getCell()->mData.mFlags&ESM::Cell::HasWater) && mListenerPos.z() < cell->getWaterLevel()); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index f4a7ee9f2..6995e24be 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -36,6 +36,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwscript/globalscripts.hpp" @@ -472,7 +473,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str if (firstPersonCam != MWBase::Environment::get().getWorld()->isFirstPerson()) MWBase::Environment::get().getWorld()->togglePOV(); - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr ptr = MWMechanics::getPlayer(); ESM::CellId cellId = ptr.getCell()->getCell()->getCellId(); @@ -519,7 +520,7 @@ void MWState::StateManager::deleteGame(const MWState::Character *character, cons MWState::Character *MWState::StateManager::getCurrentCharacter (bool create) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); std::string name = player.get()->mBase->mName; return mCharacterManager.getCurrentCharacter (create, name); diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index fb2059de9..6361b3404 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -5,6 +5,8 @@ #include "../mwbase/soundmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + const MWWorld::Ptr& MWWorld::Action::getTarget() const { return mTarget; @@ -19,7 +21,7 @@ void MWWorld::Action::execute (const Ptr& actor) { if (!mSoundId.empty()) { - if (mKeepSound && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (mKeepSound && actor == MWMechanics::getPlayer()) MWBase::Environment::get().getSoundManager()->playSound(mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Normal,mSoundOffset); else diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 87a4c6308..147f22963 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -4,6 +4,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include #include "inventorystore.hpp" @@ -24,7 +26,7 @@ namespace MWWorld std::pair result = object.getClass().canBeEquipped (object, actor); // display error message if the player tried to equip something - if (!result.second.empty() && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (!result.second.empty() && actor == MWMechanics::getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox(result.second); switch(result.first) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 05ae4f134..8c6f7d259 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -11,6 +11,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/levelledlist.hpp" +#include "../mwmechanics/actorutil.hpp" #include "manualref.hpp" #include "refdata.hpp" @@ -209,7 +210,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(const std::string & { MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), id, count); // a bit pointless to set owner for the player - if (actorPtr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actorPtr != MWMechanics::getPlayer()) return add(ref.getPtr(), count, actorPtr, true); else return add(ref.getPtr(), count, actorPtr, false); @@ -224,7 +225,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr // HACK: Set owner on the original item, then reset it after we have copied it // If we set the owner on the copied item, it would not stack correctly... std::string oldOwner = itemPtr.getCellRef().getOwner(); - if (!setOwner || actorPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) // No point in setting owner to the player - NPCs will not respect this anyway + if (!setOwner || actorPtr == MWMechanics::getPlayer()) // No point in setting owner to the player - NPCs will not respect this anyway { itemPtr.getCellRef().setOwner(""); } diff --git a/apps/openmw/mwworld/failedaction.cpp b/apps/openmw/mwworld/failedaction.cpp index cf5a2a5c2..49ca9dae0 100644 --- a/apps/openmw/mwworld/failedaction.cpp +++ b/apps/openmw/mwworld/failedaction.cpp @@ -4,6 +4,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWWorld { @@ -13,7 +14,7 @@ namespace MWWorld void FailedAction::executeImp(const Ptr &actor) { - if(actor == MWBase::Environment::get().getWorld()->getPlayerPtr() && !mMessage.empty()) + if(actor == MWMechanics::getPlayer() && !mMessage.empty()) MWBase::Environment::get().getWindowManager()->messageBox(mMessage); } } diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 2dbc22234..0755c1555 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -16,6 +16,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/actorutil.hpp" #include "esmstore.hpp" @@ -136,7 +137,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr, const MWWorld::ContainerStoreIterator& retVal = MWWorld::ContainerStore::add(itemPtr, count, actorPtr, setOwner); // Auto-equip items if an armor/clothing or weapon item is added, but not for the player nor werewolves - if (actorPtr != MWBase::Environment::get().getWorld()->getPlayerPtr() + if (actorPtr != MWMechanics::getPlayer() && !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf())) { std::string type = itemPtr.getTypeName(); @@ -508,7 +509,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor // If an armor/clothing item is removed, try to find a replacement, // but not for the player nor werewolves. - if (wasEquipped && (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (wasEquipped && (actor != MWMechanics::getPlayer()) && !(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())) { std::string type = item.getTypeName(); @@ -540,7 +541,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, c { retval = restack(*it); - if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor == MWMechanics::getPlayer()) { // Unset OnPCEquip Variable on item's script, if it has a script with that variable declared const std::string& script = it->getClass().getScript(*it); @@ -595,7 +596,7 @@ void MWWorld::InventoryStore::fireEquipmentChangedEvent(const Ptr& actor) // if player, update inventory window /* - if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor == MWMechanics::getPlayer()) { MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); } diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 6295ed159..3e9f17278 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -20,6 +20,7 @@ #include "../mwmechanics/combat.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwrender/effectmanager.hpp" #include "../mwrender/animation.hpp" @@ -187,7 +188,7 @@ namespace MWWorld } // Explodes when hitting water - if (MWBase::Environment::get().getWorld()->isUnderwater(MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), newPos)) + if (MWBase::Environment::get().getWorld()->isUnderwater(MWMechanics::getPlayer().getCell(), newPos)) hit = true; if (hit) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 99193de67..cc5b726af 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -12,6 +12,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "../mwsound/sound.hpp" #include "../mwrender/renderingmanager.hpp" @@ -798,7 +800,7 @@ void WeatherManager::changeWeather(const std::string& region, const unsigned int mRegionOverrides[Misc::StringUtils::lowerCase(region)] = weather; - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::Ptr player = MWMechanics::getPlayer(); if (player.isInCell()) { std::string playerRegion = player.getCell()->getCell()->mRegion; From 3fa5c6a0e781e7cd4f659694f56a71d2671bf06b Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 21 Aug 2015 22:00:08 +1200 Subject: [PATCH 292/419] fixed travis build failure --- apps/openmw/mwrender/renderingmanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1a1b04d18..f4b8aa451 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1,6 +1,7 @@ #include "renderingmanager.hpp" #include +#include #include #include From 5dd0ad684123f9e9fcee602c37ed30f8747f9ecf Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 21 Aug 2015 22:41:31 +1200 Subject: [PATCH 293/419] Fixed rest of travis errors. --- apps/openmw/mwmechanics/autocalcspell.cpp | 1 + apps/openmw/mwmechanics/pathfinding.cpp | 1 + apps/openmw/mwmechanics/spellcasting.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index 5dfe388a8..b798ff5dc 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -1,6 +1,7 @@ #include "autocalcspell.hpp" #include +#include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f40624ae8..f53badbf4 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -1,4 +1,5 @@ #include "pathfinding.hpp" +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 59410001f..99625e90a 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -1,6 +1,7 @@ #include "spellcasting.hpp" #include +#include #include From 3902513e65206908c0f0f54db213a7c9ea7f2fd0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 21 Aug 2015 14:02:32 +0200 Subject: [PATCH 294/419] merge id collections --- apps/opencs/model/tools/mergeoperation.cpp | 23 ++++++++++ apps/opencs/model/tools/mergestages.hpp | 53 +++++++++++++++++++++- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 9e5fb2745..4a85eca79 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -10,6 +10,29 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr : CSMDoc::Operation (CSMDoc::State_Merging, true), mState (document) { appendStage (new FinishMergedDocumentStage (mState, encoding)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getGlobals)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getGmsts)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSkills)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getClasses)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getFactions)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getRaces)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSounds)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getScripts)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getRegions)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getBirthsigns)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSpells)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getTopics)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getJournals)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getCells)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getFilters)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getEnchantments)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getBodyParts)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getDebugProfiles)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSoundGens)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getMagicEffects)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getStartScripts)); + + /// \todo TopicInfo, JournalInfo, Referencables, References, Land, LandTextures, Pathgrids } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 9844feaca..749fab18c 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -5,10 +5,12 @@ #include "../doc/stage.hpp" +#include "../world/data.hpp" + +#include "mergestate.hpp" + namespace CSMTools { - struct MergeState; - class FinishMergedDocumentStage : public CSMDoc::Stage { MergeState& mState; @@ -24,6 +26,53 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. }; + + template + class MergeIdCollectionStage : public CSMDoc::Stage + { + typedef typename CSMWorld::IdCollection Collection; + + MergeState& mState; + Collection& (CSMWorld::Data::*mAccessor)(); + + public: + + MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + + template + MergeIdCollectionStage::MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()) + : mState (state), mAccessor (accessor) + {} + + template + int MergeIdCollectionStage::setup() + { + return 1; + } + + template + void MergeIdCollectionStage::perform (int stage, CSMDoc::Messages& messages) + { + const Collection& source = (mState.mSource.getData().*mAccessor)(); + Collection& target = (mState.mTarget->getData().*mAccessor)(); + + int size = source.getSize(); + + for (int i=0; i& record = source.getRecord (i); + + if (!record.isDeleted()) + target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_BaseOnly, &record.get())); + } + } } #endif From 52d8bc555c10b1ef8ac263856ff2e8d4131c7160 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 21 Aug 2015 14:24:34 +0200 Subject: [PATCH 295/419] Add missing checks to see if spell still exists when loading a savegame (Bug #2883) --- apps/openmw/mwgui/quickkeysmenu.cpp | 3 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 3f896bae2..89e6e59be 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -467,7 +467,8 @@ namespace MWGui switch (keyType) { case Type_Magic: - onAssignMagic(id); + if (MWBase::Environment::get().getWorld()->getStore().get().search(id)) + onAssignMagic(id); break; case Type_Item: case Type_MagicItem: diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index db5593704..7f9302bf2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1686,7 +1686,9 @@ namespace MWGui else if (type == ESM::REC_ASPL) { reader.getSubNameIs("ID__"); - mSelectedSpell = reader.getHString(); + std::string spell = reader.getHString(); + if (MWBase::Environment::get().getWorld()->getStore().get().search(spell)) + mSelectedSpell = spell; } else if (type == ESM::REC_MARK) { From ba8e4c22aa51efa5f689dfecfe0673b96c56a57a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 21 Aug 2015 20:17:42 +0200 Subject: [PATCH 296/419] Avoid using loops to wrap angle values (Fixes #2882) --- apps/openmw/mwworld/worldimp.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1eed841bd..aa444cb14 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1213,7 +1213,6 @@ namespace MWWorld void World::rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, bool adjust) { const float pi = static_cast(osg::PI); - const float two_pi = pi*2.f; ESM::Position pos = ptr.getRefData().getPosition(); float *objRot = pos.rot; @@ -1243,15 +1242,11 @@ namespace MWWorld } else { - while(objRot[0] < -pi) objRot[0] += two_pi; - while(objRot[0] > pi) objRot[0] -= two_pi; + wrap(objRot[0]); } - while(objRot[1] < -pi) objRot[1] += two_pi; - while(objRot[1] > pi) objRot[1] -= two_pi; - - while(objRot[2] < -pi) objRot[2] += two_pi; - while(objRot[2] > pi) objRot[2] -= two_pi; + wrap(objRot[1]); + wrap(objRot[2]); ptr.getRefData().setPosition(pos); From d038ac2da092629e7b08379ae938f2666073b574 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 21 Aug 2015 21:38:28 +0300 Subject: [PATCH 297/419] Sort tables by ID in the ascending order initially --- apps/opencs/view/world/table.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 72e0c82d0..73bef7b26 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -273,12 +273,16 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, horizontalHeader()->setResizeMode (QHeaderView::Interactive); #endif verticalHeader()->hide(); - setSortingEnabled (sorting); setSelectionBehavior (QAbstractItemView::SelectRows); setSelectionMode (QAbstractItemView::ExtendedSelection); - int columns = mModel->columnCount(); + setSortingEnabled (sorting); + if (sorting) + { + sortByColumn (mModel->findColumnIndex(CSMWorld::Columns::ColumnId_Id), Qt::AscendingOrder); + } + int columns = mModel->columnCount(); for (int i=0; iheaderData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); From e14aedc7cde788e3a9d67c555a749fd319a2e656 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 21 Aug 2015 21:47:29 +0300 Subject: [PATCH 298/419] ModifyCommand uses a proper name of a modified nested value --- apps/opencs/model/world/commands.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 7673e6bc9..d510cd103 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -21,12 +21,17 @@ CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelI // Replace proxy with actual model mIndex = proxy->mapToSource (index); mModel = proxy->sourceModel(); + } + if (mIndex.parent().isValid()) + { setText ("Modify " + dynamic_cast(mModel)->nestedHeaderData ( mIndex.parent().column(), mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); } else + { setText ("Modify " + mModel->headerData (mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); + } // Remember record state before the modification if (CSMWorld::IdTable *table = dynamic_cast(mModel)) From aeb1acca514d86e8cb4fcc41c1045f4b1f1886a0 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 21 Aug 2015 22:05:40 +0300 Subject: [PATCH 299/419] Remove enum names for AiWanderRepeat column --- apps/opencs/model/world/columns.cpp | 6 ------ apps/opencs/view/doc/viewmanager.cpp | 1 - 2 files changed, 7 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 1fcf0ae41..045438bef 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -536,11 +536,6 @@ namespace "AI Wander", "AI Travel", "AI Follow", "AI Escort", "AI Activate", 0 }; - static const char *sAiWanderRepeat[] = - { - "No", "Yes", 0 - }; - static const char *sInfoCondFunc[] = { " ", "Function", "Global", "Local", "Journal", @@ -580,7 +575,6 @@ namespace case CSMWorld::Columns::ColumnId_EffectId: return sEffectId; case CSMWorld::Columns::ColumnId_PartRefType: return sPartRefType; case CSMWorld::Columns::ColumnId_AiPackageType: return sAiPackageType; - case CSMWorld::Columns::ColumnId_AiWanderRepeat: return sAiWanderRepeat; case CSMWorld::Columns::ColumnId_InfoCondFunc: return sInfoCondFunc; // FIXME: don't have dynamic value enum delegate, use Display_String for now //case CSMWorld::Columns::ColumnId_InfoCond: return sInfoCond; diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 7c9686277..3e832bdcf 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -102,7 +102,6 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false }, { CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false }, { CSMWorld::ColumnBase::Display_AiPackageType, CSMWorld::Columns::ColumnId_AiPackageType, false }, - { CSMWorld::ColumnBase::Display_Boolean, CSMWorld::Columns::ColumnId_AiWanderRepeat, false }, { CSMWorld::ColumnBase::Display_InfoCondFunc, CSMWorld::Columns::ColumnId_InfoCondFunc, false }, { CSMWorld::ColumnBase::Display_InfoCondComp, CSMWorld::Columns::ColumnId_InfoCondComp, false }, { CSMWorld::ColumnBase::Display_RaceSkill, CSMWorld::Columns::ColumnId_RaceSkill, true }, From b7295e263210ce0a6c1f46c61189b44c1d188951 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 21 Aug 2015 22:36:53 +0300 Subject: [PATCH 300/419] Columns with Display_Boolean use Combobox editor even for non-boolean values --- apps/opencs/view/world/util.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 2654644c4..b87d6b4f4 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "../../model/world/commands.hpp" #include "../../model/world/tablemimedata.hpp" @@ -172,7 +173,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO // TODO: Find a better solution? if (display == CSMWorld::ColumnBase::Display_Boolean) { - return QStyledItemDelegate::createEditor(parent, option, index); + return QItemEditorFactory::defaultFactory()->createEditor(QVariant::Bool, parent); } // For tables the pop-up of the color editor should appear immediately after the editor creation // (the third parameter of ColorEditor's constructor) From 031d64d0d34f6ac72520ffcdf5634454e34f475a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 22 Aug 2015 12:57:39 +0200 Subject: [PATCH 301/419] Adjust OpenCS saving stages order to stop vanilla MW complaining about missing records --- apps/opencs/model/doc/saving.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 25372f1a6..95a2feaf2 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -80,22 +80,25 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new WriteCollectionStage > (mDocument.getData().getStartScripts(), mState)); - appendStage (new WriteDialogueCollectionStage (mDocument, mState, false)); - - appendStage (new WriteDialogueCollectionStage (mDocument, mState, true)); - appendStage (new WriteRefIdCollectionStage (mDocument, mState)); appendStage (new CollectionReferencesStage (mDocument, mState)); appendStage (new WriteCellCollectionStage (mDocument, mState)); + // Dialogue can reference objects and cells so must be written after these records for vanilla-compatible files + + appendStage (new WriteDialogueCollectionStage (mDocument, mState, false)); + + appendStage (new WriteDialogueCollectionStage (mDocument, mState, true)); + appendStage (new WritePathgridCollectionStage (mDocument, mState)); - appendStage (new WriteLandCollectionStage (mDocument, mState)); - appendStage (new WriteLandTextureCollectionStage (mDocument, mState)); + // references Land Textures + appendStage (new WriteLandCollectionStage (mDocument, mState)); + // close file and clean up appendStage (new CloseSaveStage (mState)); From 32ad8c86bf6c3414651c899d6859ed2463e4afca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 22 Aug 2015 13:10:54 +0200 Subject: [PATCH 302/419] Fix the ESM::LandTexture NAME being discarded on loading --- apps/opencs/model/doc/savingstages.cpp | 2 ++ apps/opencs/model/world/landtexture.cpp | 8 +------- apps/opencs/model/world/landtexture.hpp | 7 ++----- apps/opencs/view/render/terrainstorage.cpp | 14 +++++++++++--- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index ef3b23ec8..01d260d68 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -454,6 +454,8 @@ void CSMDoc::WriteLandTextureCollectionStage::perform (int stage, Messages& mess mState.getWriter().startRecord (record.sRecordId); + mState.getWriter().writeHNString("NAME", record.mId); + record.save (mState.getWriter()); mState.getWriter().endRecord (record.sRecordId); diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 4725866a5..e7772129c 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -9,13 +9,7 @@ namespace CSMWorld { ESM::LandTexture::load(esm); - int plugin = esm.getIndex(); - - std::ostringstream stream; - - stream << mIndex << "_" << plugin; - - mId = stream.str(); + mPluginIndex = esm.getIndex(); } } diff --git a/apps/opencs/model/world/landtexture.hpp b/apps/opencs/model/world/landtexture.hpp index b13903186..c0b6eeba9 100644 --- a/apps/opencs/model/world/landtexture.hpp +++ b/apps/opencs/model/world/landtexture.hpp @@ -7,13 +7,10 @@ namespace CSMWorld { - /// \brief Wrapper for LandTexture record. Encodes mIndex and the plugin index (obtained from ESMReader) - /// in the ID. - /// - /// \attention The mId field of the ESM::LandTexture struct is not used. + /// \brief Wrapper for LandTexture record, providing info which plugin the LandTexture was loaded from. struct LandTexture : public ESM::LandTexture { - std::string mId; + int mPluginIndex; void load (ESM::ESMReader &esm); }; diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index fe302cef1..3d9d1ee97 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -29,10 +29,18 @@ namespace CSVRender const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin) { - std::ostringstream stream; - stream << index << "_" << plugin; + int numRecords = mData.getLandTextures().getSize(); - return &mData.getLandTextures().getRecord(stream.str()).get(); + for (int i=0; imIndex == index && ltex->mPluginIndex == plugin) + return ltex; + } + + std::stringstream error; + error << "Can't find LandTexture " << index << " from plugin " << plugin; + throw std::runtime_error(error.str()); } void TerrainStorage::getBounds(float &minX, float &maxX, float &minY, float &maxY) From 6d81ca07b5d765fcf479480896f8bc2d2eb6cfd4 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Fri, 21 Aug 2015 22:55:58 +0300 Subject: [PATCH 303/419] Convert AiWanderRepeat to bool in ActorAiRefIdAdapter::getNestedData() --- apps/opencs/model/world/refidadapterimp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 4066b5646..5ceb3325a 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1566,7 +1566,7 @@ namespace CSMWorld return QVariant(); case 5: // wander repeat if (content.mType == ESM::AI_Wander) - return content.mWander.mShouldRepeat; + return content.mWander.mShouldRepeat != 0; else return QVariant(); case 6: // activate name From 4d24eff859aec2b8f5c901b35bae11e0e30c068c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 22 Aug 2015 00:01:27 +0300 Subject: [PATCH 304/419] Show race only when mesh type is Skin (in BodyParts table) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/columnimp.cpp | 28 +++++++++++++++++++++++++++ apps/opencs/model/world/columnimp.hpp | 19 +++++++++++++++--- apps/opencs/model/world/data.cpp | 7 +++++-- 4 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 apps/opencs/model/world/columnimp.cpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index b1953ee97..9dd7e8c8e 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -23,7 +23,7 @@ opencs_units (model/world opencs_units_noqt (model/world - universalid record commands columnbase scriptcontext cell refidcollection + universalid record commands columnbase columnimp scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection idcompletionmanager metadata diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp new file mode 100644 index 000000000..dc3d39edb --- /dev/null +++ b/apps/opencs/model/world/columnimp.cpp @@ -0,0 +1,28 @@ +#include "columnimp.hpp" + +CSMWorld::BodyPartRaceColumn::BodyPartRaceColumn(const MeshTypeColumn *meshType) + : mMeshType(meshType) +{} + +QVariant CSMWorld::BodyPartRaceColumn::get(const Record &record) const +{ + if (mMeshType != NULL && mMeshType->get(record) == ESM::BodyPart::MT_Skin) + { + return QString::fromUtf8(record.get().mRace.c_str()); + } + return QVariant(QVariant::UserType); +} + +void CSMWorld::BodyPartRaceColumn::set(Record &record, const QVariant &data) +{ + ESM::BodyPart record2 = record.get(); + + record2.mRace = data.toString().toUtf8().constData(); + + record.setModified(record2); +} + +bool CSMWorld::BodyPartRaceColumn::isEditable() const +{ + return true; +} diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 15dd2c15b..824196c88 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -9,6 +9,8 @@ #include +#include + #include "columnbase.hpp" #include "columns.hpp" #include "info.hpp" @@ -1911,8 +1913,8 @@ namespace CSMWorld template struct MeshTypeColumn : public Column { - MeshTypeColumn() - : Column (Columns::ColumnId_MeshType, ColumnBase::Display_MeshType) + MeshTypeColumn(int flags = ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue) + : Column (Columns::ColumnId_MeshType, ColumnBase::Display_MeshType, flags) {} virtual QVariant get (const Record& record) const @@ -2379,7 +2381,18 @@ namespace CSMWorld { return true; } - }; + }; + + struct BodyPartRaceColumn : public RaceColumn + { + const MeshTypeColumn *mMeshType; + + BodyPartRaceColumn(const MeshTypeColumn *meshType); + + virtual QVariant get(const Record &record) const; + virtual void set(Record &record, const QVariant &data); + virtual bool isEditable() const; + }; } #endif diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 12ff1a38c..94312ae7d 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -351,9 +351,12 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mBodyParts.addColumn (new FlagColumn (Columns::ColumnId_Female, ESM::BodyPart::BPF_Female)); mBodyParts.addColumn (new FlagColumn (Columns::ColumnId_Playable, ESM::BodyPart::BPF_NotPlayable, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, true)); - mBodyParts.addColumn (new MeshTypeColumn); + + int meshTypeFlags = ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh; + MeshTypeColumn *meshTypeColumn = new MeshTypeColumn(meshTypeFlags); + mBodyParts.addColumn (meshTypeColumn); mBodyParts.addColumn (new ModelColumn); - mBodyParts.addColumn (new RaceColumn); + mBodyParts.addColumn (new BodyPartRaceColumn(meshTypeColumn)); mSoundGens.addColumn (new StringIdColumn); mSoundGens.addColumn (new RecordStateColumn); From 720aca8f3dae258cc23ae7c28307ef5ab47637d1 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 22 Aug 2015 13:38:38 +0300 Subject: [PATCH 305/419] Inform about State change (not a whole row) when modifying a table value --- apps/opencs/model/world/idtable.cpp | 11 +++++++---- apps/opencs/model/world/idtree.cpp | 13 +++++++------ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index bdbc5e0c4..bd1179cea 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -76,12 +76,15 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) { mIdCollection->setData (index.row(), index.column(), value); + emit dataChanged(index, index); // Modifying a value can also change the Modified status of a record. - // To track this, we inform about the change of a whole row. - QModelIndex rowStart = this->index(index.row(), 0); - QModelIndex rowEnd = this->index(index.row(), columnCount(index.parent()) - 1); - emit dataChanged(rowStart, rowEnd); + int stateColumn = searchColumnIndex(Columns::ColumnId_Modification); + if (stateColumn != -1) + { + QModelIndex stateIndex = this->index(index.row(), stateColumn); + emit dataChanged(stateIndex, stateIndex); + } return true; } diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 0b027cdab..124a94e8c 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -95,14 +95,15 @@ bool CSMWorld::IdTree::setData (const QModelIndex &index, const QVariant &value, const std::pair& parentAddress(unfoldIndexAddress(index.internalId())); mNestedCollection->setNestedData(parentAddress.first, parentAddress.second, value, index.row(), index.column()); - emit dataChanged(index, index); - // Modifying a value can also change the Modified status of a record (located in the parent row). - // To track this, we inform about the change of a whole parent row. - QModelIndex parentRowStart = this->index(index.parent().row(), 0); - QModelIndex parentRowEnd = this->index(index.parent().row(), columnCount(index.parent()) - 1); - emit dataChanged(parentRowStart, parentRowEnd); + // Modifying a value can also change the Modified status of a record. + int stateColumn = searchColumnIndex(Columns::ColumnId_Modification); + if (stateColumn != -1) + { + QModelIndex stateIndex = this->index(index.parent().row(), stateColumn); + emit dataChanged(stateIndex, stateIndex); + } return true; } From ba4b7df99dc2d0e1b3f6189158c5c4f1aaab57ee Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 22 Aug 2015 14:34:05 +0300 Subject: [PATCH 306/419] Add missing includes to columnimp.hpp --- apps/opencs/model/world/columnimp.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 824196c88..4e608dbbd 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -10,6 +10,8 @@ #include #include +#include +#include #include "columnbase.hpp" #include "columns.hpp" From 542c648e6986160c7590703a6c1811ec06e34c8a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 22 Aug 2015 22:53:06 +0200 Subject: [PATCH 307/419] Fix incorrect assignment of PcRace, need to sort race IDs (Fixes #2884) --- apps/openmw/mwworld/store.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 3cbd8d3ac..47c87f742 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -170,6 +170,7 @@ namespace MWWorld size_t getSize() const; int getDynamicSize() const; + /// @note The record identifiers are listed in the order that the records were defined by the content files. void listIdentifier(std::vector &list) const; T *insert(const T &item); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5b2624f4c..8b53d1675 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1496,6 +1496,8 @@ namespace MWWorld std::vector ids; getStore().get().listIdentifier(ids); + std::sort(ids.begin(), ids.end()); + unsigned int i=0; for (; i Date: Sun, 23 Aug 2015 12:37:45 +0200 Subject: [PATCH 308/419] flag newly merged documents as dirty (triggering an 'are you sure' dialogue when closing without saving first) --- apps/opencs/model/doc/document.cpp | 12 ++++++++++-- apps/opencs/model/doc/document.hpp | 3 +++ apps/opencs/model/tools/tools.cpp | 2 ++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 8d5580bcf..2cff89389 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2256,7 +2256,7 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM mSavingOperation (*this, mProjectPath, encoding), mSaving (&mSavingOperation), mResDir(resDir), - mRunner (mProjectPath), mIdCompletionManager(mData) + mRunner (mProjectPath), mIdCompletionManager(mData), mDirty (false) { if (mContentFiles.empty()) throw std::runtime_error ("Empty content file sequence"); @@ -2325,7 +2325,7 @@ int CSMDoc::Document::getState() const { int state = 0; - if (!mUndoStack.isClean()) + if (!mUndoStack.isClean() || mDirty) state |= State_Modified; if (mSaving.isRunning()) @@ -2417,6 +2417,9 @@ void CSMDoc::Document::reportMessage (const CSMDoc::Message& message, int type) void CSMDoc::Document::operationDone (int type, bool failed) { + if (type==CSMDoc::State_Saving && !failed) + mDirty = false; + emit stateChanged (getState(), this); } @@ -2493,3 +2496,8 @@ CSMWorld::IdCompletionManager &CSMDoc::Document::getIdCompletionManager() { return mIdCompletionManager; } + +void CSMDoc::Document::flagAsDirty() +{ + mDirty = true; +} diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 3eaa5bb14..0e8ae6d45 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -68,6 +68,7 @@ namespace CSMDoc boost::filesystem::path mResDir; Blacklist mBlacklist; Runner mRunner; + bool mDirty; CSMWorld::IdCompletionManager mIdCompletionManager; @@ -152,6 +153,8 @@ namespace CSMDoc CSMWorld::IdCompletionManager &getIdCompletionManager(); + void flagAsDirty(); + signals: void stateChanged (int state, CSMDoc::Document *document); diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index c4ff6868b..cabd53937 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -207,6 +207,8 @@ void CSMTools::Tools::runMerge (std::auto_ptr target) this, SIGNAL (mergeDone (CSMDoc::Document*))); } + target->flagAsDirty(); + mMergeOperation->setTarget (target); mMerge.start(); From 103073150e87d62582649ea6943fdc510eb5ca59 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 23 Aug 2015 12:58:49 +0200 Subject: [PATCH 309/419] added info tables and pathgrid table to merge operation --- apps/opencs/model/tools/mergeoperation.cpp | 5 ++++- apps/opencs/model/tools/mergestages.hpp | 16 +++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 4a85eca79..d010e343b 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -31,8 +31,11 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSoundGens)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getMagicEffects)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getStartScripts)); + appendStage (new MergeIdCollectionStage > (mState, &CSMWorld::Data::getPathgrids)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getTopicInfos)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getJournalInfos)); - /// \todo TopicInfo, JournalInfo, Referencables, References, Land, LandTextures, Pathgrids + /// \todo Referencables, References, Land, LandTextures } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 749fab18c..f9d29420b 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -27,11 +27,9 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - template + template > class MergeIdCollectionStage : public CSMDoc::Stage { - typedef typename CSMWorld::IdCollection Collection; - MergeState& mState; Collection& (CSMWorld::Data::*mAccessor)(); @@ -46,19 +44,19 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - template - MergeIdCollectionStage::MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()) + template + MergeIdCollectionStage::MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()) : mState (state), mAccessor (accessor) {} - template - int MergeIdCollectionStage::setup() + template + int MergeIdCollectionStage::setup() { return 1; } - template - void MergeIdCollectionStage::perform (int stage, CSMDoc::Messages& messages) + template + void MergeIdCollectionStage::perform (int stage, CSMDoc::Messages& messages) { const Collection& source = (mState.mSource.getData().*mAccessor)(); Collection& target = (mState.mTarget->getData().*mAccessor)(); From 16dda281cee3fb1bab7276cc21448b754d5db3c5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 23 Aug 2015 13:04:42 +0200 Subject: [PATCH 310/419] made merge operation more fluent --- apps/opencs/model/tools/mergestages.hpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index f9d29420b..af7f06d60 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -1,6 +1,8 @@ #ifndef CSM_TOOLS_MERGESTAGES_H #define CSM_TOOLS_MERGESTAGES_H +#include + #include #include "../doc/stage.hpp" @@ -33,6 +35,8 @@ namespace CSMTools MergeState& mState; Collection& (CSMWorld::Data::*mAccessor)(); + static const int stepSize = 1000; + public: MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()); @@ -52,7 +56,16 @@ namespace CSMTools template int MergeIdCollectionStage::setup() { - return 1; + const Collection& source = (mState.mSource.getData().*mAccessor)(); + + int size = source.getSize(); + + int steps = size / stepSize; + + if (size % stepSize) + ++steps; + + return steps; } template @@ -61,9 +74,10 @@ namespace CSMTools const Collection& source = (mState.mSource.getData().*mAccessor)(); Collection& target = (mState.mTarget->getData().*mAccessor)(); - int size = source.getSize(); + int begin = stage * stepSize; + int end = std::min ((stage+1) * stepSize, source.getSize()); - for (int i=0; i& record = source.getRecord (i); From b509a18065959b0e65bceb737655d5968d9fa3da Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 23 Aug 2015 14:05:46 +0200 Subject: [PATCH 311/419] Remove code setting PcRace (Fixes #2886) This is already handled by the RaceCheck script. --- apps/openmw/mwworld/worldimp.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 40a929cda..7d4ab0c95 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -216,7 +216,6 @@ namespace MWWorld { // set new game mark mGlobalVariables["chargenstate"].setInteger (1); - mGlobalVariables["pcrace"].setInteger (3); } else mGlobalVariables["chargenstate"].setInteger (-1); @@ -1493,19 +1492,6 @@ namespace MWWorld if (Misc::StringUtils::ciEqual(record.mId, "player")) { - std::vector ids; - getStore().get().listIdentifier(ids); - - std::sort(ids.begin(), ids.end()); - - unsigned int i=0; - - for (; igetPlayer().get()->mBase; From bb54bbd2736d8440e639066bc459ec56173786de Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 24 Aug 2015 19:54:02 +1200 Subject: [PATCH 312/419] Pulled duplicated functions into common base class --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwclass/creature.cpp | 70 ------------------------- apps/openmw/mwclass/creature.hpp | 22 +------- apps/openmw/mwclass/mobile.cpp | 87 ++++++++++++++++++++++++++++++++ apps/openmw/mwclass/mobile.hpp | 47 +++++++++++++++++ apps/openmw/mwclass/npc.cpp | 66 +----------------------- apps/openmw/mwclass/npc.hpp | 18 +------ 7 files changed, 140 insertions(+), 172 deletions(-) create mode 100644 apps/openmw/mwclass/mobile.cpp create mode 100644 apps/openmw/mwclass/mobile.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index a0f9e8e13..9054e53c9 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -74,7 +74,7 @@ add_openmw_dir (mwphysics add_openmw_dir (mwclass classes activator creature npc weapon armor potion apparatus book clothing container door - ingredient creaturelevlist itemlevlist light lockpick misc probe repair static + ingredient creaturelevlist itemlevlist light lockpick misc probe repair static mobile ) add_openmw_dir (mwmechanics diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index ff09282c1..e14d9f8ba 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -156,11 +156,6 @@ namespace MWClass return ref->mBase->mId; } - void Creature::adjustPosition(const MWWorld::Ptr& ptr, bool force) const - { - MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); - } - void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -169,17 +164,6 @@ namespace MWClass objects.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); } - void Creature::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const - { - if(!model.empty()) - { - physics.addActor(ptr, model); - if (getCreatureStats(ptr).isDead()) - MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); - } - MWBase::Environment::get().getMechanicsManager()->add(ptr); - } - std::string Creature::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = @@ -408,30 +392,6 @@ namespace MWClass } } - void Creature::block(const MWWorld::Ptr &ptr) const - { - MWWorld::InventoryStore& inv = getInventoryStore(ptr); - MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); - if (shield == inv.end()) - return; - - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - switch(shield->getClass().getEquipmentSkill(*shield)) - { - case ESM::Skill::LightArmor: - sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::MediumArmor: - sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::HeavyArmor: - sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f); - break; - default: - return; - } - } - boost::shared_ptr Creature::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { @@ -499,11 +459,6 @@ namespace MWClass registerClass (typeid (ESM::Creature).name(), instance); } - bool Creature::hasToolTip (const MWWorld::Ptr& ptr) const - { - return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat() || getCreatureStats(ptr).isDead(); - } - float Creature::getSpeed(const MWWorld::Ptr &ptr) const { MWMechanics::CreatureStats& stats = getCreatureStats(ptr); @@ -562,16 +517,6 @@ namespace MWClass return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; } - osg::Vec3f Creature::getRotationVector (const MWWorld::Ptr& ptr) const - { - MWMechanics::Movement &movement = getMovementSettings(ptr); - osg::Vec3f vec(movement.mRotation[0], movement.mRotation[1], movement.mRotation[2]); - 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 *ref = @@ -600,21 +545,6 @@ namespace MWClass return static_cast(stats.getAttribute(0).getModified() * 5); } - float Creature::getEncumbrance (const MWWorld::Ptr& ptr) const - { - float weight = getContainerStore (ptr).getWeight(); - - const MWMechanics::MagicEffects& effects = getCreatureStats(ptr).getMagicEffects(); - weight -= effects.get(ESM::MagicEffect::Feather).getMagnitude(); - weight += effects.get(ESM::MagicEffect::Burden).getMagnitude(); - - if (weight<0) - weight = 0; - - return weight; - } - - int Creature::getServices(const MWWorld::Ptr &actor) const { MWWorld::LiveCellRef* ref = actor.get(); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index b2a333beb..3881c1d40 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWCLASS_CREATURE_H #define GAME_MWCLASS_CREATURE_H -#include "../mwworld/class.hpp" +#include "mobile.hpp" namespace ESM { @@ -10,7 +10,7 @@ namespace ESM namespace MWClass { - class Creature : public MWWorld::Class + class Creature : public Mobile { void ensureCustomData (const MWWorld::Ptr& ptr) const; @@ -47,19 +47,10 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - - virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; - ///< Adjust position to stand on ground. Must be called post model load - /// @param force do this even if the ptr is flying - virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. @@ -68,8 +59,6 @@ namespace MWClass virtual void hit(const MWWorld::Ptr& ptr, float attackStrength, int type) const; - virtual void block(const MWWorld::Ptr &ptr) const; - virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, @@ -92,10 +81,6 @@ namespace MWClass ///< Return total weight that fits into the object. Throws an exception, if the object can't /// hold other objects. - virtual float getEncumbrance (const MWWorld::Ptr& ptr) const; - ///< Returns total weight of objects inside this object (including modifications from magic - /// effects). Throws an exception, if the object can't hold other objects. - virtual float getArmorRating (const MWWorld::Ptr& ptr) const; ///< @return combined armor rating of this actor @@ -111,9 +96,6 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - virtual osg::Vec3f getRotationVector (const MWWorld::Ptr& ptr) const; - ///< Return desired rotations, as euler angles. - float getSpeed (const MWWorld::Ptr& ptr) const; static void registerSelf(); diff --git a/apps/openmw/mwclass/mobile.cpp b/apps/openmw/mwclass/mobile.cpp new file mode 100644 index 000000000..9cd5510e2 --- /dev/null +++ b/apps/openmw/mwclass/mobile.cpp @@ -0,0 +1,87 @@ +#include "mobile.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/soundmanager.hpp" + +#include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/movement.hpp" +#include "../mwmechanics/magiceffects.hpp" + +#include "../mwphysics/physicssystem.hpp" + +#include "../mwworld/inventorystore.hpp" + +namespace MWClass +{ + Mobile::Mobile() {} + + Mobile::~Mobile() {} + + void Mobile::adjustPosition(const MWWorld::Ptr& ptr, bool force) const + { + MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); + } + + void Mobile::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const + { + if (!model.empty()) + { + physics.addActor(ptr, model); + if (getCreatureStats(ptr).isDead()) + MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); + } + MWBase::Environment::get().getMechanicsManager()->add(ptr); + } + + void Mobile::block(const MWWorld::Ptr &ptr) const + { + MWWorld::InventoryStore& inv = getInventoryStore(ptr); + MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); + if (shield == inv.end()) + return; + + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + switch (shield->getClass().getEquipmentSkill(*shield)) + { + case ESM::Skill::LightArmor: + sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f); + break; + case ESM::Skill::MediumArmor: + sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f); + break; + case ESM::Skill::HeavyArmor: + sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f); + break; + default: + return; + } + } + + bool Mobile::hasToolTip(const MWWorld::Ptr& ptr) const + { + return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat() || getCreatureStats(ptr).isDead(); + } + + osg::Vec3f Mobile::getRotationVector(const MWWorld::Ptr& ptr) const + { + MWMechanics::Movement &movement = getMovementSettings(ptr); + osg::Vec3f vec(movement.mRotation[0], movement.mRotation[1], movement.mRotation[2]); + movement.mRotation[0] = 0.0f; + movement.mRotation[1] = 0.0f; + movement.mRotation[2] = 0.0f; + return vec; + } + + float Mobile::getEncumbrance(const MWWorld::Ptr& ptr) const + { + float weight = getContainerStore(ptr).getWeight(); + const MWMechanics::MagicEffects& effects = getCreatureStats(ptr).getMagicEffects(); + weight -= effects.get(MWMechanics::EffectKey(ESM::MagicEffect::Feather)).getMagnitude(); + weight += effects.get(MWMechanics::EffectKey(ESM::MagicEffect::Burden)).getMagnitude(); + return (weight < 0) ? 0.0f : weight; + } +} diff --git a/apps/openmw/mwclass/mobile.hpp b/apps/openmw/mwclass/mobile.hpp new file mode 100644 index 000000000..5b1eeae9d --- /dev/null +++ b/apps/openmw/mwclass/mobile.hpp @@ -0,0 +1,47 @@ +#ifndef GAME_MWCLASS_MOBILE_H +#define GAME_MWCLASS_MOBILE_H + +#include "../mwworld/class.hpp" + +namespace ESM +{ + struct GameSetting; +} + +namespace MWClass +{ + /// \brief Class holding functionality common to Creature and NPC + class Mobile : public MWWorld::Class + { + protected: + + Mobile(); + + public: + ~Mobile(); + + virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; + ///< Adjust position to stand on ground. Must be called post model load + /// @param force do this even if the ptr is flying + + virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; + + virtual void block(const MWWorld::Ptr &ptr) const; + + virtual bool hasToolTip(const MWWorld::Ptr& ptr) const; + ///< @return true if this object has a tooltip when focused (default implementation: false) + + virtual osg::Vec3f getRotationVector(const MWWorld::Ptr& ptr) const; + ///< Return desired rotations, as euler angles. + + virtual float getEncumbrance(const MWWorld::Ptr& ptr) const; + ///< Returns total weight of objects inside this object (including modifications from magic + /// effects). Throws an exception, if the object can't hold other objects. + + // not implemented + Mobile(const Mobile&); + Mobile& operator= (const Mobile&); + }; +} + +#endif diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 5f166b3e3..bd1579d9e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -402,24 +402,11 @@ namespace MWClass return ref->mBase->mId; } - void Npc::adjustPosition(const MWWorld::Ptr& ptr, bool force) const - { - MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); - } - void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { renderingInterface.getObjects().insertNPC(ptr); } - void Npc::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const - { - physics.addActor(ptr, model); - MWBase::Environment::get().getMechanicsManager()->add(ptr); - if (getCreatureStats(ptr).isDead()) - MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); - } - bool Npc::isPersistent(const MWWorld::Ptr &actor) const { MWWorld::LiveCellRef* ref = actor.get(); @@ -756,30 +743,6 @@ namespace MWClass } } - void Npc::block(const MWWorld::Ptr &ptr) const - { - MWWorld::InventoryStore& inv = getInventoryStore(ptr); - MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); - if (shield == inv.end()) - return; - - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - switch(shield->getClass().getEquipmentSkill(*shield)) - { - case ESM::Skill::LightArmor: - sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::MediumArmor: - sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::HeavyArmor: - sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f); - break; - default: - return; - } - } - boost::shared_ptr Npc::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { @@ -937,16 +900,6 @@ namespace MWClass return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; } - osg::Vec3f Npc::getRotationVector (const MWWorld::Ptr& ptr) const - { - MWMechanics::Movement &movement = getMovementSettings(ptr); - osg::Vec3f vec(movement.mRotation[0], movement.mRotation[1], movement.mRotation[2]); - movement.mRotation[0] = 0.0f; - movement.mRotation[1] = 0.0f; - movement.mRotation[2] = 0.0f; - return vec; - } - bool Npc::isEssential (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = @@ -961,11 +914,6 @@ namespace MWClass registerClass (typeid (ESM::NPC).name(), instance); } - bool Npc::hasToolTip (const MWWorld::Ptr& ptr) const - { - return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat() || getCreatureStats(ptr).isDead(); - } - MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -996,21 +944,9 @@ namespace MWClass float Npc::getEncumbrance (const MWWorld::Ptr& ptr) const { - const MWMechanics::NpcStats &stats = getNpcStats(ptr); - // According to UESP, inventory weight is ignored in werewolf form. Does that include // feather and burden effects? - float weight = 0.0f; - if(!stats.isWerewolf()) - { - weight = getContainerStore(ptr).getWeight(); - weight -= stats.getMagicEffects().get(ESM::MagicEffect::Feather).getMagnitude(); - weight += stats.getMagicEffects().get(ESM::MagicEffect::Burden).getMagnitude(); - if(weight < 0.0f) - weight = 0.0f; - } - - return weight; + return getNpcStats(ptr).isWerewolf() ? 0.0f : Mobile::getEncumbrance(ptr); } bool Npc::apply (const MWWorld::Ptr& ptr, const std::string& id, diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index b12b7b13f..16dd4f8bd 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWCLASS_NPC_H #define GAME_MWCLASS_NPC_H -#include "../mwworld/class.hpp" +#include "mobile.hpp" namespace ESM { @@ -10,7 +10,7 @@ namespace ESM namespace MWClass { - class Npc : public MWWorld::Class + class Npc : public Mobile { void ensureCustomData (const MWWorld::Ptr& ptr) const; @@ -51,12 +51,6 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; - - virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; - ///< Adjust position to stand on ground. Must be called post model load - /// @param force do this even if the ptr is flying - virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. @@ -70,9 +64,6 @@ namespace MWClass virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; ///< Return container store - virtual bool hasToolTip (const MWWorld::Ptr& ptr) const; - ///< @return true if this object has a tooltip when focused (default implementation: false) - virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. @@ -85,8 +76,6 @@ namespace MWClass virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const; - virtual void block(const MWWorld::Ptr &ptr) const; - virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; ///< Generate action for activation @@ -103,9 +92,6 @@ namespace MWClass virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. - virtual osg::Vec3f getRotationVector (const MWWorld::Ptr& ptr) const; - ///< Return desired rotations, as euler angles. - virtual float getCapacity (const MWWorld::Ptr& ptr) const; ///< Return total weight that fits into the object. Throws an exception, if the object can't /// hold other objects. From cd5bef958f5fc163fd6609661a4e251e1ffb315c Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Mon, 17 Aug 2015 20:32:23 -0500 Subject: [PATCH 313/419] Remove dead code from alchemywindow. Also align some braces. --- apps/openmw/mwgui/alchemywindow.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 60bd70c04..d12c22e06 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -1,7 +1,5 @@ #include "alchemywindow.hpp" -#include - #include #include "../mwbase/environment.hpp" @@ -67,9 +65,6 @@ namespace MWGui void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) { - std::string name = mNameEdit->getCaption(); - boost::algorithm::trim(name); - MWMechanics::Alchemy::Result result = mAlchemy->create (mNameEdit->getCaption ()); if (result == MWMechanics::Alchemy::Result_NoName) @@ -118,7 +113,7 @@ namespace MWGui MWWorld::Ptr ingred = *mIngredients[i]->getUserData(); if (ingred.getRefData().getCount() == 0) removeIngredient(mIngredients[i]); - } + } update(); } @@ -136,9 +131,6 @@ namespace MWGui mNameEdit->setCaption(""); int index = 0; - - mAlchemy->setAlchemist (MWMechanics::getPlayer()); - for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy->beginTools()); iter!=mAlchemy->endTools() && index (mApparatus.size()); ++iter, ++index) { From 541d7fb4fb9db72ed30bdbebd9d59aa1b810886b Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 25 Aug 2015 18:19:16 +1200 Subject: [PATCH 314/419] Fixed assorted issues * destructor is virtual * renamed class to Actor * corrected indentation of case statement --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwclass/{mobile.cpp => actor.cpp} | 40 +++++++++---------- apps/openmw/mwclass/{mobile.hpp => actor.hpp} | 10 ++--- apps/openmw/mwclass/creature.hpp | 4 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwclass/npc.hpp | 4 +- 6 files changed, 31 insertions(+), 31 deletions(-) rename apps/openmw/mwclass/{mobile.cpp => actor.cpp} (68%) rename apps/openmw/mwclass/{mobile.hpp => actor.hpp} (89%) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 9054e53c9..2dd16a4e6 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -74,7 +74,7 @@ add_openmw_dir (mwphysics add_openmw_dir (mwclass classes activator creature npc weapon armor potion apparatus book clothing container door - ingredient creaturelevlist itemlevlist light lockpick misc probe repair static mobile + ingredient creaturelevlist itemlevlist light lockpick misc probe repair static actor ) add_openmw_dir (mwmechanics diff --git a/apps/openmw/mwclass/mobile.cpp b/apps/openmw/mwclass/actor.cpp similarity index 68% rename from apps/openmw/mwclass/mobile.cpp rename to apps/openmw/mwclass/actor.cpp index 9cd5510e2..d58047d06 100644 --- a/apps/openmw/mwclass/mobile.cpp +++ b/apps/openmw/mwclass/actor.cpp @@ -1,4 +1,4 @@ -#include "mobile.hpp" +#include "actor.hpp" #include @@ -17,16 +17,16 @@ namespace MWClass { - Mobile::Mobile() {} + Actor::Actor() {} - Mobile::~Mobile() {} + Actor::~Actor() {} - void Mobile::adjustPosition(const MWWorld::Ptr& ptr, bool force) const + void Actor::adjustPosition(const MWWorld::Ptr& ptr, bool force) const { MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); } - void Mobile::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const + void Actor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const { if (!model.empty()) { @@ -37,7 +37,7 @@ namespace MWClass MWBase::Environment::get().getMechanicsManager()->add(ptr); } - void Mobile::block(const MWWorld::Ptr &ptr) const + void Actor::block(const MWWorld::Ptr &ptr) const { MWWorld::InventoryStore& inv = getInventoryStore(ptr); MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); @@ -47,26 +47,26 @@ namespace MWClass MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); switch (shield->getClass().getEquipmentSkill(*shield)) { - case ESM::Skill::LightArmor: - sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::MediumArmor: - sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f); - break; - case ESM::Skill::HeavyArmor: - sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f); - break; - default: - return; + case ESM::Skill::LightArmor: + sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f); + break; + case ESM::Skill::MediumArmor: + sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f); + break; + case ESM::Skill::HeavyArmor: + sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f); + break; + default: + return; } } - bool Mobile::hasToolTip(const MWWorld::Ptr& ptr) const + bool Actor::hasToolTip(const MWWorld::Ptr& ptr) const { return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat() || getCreatureStats(ptr).isDead(); } - osg::Vec3f Mobile::getRotationVector(const MWWorld::Ptr& ptr) const + osg::Vec3f Actor::getRotationVector(const MWWorld::Ptr& ptr) const { MWMechanics::Movement &movement = getMovementSettings(ptr); osg::Vec3f vec(movement.mRotation[0], movement.mRotation[1], movement.mRotation[2]); @@ -76,7 +76,7 @@ namespace MWClass return vec; } - float Mobile::getEncumbrance(const MWWorld::Ptr& ptr) const + float Actor::getEncumbrance(const MWWorld::Ptr& ptr) const { float weight = getContainerStore(ptr).getWeight(); const MWMechanics::MagicEffects& effects = getCreatureStats(ptr).getMagicEffects(); diff --git a/apps/openmw/mwclass/mobile.hpp b/apps/openmw/mwclass/actor.hpp similarity index 89% rename from apps/openmw/mwclass/mobile.hpp rename to apps/openmw/mwclass/actor.hpp index 5b1eeae9d..3f795dff9 100644 --- a/apps/openmw/mwclass/mobile.hpp +++ b/apps/openmw/mwclass/actor.hpp @@ -11,14 +11,14 @@ namespace ESM namespace MWClass { /// \brief Class holding functionality common to Creature and NPC - class Mobile : public MWWorld::Class + class Actor : public MWWorld::Class { protected: - Mobile(); + Actor(); public: - ~Mobile(); + virtual ~Actor(); virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; ///< Adjust position to stand on ground. Must be called post model load @@ -39,8 +39,8 @@ namespace MWClass /// effects). Throws an exception, if the object can't hold other objects. // not implemented - Mobile(const Mobile&); - Mobile& operator= (const Mobile&); + Actor(const Actor&); + Actor& operator= (const Actor&); }; } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 3881c1d40..c4ea09255 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWCLASS_CREATURE_H #define GAME_MWCLASS_CREATURE_H -#include "mobile.hpp" +#include "actor.hpp" namespace ESM { @@ -10,7 +10,7 @@ namespace ESM namespace MWClass { - class Creature : public Mobile + class Creature : public Actor { void ensureCustomData (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index bd1579d9e..9fa2cc603 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -946,7 +946,7 @@ namespace MWClass { // According to UESP, inventory weight is ignored in werewolf form. Does that include // feather and burden effects? - return getNpcStats(ptr).isWerewolf() ? 0.0f : Mobile::getEncumbrance(ptr); + return getNpcStats(ptr).isWerewolf() ? 0.0f : Actor::getEncumbrance(ptr); } bool Npc::apply (const MWWorld::Ptr& ptr, const std::string& id, diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 16dd4f8bd..d919131db 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWCLASS_NPC_H #define GAME_MWCLASS_NPC_H -#include "mobile.hpp" +#include "actor.hpp" namespace ESM { @@ -10,7 +10,7 @@ namespace ESM namespace MWClass { - class Npc : public Mobile + class Npc : public Actor { void ensureCustomData (const MWWorld::Ptr& ptr) const; From 40753aa9a3759e247b1fc907f5ef61af2656d533 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 25 Aug 2015 08:43:03 +0200 Subject: [PATCH 315/419] simplifying merge stage --- apps/opencs/model/tools/mergestages.hpp | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index af7f06d60..c0ed16787 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -35,8 +35,6 @@ namespace CSMTools MergeState& mState; Collection& (CSMWorld::Data::*mAccessor)(); - static const int stepSize = 1000; - public: MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)()); @@ -56,16 +54,7 @@ namespace CSMTools template int MergeIdCollectionStage::setup() { - const Collection& source = (mState.mSource.getData().*mAccessor)(); - - int size = source.getSize(); - - int steps = size / stepSize; - - if (size % stepSize) - ++steps; - - return steps; + return (mState.mSource.getData().*mAccessor)().getSize(); } template @@ -74,16 +63,10 @@ namespace CSMTools const Collection& source = (mState.mSource.getData().*mAccessor)(); Collection& target = (mState.mTarget->getData().*mAccessor)(); - int begin = stage * stepSize; - int end = std::min ((stage+1) * stepSize, source.getSize()); + const CSMWorld::Record& record = source.getRecord (stage); - for (int i=begin; i& record = source.getRecord (i); - - if (!record.isDeleted()) - target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_BaseOnly, &record.get())); - } + if (!record.isDeleted()) + target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_BaseOnly, &record.get())); } } From 9cf793c0b519143fd7d3ac3cfb7beb82f65b72f3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 25 Aug 2015 11:39:43 +0200 Subject: [PATCH 316/419] silenced a warning --- apps/opencs/model/doc/document.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 2cff89389..0e2d4e7d1 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2256,7 +2256,7 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM mSavingOperation (*this, mProjectPath, encoding), mSaving (&mSavingOperation), mResDir(resDir), - mRunner (mProjectPath), mIdCompletionManager(mData), mDirty (false) + mRunner (mProjectPath), mDirty (false), mIdCompletionManager(mData) { if (mContentFiles.empty()) throw std::runtime_error ("Empty content file sequence"); From f95950e8d815997da34eb9939b81cd27afb62dbb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 25 Aug 2015 11:54:16 +0200 Subject: [PATCH 317/419] merge referenceables table --- apps/opencs/model/tools/mergeoperation.cpp | 3 ++- apps/opencs/model/tools/mergestages.cpp | 14 ++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 16 ++++++++++++++++ apps/opencs/model/world/refidcollection.cpp | 5 +++++ apps/opencs/model/world/refidcollection.hpp | 1 + apps/opencs/model/world/refiddata.cpp | 11 +++++++++++ apps/opencs/model/world/refiddata.hpp | 6 ++---- 7 files changed, 51 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index d010e343b..0f128e86e 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -34,8 +34,9 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeIdCollectionStage > (mState, &CSMWorld::Data::getPathgrids)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getTopicInfos)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getJournalInfos)); + appendStage (new MergeRefIdsStage (mState)); - /// \todo Referencables, References, Land, LandTextures + /// \todo References, Land, LandTextures } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 776808b26..d8bd93824 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -39,3 +39,17 @@ void CSMTools::FinishMergedDocumentStage::perform (int stage, CSMDoc::Messages& mState.mCompleted = true; } + + +CSMTools::MergeRefIdsStage::MergeRefIdsStage (MergeState& state) : mState (state) {} + +int CSMTools::MergeRefIdsStage::setup() +{ + return mState.mSource.getData().getReferenceables().getSize(); +} + +void CSMTools::MergeRefIdsStage::perform (int stage, CSMDoc::Messages& messages) +{ + mState.mSource.getData().getReferenceables().copyTo ( + stage, mState.mTarget->getData().getReferenceables()); +} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index c0ed16787..308ebe1c3 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -68,6 +68,22 @@ namespace CSMTools if (!record.isDeleted()) target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_BaseOnly, &record.get())); } + + + class MergeRefIdsStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + MergeRefIdsStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; } #endif diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 5495926b4..c50f8c1f1 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -914,3 +914,8 @@ const CSMWorld::NestedRefIdAdapterBase& CSMWorld::RefIdCollection::getNestedAdap } throw std::runtime_error("No such column in the nestedadapters"); } + +void CSMWorld::RefIdCollection::copyTo (int index, RefIdCollection& target) const +{ + mData.copyTo (index, target.mData); +} diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index 4d511d12d..de5a709c6 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -138,6 +138,7 @@ namespace CSMWorld void save (int index, ESM::ESMWriter& writer) const; const RefIdData& getDataSet() const; //I can't figure out a better name for this one :( + void copyTo (int index, RefIdCollection& target) const; }; } diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index 7f5c25f36..70d968efb 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -358,3 +358,14 @@ void CSMWorld::RefIdData::insertRecord(CSMWorld::RecordBase& record, CSMWorld::U mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id), LocalIndex (iter->second->getSize()-1, type))); } + +void CSMWorld::RefIdData::copyTo (int index, RefIdData& target) const +{ + LocalIndex localIndex = globalToLocalIndex (index); + + RefIdDataContainerBase *source = mRecordContainers.find (localIndex.second)->second; + + std::string id = source->getId (localIndex.first); + + target.insertRecord (source->getRecord (localIndex.first), localIndex.second, id); +} diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 85d16a6eb..4507f6028 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -252,11 +252,9 @@ namespace CSMWorld const RefIdDataContainer& getProbes() const; const RefIdDataContainer& getRepairs() const; const RefIdDataContainer& getStatics() const; + + void copyTo (int index, RefIdData& target) const; }; } #endif - - - - From 845cafd61c12142a353119a6304845370037d7a5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 25 Aug 2015 12:40:40 +0200 Subject: [PATCH 318/419] fixed record state issues after merge --- apps/opencs/model/tools/mergestages.hpp | 2 +- apps/opencs/model/world/refiddata.cpp | 7 +++++-- apps/opencs/model/world/refiddata.hpp | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 308ebe1c3..5c2243d43 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -66,7 +66,7 @@ namespace CSMTools const CSMWorld::Record& record = source.getRecord (stage); if (!record.isDeleted()) - target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_BaseOnly, &record.get())); + target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_ModifiedOnly, 0, &record.get())); } diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index 70d968efb..14f580d39 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -2,6 +2,7 @@ #include "refiddata.hpp" #include +#include #include @@ -345,7 +346,7 @@ const CSMWorld::RefIdDataContainer< ESM::Static >& CSMWorld::RefIdData::getStati return mStatics; } -void CSMWorld::RefIdData::insertRecord(CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id) +void CSMWorld::RefIdData::insertRecord (CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id) { std::map::iterator iter = mRecordContainers.find (type); @@ -367,5 +368,7 @@ void CSMWorld::RefIdData::copyTo (int index, RefIdData& target) const std::string id = source->getId (localIndex.first); - target.insertRecord (source->getRecord (localIndex.first), localIndex.second, id); + std::auto_ptr newRecord (source->getRecord (localIndex.first).modifiedCopy()); + + target.insertRecord (*newRecord, localIndex.second, id); } diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 4507f6028..8909ae4fb 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -210,7 +210,8 @@ namespace CSMWorld void erase (int index, int count); - void insertRecord(CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id); + void insertRecord (CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, + const std::string& id); const RecordBase& getRecord (const LocalIndex& index) const; From a97a632aa76c3b7499ae170b689676d2f32b8550 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 26 Aug 2015 17:21:24 +0200 Subject: [PATCH 319/419] merge references tables --- apps/opencs/model/tools/mergeoperation.cpp | 3 +- apps/opencs/model/tools/mergestages.cpp | 34 ++++++++++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 18 +++++++++++- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 0f128e86e..f9a89aaa1 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -35,8 +35,9 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getTopicInfos)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getJournalInfos)); appendStage (new MergeRefIdsStage (mState)); + appendStage (new MergeReferencesStage (mState)); - /// \todo References, Land, LandTextures + /// \todo Land, LandTextures } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index d8bd93824..80f16ec14 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -1,6 +1,8 @@ #include "mergestages.hpp" +#include + #include "mergestate.hpp" #include "../doc/document.hpp" @@ -53,3 +55,35 @@ void CSMTools::MergeRefIdsStage::perform (int stage, CSMDoc::Messages& messages) mState.mSource.getData().getReferenceables().copyTo ( stage, mState.mTarget->getData().getReferenceables()); } + + +CSMTools::MergeReferencesStage::MergeReferencesStage (MergeState& state) +: mState (state) +{} + +int CSMTools::MergeReferencesStage::setup() +{ + mIndex.clear(); + return mState.mSource.getData().getReferences().getSize(); +} + +void CSMTools::MergeReferencesStage::perform (int stage, CSMDoc::Messages& messages) +{ + const CSMWorld::Record& record = + mState.mSource.getData().getReferences().getRecord (stage); + + if (!record.isDeleted()) + { + CSMWorld::CellRef ref = record.get(); + + ref.mOriginalCell = ref.mCell; + + ref.mRefNum.mIndex = mIndex[Misc::StringUtils::lowerCase (ref.mCell)]++; + ref.mRefNum.mContentFile = 0; + + CSMWorld::Record newRecord ( + CSMWorld::RecordBase::State_ModifiedOnly, 0, &ref); + + mState.mTarget->getData().getReferences().appendRecord (newRecord); + } +} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 5c2243d43..e1cc17a3e 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -2,6 +2,7 @@ #define CSM_TOOLS_MERGESTAGES_H #include +#include #include @@ -69,7 +70,6 @@ namespace CSMTools target.appendRecord (CSMWorld::Record (CSMWorld::RecordBase::State_ModifiedOnly, 0, &record.get())); } - class MergeRefIdsStage : public CSMDoc::Stage { MergeState& mState; @@ -84,6 +84,22 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. }; + + class MergeReferencesStage : public CSMDoc::Stage + { + MergeState& mState; + std::map mIndex; + + public: + + MergeReferencesStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; } #endif From 54fa5273dc2d95f79368a82f815519b1c6d53fde Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 26 Aug 2015 22:59:21 -0500 Subject: [PATCH 320/419] Refactor weather transitions to act more like MW Fixed several issues: * Waiting/jail time/training all now properly skip remaining transitions * ChangeWeather no longer permanently sets the region's weather * ChangeWeather being called during a transition now correctly queues up another transition * Corrected transition delta and factor calculations * ModRegion settings are now saved --- apps/essimporter/converter.hpp | 64 +- apps/openmw/engine.cpp | 3 +- apps/openmw/mwbase/world.hpp | 3 + apps/openmw/mwworld/weather.cpp | 1152 +++++++++++++++++------------- apps/openmw/mwworld/weather.hpp | 151 ++-- apps/openmw/mwworld/worldimp.cpp | 39 +- apps/openmw/mwworld/worldimp.hpp | 3 + components/esm/weatherstate.cpp | 131 ++-- components/esm/weatherstate.hpp | 63 +- 9 files changed, 890 insertions(+), 719 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index fb8fb8c9f..4bad5e23b 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -507,60 +507,40 @@ class ConvertGAME : public Converter public: ConvertGAME() : mHasGame(false) {} - std::string toString(int weatherId) - { - switch (weatherId) - { - case 0: - return "clear"; - case 1: - return "cloudy"; - case 2: - return "foggy"; - case 3: - return "overcast"; - case 4: - return "rain"; - case 5: - return "thunderstorm"; - case 6: - return "ashstorm"; - case 7: - return "blight"; - case 8: - return "snow"; - case 9: - return "blizzard"; - case -1: - return ""; - default: - { - std::stringstream error; - error << "unknown weather id: " << weatherId; - throw std::runtime_error(error.str()); - } - } - } - virtual void read(ESM::ESMReader &esm) { mGame.load(esm); mHasGame = true; } + int validateWeatherID(int weatherID) + { + if(weatherID >= -1 && weatherID < 10) + { + return weatherID; + } + else + { + std::stringstream error; + error << "Invalid weather ID:" << weatherID << std::endl; + throw std::runtime_error(error.str()); + } + } + virtual void write(ESM::ESMWriter &esm) { if (!mHasGame) return; esm.startRecord(ESM::REC_WTHR); ESM::WeatherState weather; - weather.mCurrentWeather = toString(mGame.mGMDT.mCurrentWeather); - weather.mNextWeather = toString(mGame.mGMDT.mNextWeather); - weather.mRemainingTransitionTime = mGame.mGMDT.mWeatherTransition/100.f*(0.015f*24*3600); - weather.mHour = mContext->mHour; - weather.mWindSpeed = 0.f; - weather.mTimePassed = 0.0; - weather.mFirstUpdate = false; + weather.mTimePassed = 0.0f; + weather.mFastForward = false; + weather.mWeatherUpdateTime = mGame.mGMDT.mTimeOfNextTransition - mContext->mHour; + weather.mTransitionFactor = 1 - (mGame.mGMDT.mWeatherTransition / 100.0f); + weather.mCurrentWeather = validateWeatherID(mGame.mGMDT.mCurrentWeather); + weather.mNextWeather = validateWeatherID(mGame.mGMDT.mNextWeather); + weather.mQueuedWeather = -1; + // TODO: Determine how ModRegion modifiers are saved in Morrowind. weather.save(esm); esm.endRecord(ESM::REC_WTHR); } diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index e183107ec..6c95700b3 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -128,8 +128,7 @@ void OMW::Engine::frame(float frametime) } if (!guiActive) - mEnvironment.getWorld()->advanceTime( - frametime*mEnvironment.getWorld()->getTimeScaleFactor()/3600); + mEnvironment.getWorld()->advanceTimeByFrame(frametime); } osg::Timer_t afterScriptTick = osg::Timer::instance()->tick(); diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index d345cdf7e..636370342 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -188,6 +188,9 @@ namespace MWBase virtual void advanceTime (double hours) = 0; ///< Advance in-game time. + virtual void advanceTimeByFrame (double frametime) = 0; + ///< Advance in-game time by the duration of a frame. + virtual void setHour (double hour) = 0; ///< Set in-game time hour. diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index cc5b726af..8799ae57c 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -28,6 +28,8 @@ using namespace MWWorld; namespace { + static const int invalidWeatherID = -1; + float lerp (float x, float y, float factor) { return x * (1-factor) + y * factor; @@ -87,12 +89,11 @@ Max Raindrops=650 ? */ } -float Weather::transitionSeconds() const +float Weather::transitionDelta() const { - // This formula is reversed from Morrowind by observing different Transition Delta values with Clouds - // Maximum Percent set to 1.0, and watching for when the light from the sun was no longer visible. - static const float deltasPerHour = 0.00835; - return (deltasPerHour / mTransitionDelta) * 60.0f * 60.0f; + // Transition Delta describes how quickly transitioning to the weather in question will take, in Hz. Note that the + // measurement is in real time, not in-game time. + return mTransitionDelta; } float Weather::cloudBlendFactor(float transitionRatio) const @@ -101,6 +102,89 @@ float Weather::cloudBlendFactor(float transitionRatio) const return transitionRatio / mCloudsMaximumPercent; } +RegionWeather::RegionWeather(const ESM::Region& region) + : mWeather(invalidWeatherID) + , mChances() +{ + mChances.reserve(10); + mChances.push_back(region.mData.mClear); + mChances.push_back(region.mData.mCloudy); + mChances.push_back(region.mData.mFoggy); + mChances.push_back(region.mData.mOvercast); + mChances.push_back(region.mData.mRain); + mChances.push_back(region.mData.mThunder); + mChances.push_back(region.mData.mAsh); + mChances.push_back(region.mData.mBlight); + mChances.push_back(region.mData.mA); + mChances.push_back(region.mData.mB); +} + +RegionWeather::RegionWeather(const ESM::RegionWeatherState& state) + : mWeather(state.mWeather) + , mChances(state.mChances) +{ +} + +RegionWeather::operator ESM::RegionWeatherState() const +{ + return ESM::RegionWeatherState { mWeather, mChances }; +} + +void RegionWeather::setChances(const std::vector& chances) +{ + if(mChances.size() < chances.size()) + { + mChances.reserve(chances.size()); + } + + std::vector::const_iterator it = chances.begin(); + for(size_t i = 0; it != chances.end(); ++it, ++i) + { + mChances[i] = *it; + } + + // Regional weather no longer supports the current type, select a new weather pattern. + if((static_cast(mWeather) >= mChances.size()) || (mChances[mWeather] == 0)) + { + chooseNewWeather(); + } +} + +void RegionWeather::setWeather(int weatherID) +{ + mWeather = weatherID; +} + +int RegionWeather::getWeather() +{ + // If the region weather was already set (by ChangeWeather, or by a previous call) then just return that value. + // Note that the region weather will be expired periodically when the weather update timer expires. + if(mWeather == invalidWeatherID) + { + chooseNewWeather(); + } + + return mWeather; +} + +void RegionWeather::chooseNewWeather() +{ + // All probabilities must add to 100 (responsibility of the user). + // If chances A and B has values 30 and 70 then by generating 100 numbers 1..100, 30% will be lesser or equal 30 + // and 70% will be greater than 30 (in theory). + int chance = Misc::Rng::rollDice(100) + 1; // 1..100 + int sum = 0; + int i = 0; + for(; static_cast(i) < mChances.size(); ++i) + { + sum += mChances[i]; + if(chance <= sum) + break; + } + + mWeather = i; +} + MoonModel::MoonModel(const std::string& name, const MWWorld::Fallback& fallback) : mFadeInStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Start")) , mFadeInFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Finish")) @@ -118,22 +202,22 @@ MoonModel::MoonModel(const std::string& name, const MWWorld::Fallback& fallback) mSpeed = std::min(mSpeed, 180.0f / 23.0f); } -MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gameHour) const +MWRender::MoonState MoonModel::calculateState(const TimeStamp& gameTime) const { - float rotationFromHorizon = angle(daysPassed, gameHour); + float rotationFromHorizon = angle(gameTime); MWRender::MoonState state = - { - rotationFromHorizon, - mAxisOffset, // Reverse engineered from Morrowind's scene graph rotation matrices. - static_cast(phase(daysPassed, gameHour)), - shadowBlend(rotationFromHorizon), - earlyMoonShadowAlpha(rotationFromHorizon) * hourlyAlpha(gameHour) - }; + { + rotationFromHorizon, + mAxisOffset, // Reverse engineered from Morrowind's scene graph rotation matrices. + static_cast(phase(gameTime)), + shadowBlend(rotationFromHorizon), + earlyMoonShadowAlpha(rotationFromHorizon) * hourlyAlpha(gameTime.getHour()) + }; return state; } -inline float MoonModel::angle(unsigned int daysPassed, float gameHour) const +inline float MoonModel::angle(const TimeStamp& gameTime) const { // Morrowind's moons start travel on one side of the horizon (let's call it H-rise) and travel 180 degrees to the // opposite horizon (let's call it H-set). Upon reaching H-set, they reset to H-rise until the next moon rise. @@ -142,25 +226,25 @@ inline float MoonModel::angle(unsigned int daysPassed, float gameHour) const // 1. Moon rises and then sets in one day. // 2. Moon sets and doesn't rise in one day (occurs when the moon rise hour is >= 24). // 3. Moon sets and then rises in one day. - float moonRiseHourToday = moonRiseHour(daysPassed); + float moonRiseHourToday = moonRiseHour(gameTime.getDay()); float moonRiseAngleToday = 0; - if(gameHour < moonRiseHourToday) + if(gameTime.getHour() < moonRiseHourToday) { - float moonRiseHourYesterday = moonRiseHour(daysPassed - 1); + float moonRiseHourYesterday = moonRiseHour(gameTime.getDay() - 1); if(moonRiseHourYesterday < 24) { float moonRiseAngleYesterday = rotation(24 - moonRiseHourYesterday); if(moonRiseAngleYesterday < 180) { // The moon rose but did not set yesterday, so accumulate yesterday's angle with how much we've travelled today. - moonRiseAngleToday = rotation(gameHour) + moonRiseAngleYesterday; + moonRiseAngleToday = rotation(gameTime.getHour()) + moonRiseAngleYesterday; } } } else { - moonRiseAngleToday = rotation(gameHour - moonRiseHourToday); + moonRiseAngleToday = rotation(gameTime.getHour() - moonRiseHourToday); } if(moonRiseAngleToday >= 180) @@ -194,17 +278,17 @@ inline float MoonModel::rotation(float hours) const return 15.0f * mSpeed * hours; } -inline unsigned int MoonModel::phase(unsigned int daysPassed, float gameHour) const +inline unsigned int MoonModel::phase(const TimeStamp& gameTime) const { // Morrowind starts with a full moon on 16 Last Seed and then begins to wane 17 Last Seed, working on 3 day phase cycle. // Note: this is an internal helper, and as such we don't want to return MWRender::MoonState::Phase since we can't // forward declare it (C++11 strongly typed enums solve this). // If the moon didn't rise yet today, use yesterday's moon phase. - if(gameHour < moonRiseHour(daysPassed)) - return (daysPassed / 3) % 8; + if(gameTime.getHour() < moonRiseHour(gameTime.getDay())) + return (gameTime.getDay() / 3) % 8; else - return ((daysPassed + 1) / 3) % 8; + return ((gameTime.getDay() + 1) / 3) % 8; } inline float MoonModel::shadowBlend(float angle) const @@ -270,51 +354,68 @@ inline float MoonModel::earlyMoonShadowAlpha(float angle) const return 0.0f; } -WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::Fallback* fallback, MWWorld::ESMStore* store) : - mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mStore(store), - mRendering(rendering), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true), - mRemainingTransitionTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), - mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0), - mMasser("Masser", *fallback), mSecunda("Secunda", *fallback) +WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWorld::Fallback& fallback, MWWorld::ESMStore& store) + : mStore(store) + , mRendering(rendering) + , mSunriseTime(fallback.getFallbackFloat("Weather_Sunrise_Time")) + , mSunsetTime(fallback.getFallbackFloat("Weather_Sunset_Time")) + , mSunriseDuration(fallback.getFallbackFloat("Weather_Sunrise_Duration")) + , mSunsetDuration(fallback.getFallbackFloat("Weather_Sunset_Duration")) + , mNightStart(mSunsetTime + mSunsetDuration) + , mNightEnd(mSunriseTime - 0.5f) + , mDayStart(mSunriseTime + mSunriseDuration) + , mDayEnd(mSunsetTime) + , mHoursBetweenWeatherChanges(fallback.getFallbackFloat("Weather_Hours_Between_Weather_Changes")) + , mRainSpeed(fallback.getFallbackFloat("Weather_Precip_Gravity")) + , mWeatherSettings() + , mMasser("Masser", fallback) + , mSecunda("Secunda", fallback) + , mThunderSoundID0(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0")) + , mThunderSoundID1(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1")) + , mThunderSoundID2(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2")) + , mThunderSoundID3(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3")) + , mThunderFrequency(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency")) + , mThunderThreshold(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold")) + , mWindSpeed(0.f) + , mIsStorm(false) + , mStormDirection(0,1,0) + , mThunderSoundDelay(0.25) + , mThunderFlash(0) + , mThunderChance(0) + , mThunderChanceNeeded(50) + , mCurrentRegion() + , mTimePassed(0) + , mFastForward(false) + , mWeatherUpdateTime(mHoursBetweenWeatherChanges) + , mTransitionFactor(0) + , mCurrentWeather(0) + , mNextWeather(0) + , mQueuedWeather(0) + , mRegions() + , mResult() + , mAmbientSound() + , mPlayingSoundID() { - //Globals - mThunderSoundID0 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); - mThunderSoundID1 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); - mThunderSoundID2 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); - mThunderSoundID3 = fallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); - mSunriseTime = fallback->getFallbackFloat("Weather_Sunrise_Time"); - mSunsetTime = fallback->getFallbackFloat("Weather_Sunset_Time"); - mSunriseDuration = fallback->getFallbackFloat("Weather_Sunrise_Duration"); - mSunsetDuration = fallback->getFallbackFloat("Weather_Sunset_Duration"); - mHoursBetweenWeatherChanges = fallback->getFallbackFloat("Weather_Hours_Between_Weather_Changes"); - mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600; - mThunderFrequency = fallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); - mThunderThreshold = fallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); - mThunderSoundDelay = 0.25; + mWeatherSettings.reserve(10); + addWeather("Clear", fallback); + addWeather("Cloudy", fallback); + addWeather("Foggy", fallback); + addWeather("Overcast", fallback); + addWeather("Rain", fallback, "rain"); + addWeather("Thunderstorm", fallback, "rain heavy"); + addWeather("Ashstorm", fallback, "ashstorm", "meshes\\ashcloud.nif"); + addWeather("Blight", fallback, "blight", "meshes\\blightcloud.nif"); + addWeather("Snow", fallback, "", "meshes\\snow.nif"); + addWeather("Blizzard", fallback, "BM Blizzard", "meshes\\blizzard.nif"); - mRainSpeed = fallback->getFallbackFloat("Weather_Precip_Gravity"); + Store::iterator it = store.get().begin(); + for(; it != store.get().end(); ++it) + { + std::string regionID = Misc::StringUtils::lowerCase(it->mId); + mRegions.insert(std::make_pair(regionID, RegionWeather(*it))); + } - //Some useful values - /* TODO: Use pre-sunrise_time, pre-sunset_time, - * post-sunrise_time, and post-sunset_time to better - * describe sunrise/sunset time. - * These values are fallbacks attached to weather. - */ - mNightStart = mSunsetTime + mSunsetDuration; - mNightEnd = mSunriseTime - 0.5f; - mDayStart = mSunriseTime + mSunriseDuration; - mDayEnd = mSunsetTime; - - addWeather("Clear", *fallback); - addWeather("Cloudy", *fallback); - addWeather("Foggy", *fallback); - addWeather("Overcast", *fallback); - addWeather("Rain", *fallback, "rain"); - addWeather("Thunderstorm", *fallback, "rain heavy"); - addWeather("Ashstorm", *fallback, "ashstorm", "meshes\\ashcloud.nif"); - addWeather("Blight", *fallback, "blight", "meshes\\blightcloud.nif"); - addWeather("Snow", *fallback, "", "meshes\\snow.nif"); - addWeather("Blizzard", *fallback, "BM Blizzard", "meshes\\blizzard.nif"); + forceWeather(0); } WeatherManager::~WeatherManager() @@ -322,250 +423,127 @@ WeatherManager::~WeatherManager() stopSounds(); } -void WeatherManager::setWeather(const std::string& weather, bool instant) +void WeatherManager::changeWeather(const std::string& regionID, const unsigned int weatherID) { - if (weather == mCurrentWeather && mNextWeather == "") - { - mFirstUpdate = false; - return; - } + // In Morrowind, this seems to have the following behavior, when applied to the current region: + // - When there is no transition in progress, start transitioning to the new weather. + // - If there is a transition in progress, queue up the transition and process it when the current one completes. + // - If there is a transition in progress, and a queued transition, overwrite the queued transition. + // - If multiple calls to ChangeWeather are made while paused (console up), only the last call will be used, + // meaning that if there was no transition in progress, only the last ChangeWeather will be processed. + // If the region isn't current, Morrowind will store the new weather for the region in question. - if (instant || mFirstUpdate) + if(weatherID < mWeatherSettings.size()) { - mNextWeather = ""; - mCurrentWeather = weather; - } - else - { - if (mNextWeather != "") + std::string lowerCaseRegionID = Misc::StringUtils::lowerCase(regionID); + std::map::iterator it = mRegions.find(lowerCaseRegionID); + if(it != mRegions.end()) { - // transition more than 50% finished? - if (mRemainingTransitionTime / (findWeather(mCurrentWeather).transitionSeconds()) <= 0.5) - mCurrentWeather = mNextWeather; - } - - mNextWeather = weather; - mRemainingTransitionTime = findWeather(mCurrentWeather).transitionSeconds(); - } - mFirstUpdate = false; -} - -void WeatherManager::setResult(const std::string& weatherType) -{ - const Weather& current = findWeather(weatherType); - - mResult.mCloudTexture = current.mCloudTexture; - mResult.mCloudBlendFactor = 0; - mResult.mWindSpeed = current.mWindSpeed; - mResult.mCloudSpeed = current.mCloudSpeed; - mResult.mGlareView = current.mGlareView; - mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; - mResult.mAmbientSoundVolume = 1.f; - mResult.mEffectFade = 1.f; - mResult.mSunColor = current.mSunDiscSunsetColor; - - mResult.mIsStorm = current.mIsStorm; - - mResult.mRainSpeed = current.mRainSpeed; - mResult.mRainFrequency = current.mRainFrequency; - - mResult.mParticleEffect = current.mParticleEffect; - mResult.mRainEffect = current.mRainEffect; - - mResult.mNight = (mHour < mSunriseTime || mHour > mNightStart - 1); - - mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; - - // night - if (mHour <= mNightEnd || mHour >= mNightStart + 1) - { - mResult.mFogColor = current.mFogNightColor; - mResult.mAmbientColor = current.mAmbientNightColor; - mResult.mSunColor = current.mSunNightColor; - mResult.mSkyColor = current.mSkyNightColor; - mResult.mNightFade = 1.f; - } - - // sunrise - else if (mHour >= mNightEnd && mHour <= mDayStart + 1) - { - if (mHour <= mSunriseTime) - { - // fade in - float advance = mSunriseTime - mHour; - float factor = advance / 0.5f; - mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor, factor); - mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor, factor); - mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor, factor); - mResult.mNightFade = factor; - } - else //if (mHour >= 6) - { - // fade out - float advance = mHour - mSunriseTime; - float factor = advance / 3.f; - mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor, factor); - mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor, factor); - mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor, factor); - } - } - - // day - else if (mHour >= mDayStart + 1 && mHour <= mDayEnd - 1) - { - mResult.mFogColor = current.mFogDayColor; - mResult.mAmbientColor = current.mAmbientDayColor; - mResult.mSunColor = current.mSunDayColor; - mResult.mSkyColor = current.mSkyDayColor; - } - - // sunset - else if (mHour >= mDayEnd - 1 && mHour <= mNightStart + 1) - { - if (mHour <= mDayEnd + 1) - { - // fade in - float advance = (mDayEnd + 1) - mHour; - float factor = (advance / 2); - mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor, factor); - mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor, factor); - mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor, factor); - } - else //if (mHour >= 19) - { - // fade out - float advance = mHour - (mDayEnd + 1); - float factor = advance / 2.f; - mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor, factor); - mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor, factor); - mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor, factor); - mResult.mNightFade = factor; + it->second.setWeather(weatherID); + regionalWeatherChanged(it->first, it->second); } } } -void WeatherManager::transition(float factor) +void WeatherManager::modRegion(const std::string& regionID, const std::vector& chances) { - setResult(mCurrentWeather); - const MWRender::WeatherResult current = mResult; - setResult(mNextWeather); - const MWRender::WeatherResult other = mResult; + // Sets the region's probability for various weather patterns. Note that this appears to be saved permanently. + // In Morrowind, this seems to have the following behavior when applied to the current region: + // - If the region supports the current weather, no change in current weather occurs. + // - If the region no longer supports the current weather, and there is no transition in progress, begin to + // transition to a new supported weather type. + // - If the region no longer supports the current weather, and there is a transition in progress, queue a + // transition to a new supported weather type. - const Weather& nextWeather = findWeather(mNextWeather); - - mResult.mCloudTexture = current.mCloudTexture; - mResult.mNextCloudTexture = other.mCloudTexture; - mResult.mCloudBlendFactor = nextWeather.cloudBlendFactor(factor); - - mResult.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); - mResult.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); - mResult.mSkyColor = lerp(current.mSkyColor, other.mSkyColor, factor); - - mResult.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor, factor); - mResult.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor, factor); - mResult.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor); - mResult.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor); - mResult.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor); - mResult.mGlareView = lerp(current.mGlareView, other.mGlareView, factor); - mResult.mNightFade = lerp(current.mNightFade, other.mNightFade, factor); - - mResult.mNight = current.mNight; - - if (factor < 0.5) + std::string lowerCaseRegionID = Misc::StringUtils::lowerCase(regionID); + std::map::iterator it = mRegions.find(lowerCaseRegionID); + if(it != mRegions.end()) { - mResult.mIsStorm = current.mIsStorm; - mResult.mParticleEffect = current.mParticleEffect; - mResult.mRainEffect = current.mRainEffect; - mResult.mParticleEffect = current.mParticleEffect; - mResult.mRainSpeed = current.mRainSpeed; - mResult.mRainFrequency = current.mRainFrequency; - mResult.mAmbientSoundVolume = 1-(factor*2); - mResult.mEffectFade = mResult.mAmbientSoundVolume; - mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; + it->second.setChances(chances); + regionalWeatherChanged(it->first, it->second); } - else +} + +void WeatherManager::playerTeleported() +{ + // If the player teleports to an outdoors cell in a new region (for instance, by travelling), the weather needs to + // be changed immediately, and any transitions for the previous region discarded. + MWBase::World* world = MWBase::Environment::get().getWorld(); + if(world->isCellExterior() || world->isCellQuasiExterior()) { - mResult.mIsStorm = other.mIsStorm; - mResult.mParticleEffect = other.mParticleEffect; - mResult.mRainEffect = other.mRainEffect; - mResult.mParticleEffect = other.mParticleEffect; - mResult.mRainSpeed = other.mRainSpeed; - mResult.mRainFrequency = other.mRainFrequency; - mResult.mAmbientSoundVolume = 2*(factor-0.5f); - mResult.mEffectFade = mResult.mAmbientSoundVolume; - mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; + std::string playerRegion = Misc::StringUtils::lowerCase(world->getPlayerPtr().getCell()->getCell()->mRegion); + std::map::iterator it = mRegions.find(playerRegion); + if(it != mRegions.end() && playerRegion != mCurrentRegion) + { + mCurrentRegion = playerRegion; + forceWeather(it->second.getWeather()); + } } } void WeatherManager::update(float duration, bool paused) { - float timePassed = static_cast(mTimePassed); - mTimePassed = 0; + MWWorld::Ptr player = MWMechanics::getPlayer(); + MWBase::World& world = *MWBase::Environment::get().getWorld(); + TimeStamp time = world.getTimeStamp(); - mWeatherUpdateTime -= timePassed; - - MWBase::World* world = MWBase::Environment::get().getWorld(); - const bool exterior = (world->isCellExterior() || world->isCellQuasiExterior()); - if (!exterior) + if(!paused) { - mRendering->setSkyEnabled(false); + // Add new transitions when either the player's current external region changes. + std::string playerRegion = Misc::StringUtils::lowerCase(player.getCell()->getCell()->mRegion); + if(updateWeatherTime() || updateWeatherRegion(playerRegion)) + { + std::map::iterator it = mRegions.find(mCurrentRegion); + if(it != mRegions.end()) + { + addWeatherTransition(it->second.getWeather()); + } + } + + updateWeatherTransitions(duration); + } + + const bool exterior = (world.isCellExterior() || world.isCellQuasiExterior()); + if(!exterior) + { + mRendering.setSkyEnabled(false); //mRendering->getSkyManager()->setLightningStrength(0.f); stopSounds(); return; } - switchToNextWeather(false); - - if (mNextWeather != "") - { - mRemainingTransitionTime -= timePassed; - if (mRemainingTransitionTime < 0) - { - mCurrentWeather = mNextWeather; - mNextWeather = ""; - } - } - - if (mNextWeather != "") - transition(1 - (mRemainingTransitionTime / (findWeather(mCurrentWeather).transitionSeconds()))); - else - setResult(mCurrentWeather); + calculateWeatherResult(time.getHour()); mWindSpeed = mResult.mWindSpeed; mIsStorm = mResult.mIsStorm; if (mIsStorm) { - MWWorld::Ptr player = world->getPlayerPtr(); osg::Vec3f playerPos (player.getRefData().getPosition().asVec3()); osg::Vec3f redMountainPos (19950, 72032, 27831); mStormDirection = (playerPos - redMountainPos); mStormDirection.z() = 0; mStormDirection.normalize(); - mRendering->getSkyManager()->setStormDirection(mStormDirection); + mRendering.getSkyManager()->setStormDirection(mStormDirection); } - mRendering->configureFog(mResult.mFogDepth, mResult.mFogColor); + mRendering.configureFog(mResult.mFogDepth, mResult.mFogColor); // disable sun during night - if (mHour >= mNightStart || mHour <= mSunriseTime) - mRendering->getSkyManager()->sunDisable(); + if (time.getHour() >= mNightStart || time.getHour() <= mSunriseTime) + mRendering.getSkyManager()->sunDisable(); else - mRendering->getSkyManager()->sunEnable(); + mRendering.getSkyManager()->sunEnable(); // Update the sun direction. Run it east to west at a fixed angle from overhead. // The sun's speed at day and night may differ, since mSunriseTime and mNightStart // mark when the sun is level with the horizon. { // Shift times into a 24-hour window beginning at mSunriseTime... - float adjustedHour = mHour; + float adjustedHour = time.getHour(); float adjustedNightStart = mNightStart; - if ( mHour < mSunriseTime ) + if ( time.getHour() < mSunriseTime ) adjustedHour += 24.f; if ( mNightStart < mSunriseTime ) adjustedNightStart += 24.f; @@ -585,16 +563,15 @@ void WeatherManager::update(float duration, bool paused) static_cast(cos(theta)), -0.268f, // approx tan( -15 degrees ) static_cast(sin(theta))); - mRendering->setSunDirection( final * -1 ); + mRendering.setSunDirection( final * -1 ); } - TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp(); - mRendering->getSkyManager()->setMasserState(mMasser.calculateState(time.getDay(), time.getHour())); - mRendering->getSkyManager()->setSecundaState(mSecunda.calculateState(time.getDay(), time.getHour())); + mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time)); + mRendering.getSkyManager()->setSecundaState(mSecunda.calculateState(time)); if (!paused) { - if (mCurrentWeather == "thunderstorm" && mNextWeather == "") + if(mCurrentWeather == 5 && !inTransition()) { if (mThunderFlash > 0) { @@ -641,12 +618,11 @@ void WeatherManager::update(float duration, bool paused) //else //mRendering->getSkyManager()->setLightningStrength(0.f); } - - mRendering->setAmbientColour(mResult.mAmbientColor); - mRendering->setSunColour(mResult.mSunColor); + mRendering.setAmbientColour(mResult.mAmbientColor); + mRendering.setSunColour(mResult.mSunColor); - mRendering->getSkyManager()->setWeather(mResult); + mRendering.getSkyManager()->setWeather(mResult); // Play sounds if (mPlayingSoundID != mResult.mAmbientLoopSoundID) @@ -671,250 +647,11 @@ void WeatherManager::stopSounds() } } -std::string WeatherManager::nextWeather(const ESM::Region* region) const -{ - std::vector probability; - - RegionModMap::const_iterator iter = mRegionMods.find(Misc::StringUtils::lowerCase(region->mId)); - if(iter != mRegionMods.end()) - probability = iter->second; - else - { - probability.reserve(10); - probability.push_back(region->mData.mClear); - probability.push_back(region->mData.mCloudy); - probability.push_back(region->mData.mFoggy); - probability.push_back(region->mData.mOvercast); - probability.push_back(region->mData.mRain); - probability.push_back(region->mData.mThunder); - probability.push_back(region->mData.mAsh); - probability.push_back(region->mData.mBlight); - probability.push_back(region->mData.mA); - probability.push_back(region->mData.mB); - } - - /* - * All probabilities must add to 100 (responsibility of the user). - * If chances A and B has values 30 and 70 then by generating - * 100 numbers 1..100, 30% will be lesser or equal 30 and - * 70% will be greater than 30 (in theory). - */ - - int chance = Misc::Rng::rollDice(100) + 1; // 1..100 - int sum = 0; - unsigned int i = 0; - for (; i < probability.size(); ++i) - { - sum += probability[i]; - if (chance < sum) - break; - } - - switch (i) - { - case 1: - return "cloudy"; - case 2: - return "foggy"; - case 3: - return "overcast"; - case 4: - return "rain"; - case 5: - return "thunderstorm"; - case 6: - return "ashstorm"; - case 7: - return "blight"; - case 8: - return "snow"; - case 9: - return "blizzard"; - default: // case 0 - return "clear"; - } -} - -void WeatherManager::setHour(const float hour) -{ - mHour = hour; -} - -unsigned int WeatherManager::getWeatherID() const -{ - // Source: http://www.uesp.net/wiki/Tes3Mod:GetCurrentWeather - - if (mCurrentWeather == "clear") - return 0; - else if (mCurrentWeather == "cloudy") - return 1; - else if (mCurrentWeather == "foggy") - return 2; - else if (mCurrentWeather == "overcast") - return 3; - else if (mCurrentWeather == "rain") - return 4; - else if (mCurrentWeather == "thunderstorm") - return 5; - else if (mCurrentWeather == "ashstorm") - return 6; - else if (mCurrentWeather == "blight") - return 7; - else if (mCurrentWeather == "snow") - return 8; - else if (mCurrentWeather == "blizzard") - return 9; - - else - return 0; -} - -void WeatherManager::changeWeather(const std::string& region, const unsigned int id) -{ - // make sure this region exists - MWBase::Environment::get().getWorld()->getStore().get().find(region); - - std::string weather; - if (id==0) - weather = "clear"; - else if (id==1) - weather = "cloudy"; - else if (id==2) - weather = "foggy"; - else if (id==3) - weather = "overcast"; - else if (id==4) - weather = "rain"; - else if (id==5) - weather = "thunderstorm"; - else if (id==6) - weather = "ashstorm"; - else if (id==7) - weather = "blight"; - else if (id==8) - weather = "snow"; - else if (id==9) - weather = "blizzard"; - else - weather = "clear"; - - mRegionOverrides[Misc::StringUtils::lowerCase(region)] = weather; - - MWWorld::Ptr player = MWMechanics::getPlayer(); - if (player.isInCell()) - { - std::string playerRegion = player.getCell()->getCell()->mRegion; - if (Misc::StringUtils::ciEqual(region, playerRegion)) - setWeather(weather); - } -} - -void WeatherManager::modRegion(const std::string ®ionid, const std::vector &chances) -{ - mRegionMods[Misc::StringUtils::lowerCase(regionid)] = chances; - // Start transitioning right away if the region no longer supports the current weather type - unsigned int current = getWeatherID(); - if(current >= chances.size() || chances[current] == 0) - mWeatherUpdateTime = 0.0f; -} - float WeatherManager::getWindSpeed() const { return mWindSpeed; } -bool WeatherManager::isDark() const -{ - bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() - || MWBase::Environment::get().getWorld()->isCellQuasiExterior()); - return exterior && (mHour < mSunriseTime || mHour > mNightStart - 1); -} - -void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) -{ - ESM::WeatherState state; - state.mHour = mHour; - state.mWindSpeed = mWindSpeed; - state.mCurrentWeather = mCurrentWeather; - state.mNextWeather = mNextWeather; - state.mCurrentRegion = mCurrentRegion; - state.mFirstUpdate = mFirstUpdate; - state.mRemainingTransitionTime = mRemainingTransitionTime; - state.mTimePassed = mTimePassed; - - writer.startRecord(ESM::REC_WTHR); - state.save(writer); - writer.endRecord(ESM::REC_WTHR); -} - -bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) -{ - if(ESM::REC_WTHR == type) - { - // load first so that if it fails, we haven't accidentally reset the state below - ESM::WeatherState state; - state.load(reader); - - // swap in the loaded values now that we can't fail - mHour = state.mHour; - mWindSpeed = state.mWindSpeed; - mCurrentWeather.swap(state.mCurrentWeather); - mNextWeather.swap(state.mNextWeather); - mCurrentRegion.swap(state.mCurrentRegion); - mFirstUpdate = state.mFirstUpdate; - mRemainingTransitionTime = state.mRemainingTransitionTime; - mTimePassed = state.mTimePassed; - - return true; - } - - return false; -} - -void WeatherManager::clear() -{ - stopSounds(); - mRegionOverrides.clear(); - mRegionMods.clear(); - mThunderFlash = 0.0; - mThunderChance = 0.0; - mThunderChanceNeeded = 50.0; -} - -void WeatherManager::switchToNextWeather(bool instantly) -{ - MWBase::World* world = MWBase::Environment::get().getWorld(); - if (world->isCellExterior() || world->isCellQuasiExterior()) - { - std::string regionstr = Misc::StringUtils::lowerCase(world->getPlayerPtr().getCell()->getCell()->mRegion); - - if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) - { - mCurrentRegion = regionstr; - mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600; - - std::string weatherType = "clear"; - - if (mRegionOverrides.find(regionstr) != mRegionOverrides.end()) - { - weatherType = mRegionOverrides[regionstr]; - } - else - { - // get weather probabilities for the current region - const ESM::Region *region = world->getStore().get().search (regionstr); - - if (region != 0) - { - weatherType = nextWeather(region); - } - } - - setWeather(weatherType, instantly); - } - } -} - bool WeatherManager::isInStorm() const { return mIsStorm; @@ -927,7 +664,106 @@ osg::Vec3f WeatherManager::getStormDirection() const void WeatherManager::advanceTime(double hours) { - mTimePassed += hours*3600; + // This is called when the player sleeps/waits, serves jail time, travels, or trains. + // In Morrowind, when any of those events occur, all weather transitions are immediately applied, regardless of + // whatever transition time might have been remaining. + mTimePassed += hours; + mFastForward = true; +} + +void WeatherManager::advanceTimeByFrame(double hours) +{ + // Called when time is advanced by an incremental update for each frame. + mTimePassed += hours; +} + +unsigned int WeatherManager::getWeatherID() const +{ + return mCurrentWeather; +} + +bool WeatherManager::isDark() const +{ + TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp(); + bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() + || MWBase::Environment::get().getWorld()->isCellQuasiExterior()); + return exterior && (time.getHour() < mSunriseTime || time.getHour() > mNightStart - 1); +} + +void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) +{ + ESM::WeatherState state; + state.mCurrentRegion = mCurrentRegion; + state.mTimePassed = mTimePassed; + state.mFastForward = mFastForward; + state.mWeatherUpdateTime = mWeatherUpdateTime; + state.mTransitionFactor = mTransitionFactor; + state.mCurrentWeather = mCurrentWeather; + state.mNextWeather = mNextWeather; + state.mQueuedWeather = mQueuedWeather; + + std::map::iterator it = mRegions.begin(); + for(; it != mRegions.end(); ++it) + { + state.mRegions.insert(std::make_pair(it->first, ESM::RegionWeatherState(it->second))); + } + + writer.startRecord(ESM::REC_WTHR); + state.save(writer); + writer.endRecord(ESM::REC_WTHR); +} + +bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) +{ + if(ESM::REC_WTHR == type) + { + ESM::WeatherState state; + state.load(reader); + + mCurrentRegion.swap(state.mCurrentRegion); + mTimePassed = state.mTimePassed; + mFastForward = state.mFastForward; + mWeatherUpdateTime = state.mWeatherUpdateTime; + mTransitionFactor = state.mTransitionFactor; + mCurrentWeather = state.mCurrentWeather; + mNextWeather = state.mCurrentWeather; + mQueuedWeather = state.mQueuedWeather; + + mRegions.clear(); + std::map::iterator it = state.mRegions.begin(); + if(it == state.mRegions.end()) + { + // When loading an imported save, the region modifiers aren't currently being set, so just reset them. + importRegions(); + } + else + { + for(; it != state.mRegions.end(); ++it) + { + mRegions.insert(std::make_pair(it->first, RegionWeather(it->second))); + } + } + + return true; + } + + return false; +} + +void WeatherManager::clear() +{ + stopSounds(); + + mThunderFlash = 0.0; + mThunderChance = 0.0; + mThunderChanceNeeded = 50.0; + + mCurrentRegion = ""; + mTimePassed = 0.0f; + mWeatherUpdateTime = 0.0f; + forceWeather(0); + mRegions.clear(); + importRegions(); } inline void WeatherManager::addWeather(const std::string& name, @@ -935,17 +771,301 @@ inline void WeatherManager::addWeather(const std::string& name, const std::string& ambientLoopSoundID, const std::string& particleEffect) { - static const float fStromWindSpeed = mStore->get().find("fStromWindSpeed")->getFloat(); + static const float fStromWindSpeed = mStore.get().find("fStromWindSpeed")->getFloat(); Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, ambientLoopSoundID, particleEffect); - std::string lower = name; - lower[0] = tolower(lower[0]); - mWeatherSettings.insert(std::make_pair(lower, weather)); + mWeatherSettings.push_back(weather); } -inline Weather& WeatherManager::findWeather(const std::string& name) +inline void WeatherManager::importRegions() { - return mWeatherSettings.at(name); + Store::iterator it = mStore.get().begin(); + for(; it != mStore.get().end(); ++it) + { + std::string regionID = Misc::StringUtils::lowerCase(it->mId); + mRegions.insert(std::make_pair(regionID, RegionWeather(*it))); + } +} + +inline void WeatherManager::regionalWeatherChanged(const std::string& regionID, RegionWeather& region) +{ + // If the region is current, then add a weather transition for it. + MWWorld::Ptr player = MWMechanics::getPlayer(); + if(player.isInCell()) + { + std::string playerRegion = Misc::StringUtils::lowerCase(player.getCell()->getCell()->mRegion); + if(!playerRegion.empty() && (playerRegion == regionID)) + { + addWeatherTransition(region.getWeather()); + } + } +} + +inline bool WeatherManager::updateWeatherTime() +{ + mWeatherUpdateTime -= mTimePassed; + mTimePassed = 0.0f; + if(mWeatherUpdateTime <= 0.0f) + { + // Expire all regional weather, so that any call to getWeather() will return a new weather ID. + std::map::iterator it = mRegions.begin(); + for(; it != mRegions.end(); ++it) + { + it->second.setWeather(invalidWeatherID); + } + + mWeatherUpdateTime += mHoursBetweenWeatherChanges; + + return true; + } + + return false; +} + +inline bool WeatherManager::updateWeatherRegion(const std::string& playerRegion) +{ + if(!playerRegion.empty() && playerRegion != mCurrentRegion) + { + mCurrentRegion = playerRegion; + + return true; + } + + return false; +} + +inline void WeatherManager::updateWeatherTransitions(const float elapsedRealSeconds) +{ + // When a player chooses to train, wait, or serves jail time, any transitions will be fast forwarded to the last + // weather type set, regardless of the remaining transition time. + if(!mFastForward && inTransition()) + { + const float delta = mWeatherSettings[mNextWeather].transitionDelta(); + mTransitionFactor -= elapsedRealSeconds * delta; + if(mTransitionFactor <= 0.0f) + { + mCurrentWeather = mNextWeather; + mNextWeather = mQueuedWeather; + mQueuedWeather = invalidWeatherID; + + // We may have begun processing the queued transition, so we need to apply the remaining time towards it. + if(inTransition()) + { + const float newDelta = mWeatherSettings[mNextWeather].transitionDelta(); + const float remainingSeconds = -(mTransitionFactor / delta); + mTransitionFactor = 1.0f - (remainingSeconds * newDelta); + } + else + { + mTransitionFactor = 0.0f; + } + } + } + else + { + if(mQueuedWeather != invalidWeatherID) + { + mCurrentWeather = mQueuedWeather; + } + else if(mNextWeather != invalidWeatherID) + { + mCurrentWeather = mNextWeather; + } + + mFastForward = false; + } +} + +inline void WeatherManager::forceWeather(const int weatherID) +{ + mTransitionFactor = 0.0f; + mCurrentWeather = weatherID; + mNextWeather = invalidWeatherID; + mQueuedWeather = invalidWeatherID; +} + +inline bool WeatherManager::inTransition() +{ + return mNextWeather != invalidWeatherID; +} + +inline void WeatherManager::addWeatherTransition(const int weatherID) +{ + // In order to work like ChangeWeather expects, this method begins transitioning to the new weather immediately if + // no transition is in progress, otherwise it queues it to be transitioned. + + assert(weatherID >= 0 && static_cast(weatherID) < mWeatherSettings.size()); + + if(!inTransition() && (weatherID != mCurrentWeather)) + { + mNextWeather = weatherID; + mTransitionFactor = 1.0f; + } + else if(inTransition() && (weatherID != mNextWeather)) + { + mQueuedWeather = weatherID; + } +} + +inline void WeatherManager::calculateWeatherResult(const float gameHour) +{ + if(!inTransition()) + { + calculateResult(mCurrentWeather, gameHour); + } + else + { + calculateTransitionResult(1 - mTransitionFactor, gameHour); + } +} + +inline void WeatherManager::calculateResult(const int weatherID, const float gameHour) +{ + const Weather& current = mWeatherSettings[weatherID]; + + mResult.mCloudTexture = current.mCloudTexture; + mResult.mCloudBlendFactor = 0; + mResult.mWindSpeed = current.mWindSpeed; + mResult.mCloudSpeed = current.mCloudSpeed; + mResult.mGlareView = current.mGlareView; + mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; + mResult.mAmbientSoundVolume = 1.f; + mResult.mEffectFade = 1.f; + mResult.mSunColor = current.mSunDiscSunsetColor; + + mResult.mIsStorm = current.mIsStorm; + + mResult.mRainSpeed = current.mRainSpeed; + mResult.mRainFrequency = current.mRainFrequency; + + mResult.mParticleEffect = current.mParticleEffect; + mResult.mRainEffect = current.mRainEffect; + + mResult.mNight = (gameHour < mSunriseTime || gameHour > mNightStart - 1); + + mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; + + // night + if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) + { + mResult.mFogColor = current.mFogNightColor; + mResult.mAmbientColor = current.mAmbientNightColor; + mResult.mSunColor = current.mSunNightColor; + mResult.mSkyColor = current.mSkyNightColor; + mResult.mNightFade = 1.f; + } + + // sunrise + else if (gameHour >= mNightEnd && gameHour <= mDayStart + 1) + { + if (gameHour <= mSunriseTime) + { + // fade in + float advance = mSunriseTime - gameHour; + float factor = advance / 0.5f; + mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor, factor); + mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor, factor); + mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor, factor); + mResult.mNightFade = factor; + } + else //if (gameHour >= 6) + { + // fade out + float advance = gameHour - mSunriseTime; + float factor = advance / 3.f; + mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor, factor); + mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor, factor); + mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor, factor); + } + } + + // day + else if (gameHour >= mDayStart + 1 && gameHour <= mDayEnd - 1) + { + mResult.mFogColor = current.mFogDayColor; + mResult.mAmbientColor = current.mAmbientDayColor; + mResult.mSunColor = current.mSunDayColor; + mResult.mSkyColor = current.mSkyDayColor; + } + + // sunset + else if (gameHour >= mDayEnd - 1 && gameHour <= mNightStart + 1) + { + if (gameHour <= mDayEnd + 1) + { + // fade in + float advance = (mDayEnd + 1) - gameHour; + float factor = (advance / 2); + mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor, factor); + mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor, factor); + mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor, factor); + } + else //if (gameHour >= 19) + { + // fade out + float advance = gameHour - (mDayEnd + 1); + float factor = advance / 2.f; + mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor, factor); + mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor, factor); + mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor, factor); + mResult.mNightFade = factor; + } + } +} + +inline void WeatherManager::calculateTransitionResult(const float factor, const float gameHour) +{ + calculateResult(mCurrentWeather, gameHour); + const MWRender::WeatherResult current = mResult; + calculateResult(mNextWeather, gameHour); + const MWRender::WeatherResult other = mResult; + + mResult.mCloudTexture = current.mCloudTexture; + mResult.mNextCloudTexture = other.mCloudTexture; + mResult.mCloudBlendFactor = mWeatherSettings[mNextWeather].cloudBlendFactor(factor); + + mResult.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); + mResult.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); + mResult.mSkyColor = lerp(current.mSkyColor, other.mSkyColor, factor); + + mResult.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor, factor); + mResult.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor, factor); + mResult.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor); + mResult.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor); + mResult.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor); + mResult.mGlareView = lerp(current.mGlareView, other.mGlareView, factor); + mResult.mNightFade = lerp(current.mNightFade, other.mNightFade, factor); + + mResult.mNight = current.mNight; + + if(factor < 0.5) + { + mResult.mIsStorm = current.mIsStorm; + mResult.mParticleEffect = current.mParticleEffect; + mResult.mRainEffect = current.mRainEffect; + mResult.mParticleEffect = current.mParticleEffect; + mResult.mRainSpeed = current.mRainSpeed; + mResult.mRainFrequency = current.mRainFrequency; + mResult.mAmbientSoundVolume = 1-(factor*2); + mResult.mEffectFade = mResult.mAmbientSoundVolume; + mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; + } + else + { + mResult.mIsStorm = other.mIsStorm; + mResult.mParticleEffect = other.mParticleEffect; + mResult.mRainEffect = other.mRainEffect; + mResult.mParticleEffect = other.mParticleEffect; + mResult.mRainSpeed = other.mRainSpeed; + mResult.mRainFrequency = other.mRainFrequency; + mResult.mAmbientSoundVolume = 2*(factor-0.5f); + mResult.mEffectFade = mResult.mAmbientSoundVolume; + mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; + } } diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 710e45d9b..d07e7e1e4 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -14,6 +14,7 @@ namespace ESM { struct Region; + struct RegionWeatherState; class ESMWriter; class ESMReader; } @@ -31,6 +32,7 @@ namespace Loading namespace MWWorld { class Fallback; + class TimeStamp; /// Defines a single weather setting (according to INI) class Weather @@ -110,7 +112,7 @@ namespace MWWorld // Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature // is broken in the vanilla game and was disabled. - float transitionSeconds() const; + float transitionDelta() const; float cloudBlendFactor(float transitionRatio) const; private: @@ -118,12 +120,35 @@ namespace MWWorld float mCloudsMaximumPercent; }; + /// A class for storing a region's weather. + class RegionWeather + { + public: + explicit RegionWeather(const ESM::Region& region); + explicit RegionWeather(const ESM::RegionWeatherState& state); + + explicit operator ESM::RegionWeatherState() const; + + void setChances(const std::vector& chances); + + void setWeather(int weatherID); + + int getWeather(); + + private: + int mWeather; + std::vector mChances; + + void chooseNewWeather(); + }; + + /// A class that acts as a model for the moons. class MoonModel { public: MoonModel(const std::string& name, const MWWorld::Fallback& fallback); - MWRender::MoonState calculateState(unsigned int daysPassed, float gameHour) const; + MWRender::MoonState calculateState(const TimeStamp& gameTime) const; private: float mFadeInStart; @@ -137,23 +162,23 @@ namespace MWWorld float mFadeEndAngle; float mMoonShadowEarlyFadeAngle; - float angle(unsigned int daysPassed, float gameHour) const; + float angle(const TimeStamp& gameTime) const; float moonRiseHour(unsigned int daysPassed) const; float rotation(float hours) const; - unsigned int phase(unsigned int daysPassed, float gameHour) const; + unsigned int phase(const TimeStamp& gameTime) const; float shadowBlend(float angle) const; float hourlyAlpha(float gameHour) const; float earlyMoonShadowAlpha(float angle) const; }; - /// /// Interface for weather settings - /// class WeatherManager { public: // Have to pass fallback and Store, can't use singleton since World isn't fully constructed yet at the time - WeatherManager(MWRender::RenderingManager*, MWWorld::Fallback* fallback, MWWorld::ESMStore* store); + WeatherManager(MWRender::RenderingManager& rendering, + const MWWorld::Fallback& fallback, + MWWorld::ESMStore& store); ~WeatherManager(); /** @@ -161,8 +186,9 @@ namespace MWWorld * @param region that should be changed * @param ID of the weather setting to shift to */ - void changeWeather(const std::string& region, const unsigned int id); - void switchToNextWeather(bool instantly = true); + void changeWeather(const std::string& regionID, const unsigned int weatherID); + void modRegion(const std::string& regionID, const std::vector& chances); + void playerTeleported(); /** * Per-frame update @@ -173,8 +199,6 @@ namespace MWWorld void stopSounds(); - void setHour(const float hour); - float getWindSpeed() const; /// Are we in an ash or blight storm? @@ -183,11 +207,10 @@ namespace MWWorld osg::Vec3f getStormDirection() const; void advanceTime(double hours); + void advanceTimeByFrame(double hours); unsigned int getWeatherID() const; - void modRegion(const std::string ®ionid, const std::vector &chances); - /// @see World::isDark bool isDark() const; @@ -198,73 +221,77 @@ namespace MWWorld void clear(); private: - float mHour; - float mWindSpeed; - bool mIsStorm; - osg::Vec3f mStormDirection; - - MWBase::SoundPtr mAmbientSound; - std::string mPlayingSoundID; - - MWWorld::ESMStore* mStore; - MWRender::RenderingManager* mRendering; - - std::map mWeatherSettings; - - std::map mRegionOverrides; - - std::string mCurrentWeather; - std::string mNextWeather; - - std::string mCurrentRegion; - - bool mFirstUpdate; - - float mRemainingTransitionTime; - - float mThunderFlash; - float mThunderChance; - float mThunderChanceNeeded; - - double mTimePassed; // time passed since last update - - void transition(const float factor); - void setResult(const std::string& weatherType); - - void setWeather(const std::string& weatherType, bool instant=false); - std::string nextWeather(const ESM::Region* region) const; - MWRender::WeatherResult mResult; - - typedef std::map > RegionModMap; - RegionModMap mRegionMods; - - float mRainSpeed; + MWWorld::ESMStore& mStore; + MWRender::RenderingManager& mRendering; float mSunriseTime; float mSunsetTime; float mSunriseDuration; float mSunsetDuration; - float mWeatherUpdateTime; - float mHoursBetweenWeatherChanges; - float mThunderFrequency; - float mThunderThreshold; - float mThunderSoundDelay; + // Some useful values + /* TODO: Use pre-sunrise_time, pre-sunset_time, + * post-sunrise_time, and post-sunset_time to better + * describe sunrise/sunset time. + * These values are fallbacks attached to weather. + */ float mNightStart; float mNightEnd; float mDayStart; float mDayEnd; + float mHoursBetweenWeatherChanges; + float mRainSpeed; + std::vector mWeatherSettings; + MoonModel mMasser; + MoonModel mSecunda; + + float mThunderFrequency; + float mThunderThreshold; std::string mThunderSoundID0; std::string mThunderSoundID1; std::string mThunderSoundID2; std::string mThunderSoundID3; - MoonModel mMasser; - MoonModel mSecunda; + + float mWindSpeed; + bool mIsStorm; + osg::Vec3f mStormDirection; + + float mThunderSoundDelay; + float mThunderFlash; + float mThunderChance; + float mThunderChanceNeeded; + + std::string mCurrentRegion; + float mTimePassed; + bool mFastForward; + float mWeatherUpdateTime; + float mTransitionFactor; + int mCurrentWeather; + int mNextWeather; + int mQueuedWeather; + std::map mRegions; + MWRender::WeatherResult mResult; + + MWBase::SoundPtr mAmbientSound; + std::string mPlayingSoundID; void addWeather(const std::string& name, const MWWorld::Fallback& fallback, const std::string& ambientLoopSoundID = "", const std::string& particleEffect = ""); - Weather& findWeather(const std::string& name); + void importRegions(); + + void regionalWeatherChanged(const std::string& regionID, RegionWeather& region); + bool updateWeatherTime(); + bool updateWeatherRegion(const std::string& playerRegion); + void updateWeatherTransitions(const float elapsedRealSeconds); + void forceWeather(const int weatherID); + + bool inTransition(); + void addWeatherTransition(const int weatherID); + + void calculateWeatherResult(const float gameHour); + void calculateResult(const int weatherID, const float gameHour); + void calculateTransitionResult(const float factor, const float gameHour); }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 40a929cda..56c7415a2 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -193,7 +193,7 @@ namespace MWWorld mGlobalVariables.fill (mStore); - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback,&mStore); + mWeatherManager = new MWWorld::WeatherManager(*mRendering, mFallback, mStore); mWorldScene = new Scene(*mRendering, mPhysics); } @@ -212,6 +212,11 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->updatePlayer(); + // we don't want old weather to persist on a new game + // Note that if reset later, the initial ChangeWeather that the chargen script calls will be lost. + delete mWeatherManager; + mWeatherManager = new MWWorld::WeatherManager(*mRendering, mFallback, mStore); + if (!bypass) { // set new game mark @@ -265,11 +270,6 @@ namespace MWWorld if (!mPhysics->toggleCollisionMode()) mPhysics->toggleCollisionMode(); - // we don't want old weather to persist on a new game - delete mWeatherManager; - mWeatherManager = 0; - mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback,&mStore); - if (!mStartupScript.empty()) MWBase::Environment::get().getWindowManager()->executeInConsole(mStartupScript); } @@ -804,6 +804,25 @@ namespace MWWorld days + mGlobalVariables["dayspassed"].getInteger()); } + void World::advanceTimeByFrame (double frametime) + { + double hours = (frametime * getTimeScaleFactor()) / 3600.0; + + MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast(hours * 3600)); + + mWeatherManager->advanceTimeByFrame (hours); + + hours += mGlobalVariables["gamehour"].getFloat(); + + setHour (hours); + + int days = static_cast(hours / 24); + + if (days>0) + mGlobalVariables["dayspassed"].setInteger ( + days + mGlobalVariables["dayspassed"].getInteger()); + } + void World::setHour (double hour) { if (hour<0) @@ -815,8 +834,6 @@ namespace MWWorld mGlobalVariables["gamehour"].setFloat(static_cast(hour)); - mWeatherManager->setHour(static_cast(hour)); - if (days>0) setDay (days + mGlobalVariables["day"].getInteger()); } @@ -2888,15 +2905,15 @@ namespace MWWorld MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition(), false); action.execute(ptr); } - + void World::updateWeather(float duration, bool paused) { if (mPlayer->wasTeleported()) { mPlayer->setTeleported(false); - mWeatherManager->switchToNextWeather(true); + mWeatherManager->playerTeleported(); } - + mWeatherManager->update(duration, paused); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 35e433549..80fe6d850 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -277,6 +277,9 @@ namespace MWWorld virtual void advanceTime (double hours); ///< Advance in-game time. + virtual void advanceTimeByFrame (double frametime); + ///< Advance in-game time by the duration of a frame. + virtual void setHour (double hour); ///< Set in-game time hour. diff --git a/components/esm/weatherstate.cpp b/components/esm/weatherstate.cpp index 48cf55a60..ff2528e58 100644 --- a/components/esm/weatherstate.cpp +++ b/components/esm/weatherstate.cpp @@ -1,59 +1,72 @@ -#include "weatherstate.hpp" - -#include "esmreader.hpp" -#include "esmwriter.hpp" - -namespace -{ - const char* hourRecord = "HOUR"; - const char* windSpeedRecord = "WNSP"; - const char* currentWeatherRecord = "CWTH"; - const char* nextWeatherRecord = "NWTH"; - const char* currentRegionRecord = "CREG"; - const char* firstUpdateRecord = "FUPD"; - const char* remainingTransitionTimeRecord = "RTTM"; - const char* timePassedRecord = "TMPS"; -} - -namespace ESM -{ - void WeatherState::load(ESMReader& esm) - { - // store values locally so that a failed load can't leave the state half set - float newHour = 0.0; - esm.getHNT(newHour, hourRecord); - float newWindSpeed = 0.0; - esm.getHNT(newWindSpeed, windSpeedRecord); - std::string newCurrentWeather = esm.getHNString(currentWeatherRecord); - std::string newNextWeather = esm.getHNString(nextWeatherRecord); - std::string newCurrentRegion = esm.getHNString(currentRegionRecord); - bool newFirstUpdate = false; - esm.getHNT(newFirstUpdate, firstUpdateRecord); - float newRemainingTransitionTime = 0.0; - esm.getHNT(newRemainingTransitionTime, remainingTransitionTimeRecord); - double newTimePassed = 0.0; - esm.getHNT(newTimePassed, timePassedRecord); - - // swap values now that it is safe to do so - mHour = newHour; - mWindSpeed = newWindSpeed; - mCurrentWeather.swap(newCurrentWeather); - mNextWeather.swap(newNextWeather); - mCurrentRegion.swap(newCurrentRegion); - mFirstUpdate = newFirstUpdate; - mRemainingTransitionTime = newRemainingTransitionTime; - mTimePassed = newTimePassed; - } - - void WeatherState::save(ESMWriter& esm) const - { - esm.writeHNT(hourRecord, mHour); - esm.writeHNT(windSpeedRecord, mWindSpeed); - esm.writeHNCString(currentWeatherRecord, mCurrentWeather.c_str()); - esm.writeHNCString(nextWeatherRecord, mNextWeather.c_str()); - esm.writeHNCString(currentRegionRecord, mCurrentRegion.c_str()); - esm.writeHNT(firstUpdateRecord, mFirstUpdate); - esm.writeHNT(remainingTransitionTimeRecord, mRemainingTransitionTime); - esm.writeHNT(timePassedRecord, mTimePassed); - } -} +#include "weatherstate.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace +{ + const char* currentRegionRecord = "CREG"; + const char* timePassedRecord = "TMPS"; + const char* fastForwardRecord = "FAST"; + const char* weatherUpdateTimeRecord = "WUPD"; + const char* transitionFactorRecord = "TRFC"; + const char* currentWeatherRecord = "CWTH"; + const char* nextWeatherRecord = "NWTH"; + const char* queuedWeatherRecord = "QWTH"; + const char* regionNameRecord = "RGNN"; + const char* regionWeatherRecord = "RGNW"; + const char* regionChanceRecord = "RGNC"; +} + +namespace ESM +{ + void WeatherState::load(ESMReader& esm) + { + mCurrentRegion = esm.getHNString(currentRegionRecord); + esm.getHNT(mTimePassed, timePassedRecord); + esm.getHNT(mFastForward, fastForwardRecord); + esm.getHNT(mWeatherUpdateTime, weatherUpdateTimeRecord); + esm.getHNT(mTransitionFactor, transitionFactorRecord); + esm.getHNT(mCurrentWeather, currentWeatherRecord); + esm.getHNT(mNextWeather, nextWeatherRecord); + esm.getHNT(mQueuedWeather, queuedWeatherRecord); + + while(esm.peekNextSub(regionNameRecord)) + { + std::string regionID = esm.getHNString(regionNameRecord); + RegionWeatherState region; + esm.getHNT(region.mWeather, regionWeatherRecord); + while(esm.peekNextSub(regionChanceRecord)) + { + char chance; + esm.getHNT(chance, regionChanceRecord); + region.mChances.push_back(chance); + } + + mRegions.insert(std::make_pair(regionID, region)); + } + } + + void WeatherState::save(ESMWriter& esm) const + { + esm.writeHNCString(currentRegionRecord, mCurrentRegion.c_str()); + esm.writeHNT(timePassedRecord, mTimePassed); + esm.writeHNT(fastForwardRecord, mFastForward); + esm.writeHNT(weatherUpdateTimeRecord, mWeatherUpdateTime); + esm.writeHNT(transitionFactorRecord, mTransitionFactor); + esm.writeHNT(currentWeatherRecord, mCurrentWeather); + esm.writeHNT(nextWeatherRecord, mNextWeather); + esm.writeHNT(queuedWeatherRecord, mQueuedWeather); + + std::map::const_iterator it = mRegions.begin(); + for(; it != mRegions.end(); ++it) + { + esm.writeHNCString(regionNameRecord, it->first.c_str()); + esm.writeHNT(regionWeatherRecord, it->second.mWeather); + for(size_t i = 0; i < it->second.mChances.size(); ++i) + { + esm.writeHNT(regionChanceRecord, it->second.mChances[i]); + } + } + } +} diff --git a/components/esm/weatherstate.hpp b/components/esm/weatherstate.hpp index d0cd59c16..532a056ac 100644 --- a/components/esm/weatherstate.hpp +++ b/components/esm/weatherstate.hpp @@ -1,27 +1,36 @@ -#ifndef OPENMW_ESM_WEATHERSTATE_H -#define OPENMW_ESM_WEATHERSTATE_H - -#include - -namespace ESM -{ - class ESMReader; - class ESMWriter; - - struct WeatherState - { - float mHour; - float mWindSpeed; - std::string mCurrentWeather; - std::string mNextWeather; - std::string mCurrentRegion; - bool mFirstUpdate; - float mRemainingTransitionTime; - double mTimePassed; - - void load(ESMReader& esm); - void save(ESMWriter& esm) const; - }; -} - -#endif +#ifndef OPENMW_ESM_WEATHERSTATE_H +#define OPENMW_ESM_WEATHERSTATE_H + +#include +#include +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + struct RegionWeatherState + { + int mWeather; + std::vector mChances; + }; + + struct WeatherState + { + std::string mCurrentRegion; + float mTimePassed; + bool mFastForward; + float mWeatherUpdateTime; + float mTransitionFactor; + int mCurrentWeather; + int mNextWeather; + int mQueuedWeather; + std::map mRegions; + + void load(ESMReader& esm); + void save(ESMWriter& esm) const; + }; +} + +#endif From c907ed517d05861db942b4555f0d3883e6c8814a Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 26 Aug 2015 23:34:15 -0500 Subject: [PATCH 321/419] Remove C++11 explicit on conversion operator --- apps/openmw/mwworld/weather.cpp | 14 ++++++++++---- apps/openmw/mwworld/weather.hpp | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 8799ae57c..744cae28b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -127,7 +127,13 @@ RegionWeather::RegionWeather(const ESM::RegionWeatherState& state) RegionWeather::operator ESM::RegionWeatherState() const { - return ESM::RegionWeatherState { mWeather, mChances }; + ESM::RegionWeatherState state = + { + mWeather, + mChances + }; + + return state; } void RegionWeather::setChances(const std::vector& chances) @@ -370,12 +376,12 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mWeatherSettings() , mMasser("Masser", fallback) , mSecunda("Secunda", fallback) + , mThunderFrequency(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency")) + , mThunderThreshold(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold")) , mThunderSoundID0(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0")) , mThunderSoundID1(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1")) , mThunderSoundID2(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2")) , mThunderSoundID3(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3")) - , mThunderFrequency(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency")) - , mThunderThreshold(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold")) , mWindSpeed(0.f) , mIsStorm(false) , mStormDirection(0,1,0) @@ -705,7 +711,7 @@ void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) std::map::iterator it = mRegions.begin(); for(; it != mRegions.end(); ++it) { - state.mRegions.insert(std::make_pair(it->first, ESM::RegionWeatherState(it->second))); + state.mRegions.insert(std::make_pair(it->first, it->second)); } writer.startRecord(ESM::REC_WTHR); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index d07e7e1e4..cdbe14dfa 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -127,7 +127,7 @@ namespace MWWorld explicit RegionWeather(const ESM::Region& region); explicit RegionWeather(const ESM::RegionWeatherState& state); - explicit operator ESM::RegionWeatherState() const; + operator ESM::RegionWeatherState() const; void setChances(const std::vector& chances); From 95d2d82abf75c533fe9fbec2446d7038696094e7 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 27 Aug 2015 18:36:46 +1200 Subject: [PATCH 322/419] extracted isFlagBitSet() --- apps/openmw/mwclass/creature.cpp | 60 ++++++++++++-------------------- apps/openmw/mwclass/creature.hpp | 7 ++++ 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index e14d9f8ba..80934f885 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -129,7 +129,8 @@ namespace MWClass } // inventory - if (ref->mBase->mFlags & ESM::Creature::Weapon) + bool hasInventory = hasInventoryStore(ptr); + if (hasInventory) data->mContainerStore = new MWWorld::InventoryStore(); else data->mContainerStore = new MWWorld::ContainerStore(); @@ -143,7 +144,7 @@ namespace MWClass getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr)); - if (ref->mBase->mFlags & ESM::Creature::Weapon) + if (hasInventory) getInventoryStore(ptr).autoEquip(ptr); } } @@ -158,10 +159,8 @@ namespace MWClass void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - MWWorld::LiveCellRef *ref = ptr.get(); - MWRender::Objects& objects = renderingInterface.getObjects(); - objects.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); + objects.insertCreature(ptr, model, hasInventoryStore(ptr)); } std::string Creature::getModel(const MWWorld::Ptr &ptr) const @@ -422,9 +421,7 @@ namespace MWClass MWWorld::InventoryStore& Creature::getInventoryStore(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); - - if (ref->mBase->mFlags & ESM::Creature::Weapon) + if (hasInventoryStore(ptr)) return dynamic_cast(getContainerStore(ptr)); else throw std::runtime_error("this creature has no inventory store"); @@ -432,9 +429,7 @@ namespace MWClass bool Creature::hasInventoryStore(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); - - return (ref->mBase->mFlags & ESM::Creature::Weapon) != 0; + return isFlagBitSet(ptr, ESM::Creature::Weapon); } std::string Creature::getScript (const MWWorld::Ptr& ptr) const @@ -446,10 +441,7 @@ namespace MWClass bool Creature::isEssential (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return (ref->mBase->mFlags & ESM::Creature::Essential) != 0; + return isFlagBitSet(ptr, ESM::Creature::Essential); } void Creature::registerSelf() @@ -601,34 +593,22 @@ namespace MWClass bool Creature::isBipedal(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return ref->mBase->mFlags & ESM::Creature::Bipedal; + return isFlagBitSet(ptr, ESM::Creature::Bipedal); } bool Creature::canFly(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return (ref->mBase->mFlags & ESM::Creature::Flies) != 0; + return isFlagBitSet(ptr, ESM::Creature::Flies); } bool Creature::canSwim(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return ref->mBase->mFlags & ESM::Creature::Swims || ref->mBase->mFlags & ESM::Creature::Bipedal; + return isFlagBitSet(ptr, static_cast(ESM::Creature::Swims | ESM::Creature::Bipedal)); } bool Creature::canWalk(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - return ref->mBase->mFlags & ESM::Creature::Walks || ref->mBase->mFlags & ESM::Creature::Bipedal; + return isFlagBitSet(ptr, static_cast(ESM::Creature::Walks | ESM::Creature::Bipedal)); } int Creature::getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name) @@ -691,11 +671,11 @@ namespace MWClass int Creature::getBloodTexture(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = ptr.get(); + int flags = ptr.get()->mBase->mFlags; - if (ref->mBase->mFlags & ESM::Creature::Skeleton) + if (flags & ESM::Creature::Skeleton) return 1; - if (ref->mBase->mFlags & ESM::Creature::Metal) + if (flags & ESM::Creature::Metal) return 2; return 0; } @@ -715,9 +695,7 @@ namespace MWClass // Create a CustomData, but don't fill it from ESM records (not needed) std::auto_ptr data (new CreatureCustomData); - MWWorld::LiveCellRef *ref = ptr.get(); - - if (ref->mBase->mFlags & ESM::Creature::Weapon) + if (hasInventoryStore(ptr)) data->mContainerStore = new MWWorld::InventoryStore(); else data->mContainerStore = new MWWorld::ContainerStore(); @@ -760,7 +738,7 @@ namespace MWClass void Creature::respawn(const MWWorld::Ptr &ptr) const { - if (ptr.get()->mBase->mFlags & ESM::Creature::Respawn) + if (isFlagBitSet(ptr, ESM::Creature::Respawn)) { // Note we do not respawn moved references in the cell they were moved to. Instead they are respawned in the original cell. // This also means we cannot respawn dynamically placed references with no content file connection. @@ -796,4 +774,10 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); scale *= ref->mBase->mScale; } + + bool Creature::isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) const + { + MWWorld::LiveCellRef *ref = ptr.get(); + return (ref->mBase->mFlags & bitMask) != 0; + } } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index c4ea09255..1a29d0318 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -1,6 +1,8 @@ #ifndef GAME_MWCLASS_CREATURE_H #define GAME_MWCLASS_CREATURE_H +#include + #include "actor.hpp" namespace ESM @@ -134,6 +136,11 @@ namespace MWClass virtual int getBaseFightRating(const MWWorld::Ptr &ptr) const; virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const; + + private: + + /// \return true if any of the indicated bits in Creature's mFlags is set + bool isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) const; }; } From 7817c52cbb6e7f67d4cc49a8b07a89f3d26d5407 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 27 Aug 2015 09:57:32 -0500 Subject: [PATCH 323/419] Discard old save game weather records --- apps/openmw/mwworld/weather.cpp | 49 ++++++++++++++++++++------------- components/esm/savedgame.cpp | 2 +- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 744cae28b..43b2a0dff 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -5,7 +5,9 @@ #include +#include #include +#include #include #include "../mwbase/environment.hpp" @@ -723,30 +725,39 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) { if(ESM::REC_WTHR == type) { - ESM::WeatherState state; - state.load(reader); - - mCurrentRegion.swap(state.mCurrentRegion); - mTimePassed = state.mTimePassed; - mFastForward = state.mFastForward; - mWeatherUpdateTime = state.mWeatherUpdateTime; - mTransitionFactor = state.mTransitionFactor; - mCurrentWeather = state.mCurrentWeather; - mNextWeather = state.mCurrentWeather; - mQueuedWeather = state.mQueuedWeather; - - mRegions.clear(); - std::map::iterator it = state.mRegions.begin(); - if(it == state.mRegions.end()) + if(reader.getFormat() < ESM::SavedGame::sCurrentFormat) { - // When loading an imported save, the region modifiers aren't currently being set, so just reset them. - importRegions(); + // Weather state isn't really all that important, so to preserve older save games, we'll just discard the + // older weather records, rather than fail to handle the record. + reader.skipRecord(); } else { - for(; it != state.mRegions.end(); ++it) + ESM::WeatherState state; + state.load(reader); + + mCurrentRegion.swap(state.mCurrentRegion); + mTimePassed = state.mTimePassed; + mFastForward = state.mFastForward; + mWeatherUpdateTime = state.mWeatherUpdateTime; + mTransitionFactor = state.mTransitionFactor; + mCurrentWeather = state.mCurrentWeather; + mNextWeather = state.mCurrentWeather; + mQueuedWeather = state.mQueuedWeather; + + mRegions.clear(); + std::map::iterator it = state.mRegions.begin(); + if(it == state.mRegions.end()) { - mRegions.insert(std::make_pair(it->first, RegionWeather(it->second))); + // When loading an imported save, the region modifiers aren't currently being set, so just reset them. + importRegions(); + } + else + { + for(; it != state.mRegions.end(); ++it) + { + mRegions.insert(std::make_pair(it->first, RegionWeather(it->second))); + } } } diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index 2e5509b7a..cf9f68c9a 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -5,7 +5,7 @@ #include "defs.hpp" unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE; -int ESM::SavedGame::sCurrentFormat = 1; +int ESM::SavedGame::sCurrentFormat = 2; void ESM::SavedGame::load (ESMReader &esm) { From cd8ec5c11e48def47b69373a1f5f779da84a3e43 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 27 Aug 2015 10:34:35 -0500 Subject: [PATCH 324/419] Improve checking for older weather records --- apps/openmw/mwworld/weather.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 43b2a0dff..5c2a81c09 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -725,7 +725,8 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) { if(ESM::REC_WTHR == type) { - if(reader.getFormat() < ESM::SavedGame::sCurrentFormat) + static const int oldestCompatibleSaveFormat = 2; + if(reader.getFormat() < oldestCompatibleSaveFormat) { // Weather state isn't really all that important, so to preserve older save games, we'll just discard the // older weather records, rather than fail to handle the record. From 4fd00a75d5814a495f150b302570e7779bb48132 Mon Sep 17 00:00:00 2001 From: slothlife Date: Thu, 27 Aug 2015 14:20:45 -0500 Subject: [PATCH 325/419] Merge advanceTime and advanceTimeByFrame --- apps/openmw/engine.cpp | 5 ++++- apps/openmw/mwbase/world.hpp | 5 +---- apps/openmw/mwworld/weather.cpp | 15 ++++----------- apps/openmw/mwworld/weather.hpp | 3 +-- apps/openmw/mwworld/worldimp.cpp | 23 ++--------------------- apps/openmw/mwworld/worldimp.hpp | 5 +---- 6 files changed, 13 insertions(+), 43 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 6c95700b3..32ff20ba7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -128,7 +128,10 @@ void OMW::Engine::frame(float frametime) } if (!guiActive) - mEnvironment.getWorld()->advanceTimeByFrame(frametime); + { + double hours = (frametime * mEnvironment.getWorld()->getTimeScaleFactor()) / 3600.0; + mEnvironment.getWorld()->advanceTime(hours, true); + } } osg::Timer_t afterScriptTick = osg::Timer::instance()->tick(); diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 636370342..a3d293d95 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -185,12 +185,9 @@ namespace MWBase virtual void disable (const MWWorld::Ptr& ptr) = 0; - virtual void advanceTime (double hours) = 0; + virtual void advanceTime (double hours, bool incremental = false) = 0; ///< Advance in-game time. - virtual void advanceTimeByFrame (double frametime) = 0; - ///< Advance in-game time by the duration of a frame. - virtual void setHour (double hour) = 0; ///< Set in-game time hour. diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 5c2a81c09..52609f21a 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -670,19 +670,12 @@ osg::Vec3f WeatherManager::getStormDirection() const return mStormDirection; } -void WeatherManager::advanceTime(double hours) +void WeatherManager::advanceTime(double hours, bool incremental) { - // This is called when the player sleeps/waits, serves jail time, travels, or trains. - // In Morrowind, when any of those events occur, all weather transitions are immediately applied, regardless of - // whatever transition time might have been remaining. - mTimePassed += hours; - mFastForward = true; -} - -void WeatherManager::advanceTimeByFrame(double hours) -{ - // Called when time is advanced by an incremental update for each frame. + // In Morrowind, when the player sleeps/waits, serves jail time, travels, or trains, all weather transitions are + // immediately applied, regardless of whatever transition time might have been remaining. mTimePassed += hours; + mFastForward = (!mFastForward && !incremental) ? true : mFastForward; } unsigned int WeatherManager::getWeatherID() const diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index cdbe14dfa..c808b029b 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -206,8 +206,7 @@ namespace MWWorld osg::Vec3f getStormDirection() const; - void advanceTime(double hours); - void advanceTimeByFrame(double hours); + void advanceTime(double hours, bool incremental); unsigned int getWeatherID() const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 56c7415a2..5f9c8f8d3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -787,30 +787,11 @@ namespace MWWorld } } - void World::advanceTime (double hours) + void World::advanceTime (double hours, bool incremental) { MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast(hours * 3600)); - mWeatherManager->advanceTime (hours); - - hours += mGlobalVariables["gamehour"].getFloat(); - - setHour (hours); - - int days = static_cast(hours / 24); - - if (days>0) - mGlobalVariables["dayspassed"].setInteger ( - days + mGlobalVariables["dayspassed"].getInteger()); - } - - void World::advanceTimeByFrame (double frametime) - { - double hours = (frametime * getTimeScaleFactor()) / 3600.0; - - MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast(hours * 3600)); - - mWeatherManager->advanceTimeByFrame (hours); + mWeatherManager->advanceTime (hours, incremental); hours += mGlobalVariables["gamehour"].getFloat(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 80fe6d850..241dacc8a 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -274,12 +274,9 @@ namespace MWWorld virtual void disable (const Ptr& ptr); - virtual void advanceTime (double hours); + virtual void advanceTime (double hours, bool incremental = false); ///< Advance in-game time. - virtual void advanceTimeByFrame (double frametime); - ///< Advance in-game time by the duration of a frame. - virtual void setHour (double hour); ///< Set in-game time hour. From 300c48329d447ec6a43b67a597005a4ce2fcd7fb Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 28 Aug 2015 18:38:05 +1200 Subject: [PATCH 326/419] Creature::isFlagBitSet() changed to free function. --- apps/openmw/mwclass/creature.cpp | 11 +++++------ apps/openmw/mwclass/creature.hpp | 7 ------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 80934f885..450889eb2 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -58,6 +58,11 @@ namespace cloned->mContainerStore = mContainerStore->clone(); return cloned; } + + bool isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) + { + return (ptr.get()->mBase->mFlags & bitMask) != 0; + } } namespace MWClass @@ -774,10 +779,4 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); scale *= ref->mBase->mScale; } - - bool Creature::isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) const - { - MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->mBase->mFlags & bitMask) != 0; - } } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 1a29d0318..c4ea09255 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -1,8 +1,6 @@ #ifndef GAME_MWCLASS_CREATURE_H #define GAME_MWCLASS_CREATURE_H -#include - #include "actor.hpp" namespace ESM @@ -136,11 +134,6 @@ namespace MWClass virtual int getBaseFightRating(const MWWorld::Ptr &ptr) const; virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const; - - private: - - /// \return true if any of the indicated bits in Creature's mFlags is set - bool isFlagBitSet(const MWWorld::Ptr &ptr, ESM::Creature::Flags bitMask) const; }; } From d9a7986b3a654847be77826626d68bc5ba1b22c2 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 28 Aug 2015 18:04:22 -0500 Subject: [PATCH 327/419] Remove redundant fast forward check --- apps/openmw/mwworld/weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 52609f21a..da1f2f7e6 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -675,7 +675,7 @@ void WeatherManager::advanceTime(double hours, bool incremental) // In Morrowind, when the player sleeps/waits, serves jail time, travels, or trains, all weather transitions are // immediately applied, regardless of whatever transition time might have been remaining. mTimePassed += hours; - mFastForward = (!mFastForward && !incremental) ? true : mFastForward; + mFastForward = !incremental ? true : mFastForward; } unsigned int WeatherManager::getWeatherID() const From 2b48a20b76ef0ca85311bfce201477ea799b30d6 Mon Sep 17 00:00:00 2001 From: slothlife Date: Fri, 28 Aug 2015 23:12:39 -0500 Subject: [PATCH 328/419] Fix weather transition bugs --- apps/openmw/mwworld/weather.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index da1f2f7e6..e7c67d2e1 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -736,7 +736,7 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type) mWeatherUpdateTime = state.mWeatherUpdateTime; mTransitionFactor = state.mTransitionFactor; mCurrentWeather = state.mCurrentWeather; - mNextWeather = state.mCurrentWeather; + mNextWeather = state.mNextWeather; mQueuedWeather = state.mQueuedWeather; mRegions.clear(); @@ -884,6 +884,8 @@ inline void WeatherManager::updateWeatherTransitions(const float elapsedRealSeco mCurrentWeather = mNextWeather; } + mNextWeather = invalidWeatherID; + mQueuedWeather = invalidWeatherID; mFastForward = false; } } From 067779983986e91b226e9a3c8932094b2330d377 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 29 Aug 2015 17:21:18 +1200 Subject: [PATCH 329/419] movement logic in AiPackage uses ObstacleCheck. --- apps/openmw/mwmechanics/aipackage.cpp | 27 ++++++++++----------------- apps/openmw/mwmechanics/aipackage.hpp | 2 -- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 2c8c57c56..c18ee5ceb 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -19,7 +19,7 @@ MWMechanics::AiPackage::~AiPackage() {} -MWMechanics::AiPackage::AiPackage() : mTimer(0.26f), mStuckTimer(0) { //mTimer starts at .26 to force initial pathbuild +MWMechanics::AiPackage::AiPackage() : mTimer(0.26f) { //mTimer starts at .26 to force initial pathbuild } @@ -28,7 +28,6 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po { //Update various Timers mTimer += duration; //Update timer - mStuckTimer += duration; //Update stuck timer ESM::Position pos = actor.getRefData().getPosition(); //position of the actor @@ -91,11 +90,13 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po //************************ if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1])) //Path finished? return true; - else if(mStuckTimer>0.5) //Every half second see if we need to take action to avoid something + else { -/// TODO (tluppi#1#): Use ObstacleCheck here. Not working for some reason - //if(mObstacleCheck.check(actor, duration)) { - if(distance(start, mStuckPos.pos[0], mStuckPos.pos[1], mStuckPos.pos[2]) < actor.getClass().getSpeed(actor)*0.05 && distance(dest, start) > 20) { //Actually stuck, and far enough away from destination to care + zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); + + MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor); + if(mObstacleCheck.check(actor, duration)) + { // first check if we're walking into a door MWWorld::Ptr door = getNearbyDoor(actor); if(door != MWWorld::Ptr()) // NOTE: checks interior cells only @@ -106,24 +107,16 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po } else // probably walking into another NPC { - actor.getClass().getMovementSettings(actor).mPosition[0] = 1; - actor.getClass().getMovementSettings(actor).mPosition[1] = 1; + movement.mPosition[0] = 1; + movement.mPosition[1] = 1; // change the angle a bit, too zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])); } } else { //Not stuck, so reset things - mStuckTimer = 0; - mStuckPos = pos; - actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward + movement.mPosition[1] = 1; //Just run forward } } - else { - actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward the rest of the time - } - - zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); - return false; } diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index d73833b94..00cab2d08 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -83,9 +83,7 @@ namespace MWMechanics ObstacleCheck mObstacleCheck; float mTimer; - float mStuckTimer; - ESM::Position mStuckPos; ESM::Pathgrid::Point mPrevDest; }; } From f59e918a3b697e119a224b86c7ac2edd591e978f Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 29 Aug 2015 17:34:33 +1200 Subject: [PATCH 330/419] removed useless code. zTurn ignores turns < 0.0087 radians. --- apps/openmw/mwmechanics/aipackage.cpp | 2 -- apps/openmw/mwmechanics/aiwander.cpp | 3 --- 2 files changed, 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index c18ee5ceb..36843663e 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -109,8 +109,6 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po { movement.mPosition[0] = 1; movement.mPosition[1] = 1; - // change the angle a bit, too - zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])); } } else { //Not stuck, so reset things diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 8f27a2048..01d8125b3 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -437,9 +437,6 @@ namespace MWMechanics // but doesn't seem to do that? actor.getClass().getMovementSettings(actor).mPosition[0] = 1; actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; - // change the angle a bit, too - const ESM::Position& pos = actor.getRefData().getPosition(); - zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])); } mStuckCount++; // TODO: maybe no longer needed } From 31d82b6b0c09a9e1cf2296fc46a2c40bdaf10627 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 30 Aug 2015 08:32:47 +1200 Subject: [PATCH 331/419] Unifiy evadeObstacles() logic between AiWander and AiPackage Can't use same code, but logic is now same. --- apps/openmw/mwmechanics/aipackage.cpp | 49 +++++++++++++++------------ apps/openmw/mwmechanics/aipackage.hpp | 4 +++ apps/openmw/mwmechanics/aiwander.cpp | 20 ++++++----- apps/openmw/mwmechanics/aiwander.hpp | 2 +- 4 files changed, 44 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 36843663e..097cc4042 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -92,32 +92,37 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po return true; else { - zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); - - MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor); - if(mObstacleCheck.check(actor, duration)) - { - // first check if we're walking into a door - MWWorld::Ptr door = getNearbyDoor(actor); - if(door != MWWorld::Ptr()) // NOTE: checks interior cells only - { - if(!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty() && door.getClass().getDoorState(door) == 0) { //Open the door if untrapped - MWBase::Environment::get().getWorld()->activateDoor(door, 1); - } - } - else // probably walking into another NPC - { - movement.mPosition[0] = 1; - movement.mPosition[1] = 1; - } - } - else { //Not stuck, so reset things - movement.mPosition[1] = 1; //Just run forward - } + evadeObstacles(actor, duration, pos); } return false; } +void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos) +{ + zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); + + MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor); + if (mObstacleCheck.check(actor, duration)) + { + // first check if we're walking into a door + MWWorld::Ptr door = getNearbyDoor(actor); + if (door != MWWorld::Ptr()) // NOTE: checks interior cells only + { + if (!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty() && door.getClass().getDoorState(door) == 0) { //Open the door if untrapped + MWBase::Environment::get().getWorld()->activateDoor(door, 1); + } + } + else // probably walking into another NPC + { + movement.mPosition[0] = 1; + movement.mPosition[1] = 1; + } + } + else { //Not stuck, so reset things + movement.mPosition[1] = 1; //Just run forward + } +} + bool MWMechanics::AiPackage::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell) { return distance(mPrevDest, dest) > 10; diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 00cab2d08..4f919edbc 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -85,6 +85,10 @@ namespace MWMechanics float mTimer; ESM::Pathgrid::Point mPrevDest; + + private: + void evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos); + }; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 01d8125b3..ce70fee77 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -381,11 +381,7 @@ namespace MWMechanics else { // have not yet reached the destination - //... turn towards the next point in mPath - zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); - actor.getClass().getMovementSettings(actor).mPosition[1] = 1; - - evadeObstacles(actor, storage, duration); + evadeObstacles(actor, storage, duration, pos); } } @@ -417,8 +413,12 @@ namespace MWMechanics storage.mState = Wander_IdleNow; } - void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos) { + // turn towards the next point in mPath + zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); + + MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor); if (mObstacleCheck.check(actor, duration)) { // first check if we're walking into a door @@ -435,11 +435,15 @@ namespace MWMechanics { // TODO: diagonal should have same animation as walk forward // but doesn't seem to do that? - actor.getClass().getMovementSettings(actor).mPosition[0] = 1; - actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; + movement.mPosition[0] = 1; + movement.mPosition[1] = 0.1f; } mStuckCount++; // TODO: maybe no longer needed } + else + { + movement.mPosition[1] = 1; + } //#if 0 // TODO: maybe no longer needed if (mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 27e6fe9fb..b0fabfce3 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -83,7 +83,7 @@ namespace MWMechanics short unsigned getRandomIdle(); void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); - void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); + void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos); void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); From f2c9b9351f702d18e8ca3e2fcb97d640780fa8bf Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 30 Aug 2015 10:06:09 +1200 Subject: [PATCH 332/419] Try going right and left to "unstick" actor. --- apps/openmw/mwmechanics/aipackage.cpp | 3 +-- apps/openmw/mwmechanics/aiwander.cpp | 3 +-- apps/openmw/mwmechanics/obstacle.cpp | 20 ++++++++++++++++++++ apps/openmw/mwmechanics/obstacle.hpp | 8 ++++++++ 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 097cc4042..b6b240833 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -114,8 +114,7 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur } else // probably walking into another NPC { - movement.mPosition[0] = 1; - movement.mPosition[1] = 1; + mObstacleCheck.takeEvasiveAction(movement); } } else { //Not stuck, so reset things diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index ce70fee77..67a9f766c 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -435,8 +435,7 @@ namespace MWMechanics { // TODO: diagonal should have same animation as walk forward // but doesn't seem to do that? - movement.mPosition[0] = 1; - movement.mPosition[1] = 0.1f; + mObstacleCheck.takeEvasiveAction(movement); } mStuckCount++; // TODO: maybe no longer needed } diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 25bd06301..fe3d68a58 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -6,6 +6,8 @@ #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" +#include "movement.hpp" + namespace MWMechanics { // NOTE: determined empirically but probably need further tweaking @@ -67,6 +69,7 @@ namespace MWMechanics , mStuckDuration(0) , mEvadeDuration(0) , mDistSameSpot(-1) // avoid calculating it each time + , mEvadeDirection(1.0f) { } @@ -155,6 +158,7 @@ namespace MWMechanics /* FALL THROUGH */ case State_Evade: { + chooseEvasionDirection(samePosition); mEvadeDuration += duration; if(mEvadeDuration < DURATION_TO_EVADE) return true; @@ -169,4 +173,20 @@ namespace MWMechanics } return false; // no obstacles to evade (yet) } + + void ObstacleCheck::takeEvasiveAction(MWMechanics::Movement& actorMovement) + { + actorMovement.mPosition[0] = mEvadeDirection; + actorMovement.mPosition[1] = 0; + } + + void ObstacleCheck::chooseEvasionDirection(bool samePosition) + { + // change direction if attempt didn't work + if (samePosition && (0 < mEvadeDuration)) + { + mEvadeDirection = mEvadeDirection == 1.0f ? -1.0f : 1.0f; + } + } + } diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index e0ae9203d..ef3e29e8b 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -8,6 +8,8 @@ namespace MWWorld namespace MWMechanics { + struct Movement; + /// NOTE: determined empirically based on in-game behaviour static const float MIN_DIST_TO_DOOR_SQUARED = 128*128; @@ -36,6 +38,9 @@ namespace MWMechanics // should be taken bool check(const MWWorld::Ptr& actor, float duration); + // change direction to try to fix "stuck" actor + void takeEvasiveAction(MWMechanics::Movement& actorMovement); + private: // for checking if we're stuck (ignoring Z axis) @@ -53,6 +58,9 @@ namespace MWMechanics float mStuckDuration; // accumulate time here while in same spot float mEvadeDuration; float mDistSameSpot; // take account of actor's speed + float mEvadeDirection; + + void chooseEvasionDirection(bool samePosition); }; } From 39c2ba8efe98aa4d9f29f06450a62f2081d372c9 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 30 Aug 2015 16:12:51 +1200 Subject: [PATCH 333/419] Pathfinding bugfix. Observed at Ebonheart (coe 1, -13). Especially at the western tower. Guards try to walk though tower door. Cause: buildPath() adds destination (even when unreachable) when only using single node from pathgrid. --- apps/openmw/mwmechanics/pathfinding.cpp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f53badbf4..daab32136 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -225,19 +225,16 @@ namespace MWMechanics ESM::Pathgrid::Point temp(mPathgrid->mPoints[startNode]); converter.ToWorld(temp); mPath.push_back(temp); - - mPath.push_back(endPoint); - return; } - - mPath = mCell->aStarSearch(startNode, endNode.first); - if (mPath.empty()) - return; - - // convert supplied path to world co-ordinates - for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) + else { - converter.ToWorld(*iter); + mPath = mCell->aStarSearch(startNode, endNode.first); + + // convert supplied path to world co-ordinates + for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) + { + converter.ToWorld(*iter); + } } // If endNode found is NOT the closest PathGrid point to the endPoint, @@ -254,8 +251,6 @@ namespace MWMechanics // The AI routines will have to deal with such situations. if(endNode.second) mPath.push_back(endPoint); - - return; } float PathFinder::getZAngleToNext(float x, float y) const From 1dfe438a5d37401b75bd2de491a2524cc92ffd21 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 30 Aug 2015 16:43:35 +1200 Subject: [PATCH 334/419] reduce "reset if stuck" AiWander timeout. Now is about 14 seconds, instead of 300. --- apps/openmw/mwmechanics/aiwander.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 67a9f766c..b789c4428 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -27,7 +27,7 @@ namespace MWMechanics { - static const int COUNT_BEFORE_RESET = 200; // TODO: maybe no longer needed + static const int COUNT_BEFORE_RESET = 10; static const float DOOR_CHECK_INTERVAL = 1.5f; static const float REACTION_INTERVAL = 0.25f; static const int GREETING_SHOULD_START = 4; //how many reaction intervals should pass before NPC can greet player @@ -443,8 +443,8 @@ namespace MWMechanics { movement.mPosition[1] = 1; } -//#if 0 - // TODO: maybe no longer needed + + // if stuck for sufficiently long, act like current location was the destination if (mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset { //std::cout << "Reset \""<< cls.getName(actor) << "\"" << std::endl; @@ -454,7 +454,6 @@ namespace MWMechanics storage.mState = Wander_ChooseAction; mStuckCount = 0; } -//#endif } void AiWander::playIdleDialogueRandomly(const MWWorld::Ptr& actor) From b7983d08ba3f238f0cddad467049c87b17a3745f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 30 Aug 2015 11:08:56 +0200 Subject: [PATCH 335/419] fixed merge stage order; added proper initialisation --- apps/opencs/model/tools/mergeoperation.cpp | 5 ++++- apps/opencs/model/tools/mergestages.cpp | 17 +++++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 15 +++++++++++++++ apps/opencs/model/tools/mergestate.hpp | 2 ++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index f9a89aaa1..89f22ef1a 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -9,7 +9,8 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::FromType encoding) : CSMDoc::Operation (CSMDoc::State_Merging, true), mState (document) { - appendStage (new FinishMergedDocumentStage (mState, encoding)); + appendStage (new StartMergeStage (mState)); + appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getGlobals)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getGmsts)); appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getSkills)); @@ -37,6 +38,8 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeRefIdsStage (mState)); appendStage (new MergeReferencesStage (mState)); + appendStage (new FinishMergedDocumentStage (mState, encoding)); + /// \todo Land, LandTextures } diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 80f16ec14..349cc2925 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -8,6 +8,23 @@ #include "../doc/document.hpp" #include "../world/data.hpp" + +CSMTools::StartMergeStage::StartMergeStage (MergeState& state) +: mState (state) +{} + +int CSMTools::StartMergeStage::setup() +{ + return 1; +} + +void CSMTools::StartMergeStage::perform (int stage, CSMDoc::Messages& messages) +{ + mState.mCompleted = false; + mState.mTextureIndices.clear(); +} + + CSMTools::FinishMergedDocumentStage::FinishMergedDocumentStage (MergeState& state, ToUTF8::FromType encoding) : mState (state), mEncoder (encoding) {} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index e1cc17a3e..7d62058f0 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -14,6 +14,21 @@ namespace CSMTools { + class StartMergeStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + StartMergeStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + class FinishMergedDocumentStage : public CSMDoc::Stage { MergeState& mState; diff --git a/apps/opencs/model/tools/mergestate.hpp b/apps/opencs/model/tools/mergestate.hpp index 4482ba6f4..077edc9d9 100644 --- a/apps/opencs/model/tools/mergestate.hpp +++ b/apps/opencs/model/tools/mergestate.hpp @@ -2,6 +2,7 @@ #define CSM_TOOLS_MERGESTATE_H #include +#include #include "../doc/document.hpp" @@ -12,6 +13,7 @@ namespace CSMTools std::auto_ptr mTarget; CSMDoc::Document& mSource; bool mCompleted; + std::map, int> mTextureIndices; // (texture, content file) -> new texture MergeState (CSMDoc::Document& source) : mSource (source), mCompleted (false) {} }; From 890bbb6b119bab1b9a7b5724ab3e6a769ede761a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 30 Aug 2015 14:27:22 +0200 Subject: [PATCH 336/419] merge land texture tables --- apps/opencs/model/tools/mergeoperation.cpp | 5 +- apps/opencs/model/tools/mergestages.cpp | 79 ++++++++++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 31 +++++++++ apps/opencs/model/tools/mergestate.hpp | 4 +- apps/opencs/model/world/data.cpp | 5 ++ apps/opencs/model/world/data.hpp | 2 + 6 files changed, 124 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 89f22ef1a..9e791683c 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -37,10 +37,13 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeIdCollectionStage (mState, &CSMWorld::Data::getJournalInfos)); appendStage (new MergeRefIdsStage (mState)); appendStage (new MergeReferencesStage (mState)); + appendStage (new MergeReferencesStage (mState)); + appendStage (new ListLandTexturesMergeStage (mState)); + appendStage (new MergeLandTexturesStage (mState)); appendStage (new FinishMergedDocumentStage (mState, encoding)); - /// \todo Land, LandTextures + /// \todo Land } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 349cc2925..f34ba8eb4 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -1,6 +1,8 @@ #include "mergestages.hpp" +#include + #include #include "mergestate.hpp" @@ -104,3 +106,80 @@ void CSMTools::MergeReferencesStage::perform (int stage, CSMDoc::Messages& messa mState.mTarget->getData().getReferences().appendRecord (newRecord); } } + + +CSMTools::ListLandTexturesMergeStage::ListLandTexturesMergeStage (MergeState& state) +: mState (state) +{} + +int CSMTools::ListLandTexturesMergeStage::setup() +{ + return mState.mSource.getData().getLand().getSize(); +} + +void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages) +{ + const CSMWorld::Record& record = + mState.mSource.getData().getLand().getRecord (stage); + + if (!record.isDeleted()) + { + ESM::Land& land = *record.get().mLand; + + // make sure record is loaded + land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | + ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); + + if (land.mLandData) + { + // list texture indices + std::pair key; + key.second = land.mPlugin; + + for (int i=0; imTextures[i]; + + mState.mTextureIndices[key] = -1; + } + } + } +} + + +CSMTools::MergeLandTexturesStage::MergeLandTexturesStage (MergeState& state) +: mState (state), mNext (mState.mTextureIndices.end()) +{} + +int CSMTools::MergeLandTexturesStage::setup() +{ + mNext = mState.mTextureIndices.begin(); + return mState.mTextureIndices.size(); +} + +void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& messages) +{ + mNext->second = stage; + + std::ostringstream stream; + stream << mNext->first.first << "_" << mNext->first.second; + + int index = mState.mSource.getData().getLandTextures().searchId (stream.str()); + + if (index!=-1) + { + CSMWorld::LandTexture texture = + mState.mSource.getData().getLandTextures().getRecord (index).get(); + + texture.mIndex = mNext->second; + texture.mId = stream.str(); + + CSMWorld::Record newRecord ( + CSMWorld::RecordBase::State_ModifiedOnly, 0, &texture); + + mState.mTarget->getData().getLandTextures().appendRecord (newRecord); + } + /// \todo deal with missing textures (either abort merge or report and make sure OpenMW can deal with missing textures) + + ++mNext; +} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 7d62058f0..f0ae99842 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -115,6 +115,37 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. }; + + class ListLandTexturesMergeStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + ListLandTexturesMergeStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + + class MergeLandTexturesStage : public CSMDoc::Stage + { + MergeState& mState; + std::map, int>::iterator mNext; + + public: + + MergeLandTexturesStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; } #endif diff --git a/apps/opencs/model/tools/mergestate.hpp b/apps/opencs/model/tools/mergestate.hpp index 077edc9d9..29e1bbda7 100644 --- a/apps/opencs/model/tools/mergestate.hpp +++ b/apps/opencs/model/tools/mergestate.hpp @@ -1,6 +1,8 @@ #ifndef CSM_TOOLS_MERGESTATE_H #define CSM_TOOLS_MERGESTATE_H +#include + #include #include @@ -13,7 +15,7 @@ namespace CSMTools std::auto_ptr mTarget; CSMDoc::Document& mSource; bool mCompleted; - std::map, int> mTextureIndices; // (texture, content file) -> new texture + std::map, int> mTextureIndices; // (texture, content file) -> new texture MergeState (CSMDoc::Document& source) : mSource (source), mCompleted (false) {} }; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index d8999d950..c12827b53 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -778,6 +778,11 @@ const CSMWorld::IdCollection& CSMWorld::Data::getLandText return mLandTextures; } +CSMWorld::IdCollection& CSMWorld::Data::getLandTextures() +{ + return mLandTextures; +} + const CSMWorld::IdCollection& CSMWorld::Data::getSoundGens() const { return mSoundGens; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 5706b005b..9a41ead42 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -234,6 +234,8 @@ namespace CSMWorld const IdCollection& getLandTextures() const; + IdCollection& getLandTextures(); + const IdCollection& getSoundGens() const; IdCollection& getSoundGens(); From 8aaba0af6fac116f09092bbc1f88241988b7706e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 30 Aug 2015 17:38:21 +0200 Subject: [PATCH 337/419] Fix journal page navigation bug introduced by 7dd09dd637c317d3d94 (Fixes #2899) --- apps/openmw/mwgui/journalwindow.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 8238f6585..b6f72a04c 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -356,6 +356,8 @@ namespace setVisible (OptionsOverlay, false); setVisible (OptionsBTN, true); setVisible (JournalBTN, true); + + mOptionsMode = false; } void notifyTopicSelected (const std::string& topic, int id) @@ -383,6 +385,8 @@ namespace setVisible (OptionsOverlay, false); setVisible (OptionsBTN, true); setVisible (JournalBTN, true); + + mOptionsMode = false; } void notifyOptions(MyGUI::Widget* _sender) From cda8a88f0d9a9fb5f12e3a39f683b2a874e4e9e2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 30 Aug 2015 20:00:37 +0200 Subject: [PATCH 338/419] Use DEEP_COPY_PRIMITIVES to work around problem in osg::Geometry copy constructor (Bug #2754) --- components/sceneutil/clone.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 36c5c02a1..74eae0b6b 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -52,6 +52,32 @@ namespace SceneUtil { osg::CopyOp copyop = *this; copyop.setCopyFlags(copyop.getCopyFlags()|osg::CopyOp::DEEP_COPY_ARRAYS); + + /* + + Deep copy of primitives required to work around the following (bad?) code in osg::Geometry copy constructor: + + if ((copyop.getCopyFlags() & osg::CopyOp::DEEP_COPY_ARRAYS)) + { + if (_useVertexBufferObjects) + { + // copying of arrays doesn't set up buffer objects so we'll need to force + // Geometry to assign these, we'll do this by switching off VBO's then renabling them. + setUseVertexBufferObjects(false); + setUseVertexBufferObjects(true); + } + } + + In case of DEEP_COPY_PRIMITIVES=Off, DEEP_COPY_ARRAYS=On, the above code makes a modification to the original const Geometry& we copied from, + causing problems if we relied on the original Geometry to remain static such as when it was added to an osgUtil::IncrementalCompileOperation. + + TODO: report/fix in upstream OSG + + */ + + copyop.setCopyFlags(copyop.getCopyFlags()|osg::CopyOp::DEEP_COPY_PRIMITIVES); + + osg::Drawable* cloned = osg::clone(drawable, copyop); if (cloned->getUpdateCallback()) cloned->setUpdateCallback(osg::clone(cloned->getUpdateCallback(), *this)); From e9acd135a6a405f88f2f3ab896cdac7eade31f04 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 30 Aug 2015 20:43:39 +0200 Subject: [PATCH 339/419] Update todo comment --- components/sceneutil/clone.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 74eae0b6b..e4b4f63bb 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -71,7 +71,7 @@ namespace SceneUtil In case of DEEP_COPY_PRIMITIVES=Off, DEEP_COPY_ARRAYS=On, the above code makes a modification to the original const Geometry& we copied from, causing problems if we relied on the original Geometry to remain static such as when it was added to an osgUtil::IncrementalCompileOperation. - TODO: report/fix in upstream OSG + Possible fix submitted to osg-submissions ( http://forum.openscenegraph.org/viewtopic.php?t=15217 ). */ From b0641934d4a34b4e462932aa715cc0ca9d854cae Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 11:06:32 +0200 Subject: [PATCH 340/419] added copy constructor and assignment operator for Land record struct --- components/esm/loadland.cpp | 27 +++++++++++++++++++++++++++ components/esm/loadland.hpp | 8 ++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index b0897ec67..baeca34de 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -1,5 +1,7 @@ #include "loadland.hpp" +#include + #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" @@ -215,4 +217,29 @@ bool Land::isDataLoaded(int flags) const return (mDataLoaded & flags) == (flags & mDataTypes); } + Land::Land (const Land& land) + : mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin), + mEsm (land.mEsm), mContext (land.mContext), mDataTypes (land.mDataTypes), + mDataLoaded (land.mDataLoaded), + mLandData (land.mLandData ? new LandData (*land.mLandData) : 0) + {} + + Land& Land::operator= (Land land) + { + swap (land); + return *this; + } + + void Land::swap (Land& land) + { + std::swap (mFlags, land.mFlags); + std::swap (mX, land.mX); + std::swap (mY, land.mY); + std::swap (mPlugin, land.mPlugin); + std::swap (mEsm, land.mEsm); + std::swap (mContext, land.mContext); + std::swap (mDataTypes, land.mDataTypes); + std::swap (mDataLoaded, land.mDataLoaded); + std::swap (mLandData, land.mLandData); + } } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 61ce4855e..e010b170c 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -116,9 +116,13 @@ struct Land /// @note We only check data types that *can* be loaded (present in mDataTypes) bool isDataLoaded(int flags) const; + Land (const Land& land); + + Land& operator= (Land land); + + void swap (Land& land); + private: - Land(const Land& land); - Land& operator=(const Land& land); /// Loads data and marks it as loaded /// \return true if data is actually loaded from file, false otherwise From 69045d7ec9d293f2bb5626b2ac4a8517a0cf67e4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 11:10:58 +0200 Subject: [PATCH 341/419] additional safety check for land texture listing merge stage --- apps/opencs/model/tools/mergestages.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index f34ba8eb4..a4072e4bc 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -130,7 +130,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); - if (land.mLandData) + if (land.mLandData && land.mDataLoaded & ESM::Land::DATA_VTEX) { // list texture indices std::pair key; From febf611c827a257a4d4000b601f9ef413f2f8012 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 14:17:11 +0200 Subject: [PATCH 342/419] made return type of ESMTerrain::Storage::getLand const --- apps/opencs/view/render/terrainstorage.cpp | 2 +- apps/opencs/view/render/terrainstorage.hpp | 2 +- apps/openmw/mwrender/terrainstorage.cpp | 2 +- apps/openmw/mwrender/terrainstorage.hpp | 2 +- components/esmterrain/storage.cpp | 10 +++++----- components/esmterrain/storage.hpp | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index fe302cef1..a60678f88 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -9,7 +9,7 @@ namespace CSVRender { } - ESM::Land* TerrainStorage::getLand(int cellX, int cellY) + const ESM::Land* TerrainStorage::getLand(int cellX, int cellY) { std::ostringstream stream; stream << "#" << cellX << " " << cellY; diff --git a/apps/opencs/view/render/terrainstorage.hpp b/apps/opencs/view/render/terrainstorage.hpp index 97782ad17..16b0f3ec7 100644 --- a/apps/opencs/view/render/terrainstorage.hpp +++ b/apps/opencs/view/render/terrainstorage.hpp @@ -18,7 +18,7 @@ namespace CSVRender private: const CSMWorld::Data& mData; - virtual ESM::Land* getLand (int cellX, int cellY); + virtual const ESM::Land* getLand (int cellX, int cellY); virtual const ESM::LandTexture* getLandTexture(int index, short plugin); virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY); diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index 269e7f99f..f9a9083f0 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -51,7 +51,7 @@ namespace MWRender maxY += 1; } - ESM::Land* TerrainStorage::getLand(int cellX, int cellY) + const ESM::Land* TerrainStorage::getLand(int cellX, int cellY) { const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwrender/terrainstorage.hpp b/apps/openmw/mwrender/terrainstorage.hpp index 93531a552..a12ffd540 100644 --- a/apps/openmw/mwrender/terrainstorage.hpp +++ b/apps/openmw/mwrender/terrainstorage.hpp @@ -10,7 +10,7 @@ namespace MWRender class TerrainStorage : public ESMTerrain::Storage { private: - virtual ESM::Land* getLand (int cellX, int cellY); + virtual const ESM::Land* getLand (int cellX, int cellY); virtual const ESM::LandTexture* getLandTexture(int index, short plugin); public: diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 10b75bb74..5bc56a430 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -74,7 +74,7 @@ namespace ESMTerrain --cellX; row += ESM::Land::LAND_SIZE-1; } - ESM::Land* land = getLand(cellX, cellY); + const ESM::Land* land = getLand(cellX, cellY); if (land && land->mDataTypes&ESM::Land::DATA_VNML) { normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; @@ -109,7 +109,7 @@ namespace ESMTerrain ++cellX; row = 0; } - ESM::Land* land = getLand(cellX, cellY); + const ESM::Land* land = getLand(cellX, cellY); if (land && land->mDataTypes&ESM::Land::DATA_VCLR) { color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; @@ -158,7 +158,7 @@ namespace ESMTerrain float vertX_ = 0; // of current cell corner for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX) { - ESM::Land* land = getLand(cellX, cellY); + const ESM::Land* land = getLand(cellX, cellY); if (land && !(land->mDataTypes&ESM::Land::DATA_VHGT)) land = NULL; @@ -262,7 +262,7 @@ namespace ESMTerrain assert(xmDataTypes&ESM::Land::DATA_VTEX)) { int tex = land->mLandData->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x]; @@ -368,7 +368,7 @@ namespace ESMTerrain int cellX = static_cast(std::floor(worldPos.x() / 8192.f)); int cellY = static_cast(std::floor(worldPos.y() / 8192.f)); - ESM::Land* land = getLand(cellX, cellY); + const ESM::Land* land = getLand(cellX, cellY); if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) return -2048; diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index 8f4a3aa92..debbc59b9 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -21,7 +21,7 @@ namespace ESMTerrain private: // Not implemented in this class, because we need different Store implementations for game and editor - virtual ESM::Land* getLand (int cellX, int cellY) = 0; + virtual const ESM::Land* getLand (int cellX, int cellY) = 0; virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0; public: From b3fdf92d2b1b37a8c118ee5bdc1a2f6d6437a667 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 16:08:19 +0200 Subject: [PATCH 343/419] more const-ness fixes --- apps/openmw/mwphysics/physicssystem.cpp | 4 ++-- apps/openmw/mwphysics/physicssystem.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 2cb261851..23b3f051c 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -460,7 +460,7 @@ namespace MWPhysics class HeightField { public: - HeightField(float* heights, int x, int y, float triSize, float sqrtVerts) + HeightField(const float* heights, int x, int y, float triSize, float sqrtVerts) { // find the minimum and maximum heights (needed for bullet) float minh = heights[0]; @@ -927,7 +927,7 @@ namespace MWPhysics return MovementSolver::traceDown(ptr, found->second, mCollisionWorld, maxHeight); } - void PhysicsSystem::addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts) + void PhysicsSystem::addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts) { HeightField *heightfield = new HeightField(heights, x, y, triSize, sqrtVerts); mHeightFields[std::make_pair(x,y)] = heightfield; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index c3b22c385..ee9378ea4 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -71,7 +71,7 @@ namespace MWPhysics void updatePosition (const MWWorld::Ptr& ptr); - void addHeightField (float* heights, int x, int y, float triSize, float sqrtVerts); + void addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts); void removeHeightField (int x, int y); From 69b9eadb52cf24398d64b6399341d9e6b5d40bdf Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 16:13:26 +0200 Subject: [PATCH 344/419] refactored loading of land data --- apps/esmtool/record.cpp | 14 ++-- apps/opencs/model/doc/savingstages.cpp | 5 +- apps/opencs/model/tools/mergestages.cpp | 4 +- apps/openmw/mwrender/globalmap.cpp | 8 ++- apps/openmw/mwworld/scene.cpp | 6 +- components/esm/loadland.cpp | 22 ++++-- components/esm/loadland.hpp | 23 ++++-- components/esmterrain/storage.cpp | 93 ++++++++++++++----------- components/esmterrain/storage.hpp | 7 +- 9 files changed, 108 insertions(+), 74 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 2ee6c54bb..76c14e728 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -841,19 +841,13 @@ void Record::print() std::cout << " Flags: " << landFlags(mData.mFlags) << std::endl; std::cout << " DataTypes: " << mData.mDataTypes << std::endl; - // Seems like this should done with reference counting in the - // loader to me. But I'm not really knowledgable about this - // record type yet. --Cory - bool wasLoaded = (mData.mDataLoaded != 0); - if (mData.mDataTypes) mData.loadData(mData.mDataTypes); - if (mData.mDataLoaded) + if (const ESM::Land::LandData *data = mData.getLandData (mData.mDataTypes)) { - std::cout << " Height Offset: " << mData.mLandData->mHeightOffset << std::endl; + std::cout << " Height Offset: " << data->mHeightOffset << std::endl; // Lots of missing members. - std::cout << " Unknown1: " << mData.mLandData->mUnk1 << std::endl; - std::cout << " Unknown2: " << mData.mLandData->mUnk2 << std::endl; + std::cout << " Unknown1: " << data->mUnk1 << std::endl; + std::cout << " Unknown2: " << data->mUnk2 << std::endl; } - if (!wasLoaded) mData.unloadData(); } template<> diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index f78c57ecd..a21a28c99 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -421,8 +421,9 @@ void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) mState.getWriter().startRecord (record.mLand->sRecordId); record.mLand->save (mState.getWriter()); - if(record.mLand->mLandData) - record.mLand->mLandData->save (mState.getWriter()); + + if (const ESM::Land::LandData *data = record.mLand->getLandData (record.mLand->mDataTypes)) + data->save (mState.getWriter()); mState.getWriter().endRecord (record.mLand->sRecordId); } diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index a4072e4bc..5bf0241ac 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -130,7 +130,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); - if (land.mLandData && land.mDataLoaded & ESM::Land::DATA_VTEX) + if (const ESM::Land::LandData *data = land.getLandData (ESM::Land::DATA_VTEX)) { // list texture indices std::pair key; @@ -138,7 +138,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& for (int i=0; imTextures[i]; + key.first = data->mTextures[i]; mState.mTextureIndices[key] = -1; } diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 890c8444a..97a27ebbc 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -156,6 +156,9 @@ namespace MWRender land->loadData(mask); } + const ESM::Land::LandData *landData = + land ? land->getLandData (ESM::Land::DATA_WNAM) : 0; + for (int cellY=0; cellY(float(cellX)/float(mCellSize) * 9); int vertexY = static_cast(float(cellY) / float(mCellSize) * 9); - int texelX = (x-mMinX) * mCellSize + cellX; int texelY = (mHeight-1) - ((y-mMinY) * mCellSize + cellY); unsigned char r,g,b; float y = 0; - if (land && land->mDataTypes & ESM::Land::DATA_WNAM) - y = (land->mLandData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f; + if (landData) + y = (landData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f; else y = (SCHAR_MIN << 4) / 2048.f; if (y < 0) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 48e346c14..459b3b6ca 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -250,9 +250,9 @@ namespace MWWorld // Actually only VHGT is needed here, but we'll need the rest for rendering anyway. // Load everything now to reduce IO overhead. const int flags = ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX; - if (!land->isDataLoaded(flags)) - land->loadData(flags); - mPhysics->addHeightField (land->mLandData->mHeights, cell->getCell()->getGridX(), cell->getCell()->getGridY(), + + const ESM::Land::LandData *data = land->getLandData (flags); + mPhysics->addHeightField (data->mHeights, cell->getCell()->getGridX(), cell->getCell()->getGridY(), worldsize / (verts-1), verts); } } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index baeca34de..770830fdd 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -10,7 +10,7 @@ namespace ESM { unsigned int Land::sRecordId = REC_LAND; -void Land::LandData::save(ESMWriter &esm) +void Land::LandData::save(ESMWriter &esm) const { if (mDataTypes & Land::DATA_VNML) { esm.writeHNT("VNML", mNormals, sizeof(mNormals)); @@ -55,7 +55,7 @@ void Land::LandData::save(ESMWriter &esm) } } -void Land::LandData::transposeTextureData(uint16_t *in, uint16_t *out) +void Land::LandData::transposeTextureData(const uint16_t *in, uint16_t *out) { int readPos = 0; //bit ugly, but it works for ( int y1 = 0; y1 < 4; y1++ ) @@ -139,7 +139,7 @@ void Land::save(ESMWriter &esm) const esm.writeHNT("DATA", mFlags); } -void Land::loadData(int flags) +void Land::loadData(int flags) const { // Try to load only available data flags = flags & mDataTypes; @@ -201,7 +201,7 @@ void Land::unloadData() } } -bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size) +bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size) const { if ((mDataLoaded & dataFlag) == 0 && (flags & dataFlag) != 0) { mEsm->getHExact(ptr, size); @@ -242,4 +242,18 @@ bool Land::isDataLoaded(int flags) const std::swap (mDataLoaded, land.mDataLoaded); std::swap (mLandData, land.mLandData); } + + const Land::LandData *Land::getLandData (int flags) const + { + if (!(flags & mDataTypes)) + return 0; + + loadData (flags); + return mLandData; + } + + const Land::LandData *Land::getLandData() const + { + return mLandData; + } } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index e010b170c..64d131ecb 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -35,7 +35,6 @@ struct Land ESM_Context mContext; int mDataTypes; - int mDataLoaded; enum { @@ -91,12 +90,10 @@ struct Land short mUnk1; uint8_t mUnk2; - void save(ESMWriter &esm); - static void transposeTextureData(uint16_t *in, uint16_t *out); + void save(ESMWriter &esm) const; + static void transposeTextureData(const uint16_t *in, uint16_t *out); }; - LandData *mLandData; - void load(ESMReader &esm); void save(ESMWriter &esm) const; @@ -105,7 +102,7 @@ struct Land /** * Actually loads data */ - void loadData(int flags); + void loadData(int flags) const; /** * Frees memory allocated for land data @@ -122,12 +119,24 @@ struct Land void swap (Land& land); + /// Return land data with at least the data types specified in \a flags loaded (if they + /// are available). Will return a 0-pointer if there is no data for any of the + /// specified types. + const LandData *getLandData (int flags) const; + + /// Return land data without loading first anything. Can return a 0-pointer. + const LandData *getLandData() const; + private: /// Loads data and marks it as loaded /// \return true if data is actually loaded from file, false otherwise /// including the case when data is already loaded - bool condLoad(int flags, int dataFlag, void *ptr, unsigned int size); + bool condLoad(int flags, int dataFlag, void *ptr, unsigned int size) const; + + mutable int mDataLoaded; + + mutable LandData *mLandData; }; } diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 5bc56a430..ccfe6d9ee 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -18,6 +18,14 @@ namespace ESMTerrain { } + const ESM::Land::LandData *Storage::getLandData (int cellX, int cellY, int flags) + { + if (const ESM::Land *land = getLand (cellX, cellY)) + return land->getLandData (flags); + + return 0; + } + bool Storage::getMinMaxHeights(float size, const osg::Vec2f ¢er, float &min, float &max) { assert (size <= 1 && "Storage::getMinMaxHeights, chunk size should be <= 1 cell"); @@ -32,24 +40,25 @@ namespace ESMTerrain int cellX = static_cast(origin.x()); int cellY = static_cast(origin.y()); - const ESM::Land* land = getLand(cellX, cellY); - if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) - return false; - - min = std::numeric_limits::max(); - max = -std::numeric_limits::max(); - for (int row=0; row::max(); + max = -std::numeric_limits::max(); + for (int row=0; rowmLandData->mHeights[col*ESM::Land::LAND_SIZE+row]; - if (h > max) - max = h; - if (h < min) - min = h; + for (int col=0; colmHeights[col*ESM::Land::LAND_SIZE+row]; + if (h > max) + max = h; + if (h < min) + min = h; + } } + return true; } - return true; + + return false; } void Storage::fixNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row) @@ -74,12 +83,12 @@ namespace ESMTerrain --cellX; row += ESM::Land::LAND_SIZE-1; } - const ESM::Land* land = getLand(cellX, cellY); - if (land && land->mDataTypes&ESM::Land::DATA_VNML) + + if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VNML)) { - normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; - normal.y() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; - normal.z() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; + normal.x() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; + normal.y() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; + normal.z() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; normal.normalize(); } else @@ -109,12 +118,12 @@ namespace ESMTerrain ++cellX; row = 0; } - const ESM::Land* land = getLand(cellX, cellY); - if (land && land->mDataTypes&ESM::Land::DATA_VCLR) + + if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VCLR)) { - color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; - color.g() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; - color.b() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; + color.r() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; + color.g() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; + color.b() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; } else { @@ -158,9 +167,9 @@ namespace ESMTerrain float vertX_ = 0; // of current cell corner for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX) { - const ESM::Land* land = getLand(cellX, cellY); - if (land && !(land->mDataTypes&ESM::Land::DATA_VHGT)) - land = NULL; + const ESM::Land::LandData *heightData = getLandData (cellX, cellY, ESM::Land::DATA_VHGT); + const ESM::Land::LandData *normalData = getLandData (cellX, cellY, ESM::Land::DATA_VNML); + const ESM::Land::LandData *colourData = getLandData (cellX, cellY, ESM::Land::DATA_VCLR); int rowStart = 0; int colStart = 0; @@ -177,20 +186,22 @@ namespace ESMTerrain vertX = vertX_; for (int row=rowStart; rowmLandData->mHeights[col*ESM::Land::LAND_SIZE + row]; + if (heightData) + height = heightData->mHeights[col*ESM::Land::LAND_SIZE + row]; (*positions)[static_cast(vertX*numVerts + vertY)] = osg::Vec3f((vertX / float(numVerts - 1) - 0.5f) * size * 8192, (vertY / float(numVerts - 1) - 0.5f) * size * 8192, height); - if (land && land->mDataTypes&ESM::Land::DATA_VNML) + if (normalData) { - normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; - normal.y() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; - normal.z() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; + for (int i=0; i<3; ++i) + normal[i] = normalData->mNormals[arrayIndex+i]; + normal.normalize(); } else @@ -208,11 +219,10 @@ namespace ESMTerrain (*normals)[static_cast(vertX*numVerts + vertY)] = normal; - if (land && land->mDataTypes&ESM::Land::DATA_VCLR) + if (colourData) { - color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; - color.g() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; - color.b() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; + for (int i=0; i<3; ++i) + color[i] = colourData->mColours[arrayIndex+i] / 255.f; } else { @@ -262,13 +272,12 @@ namespace ESMTerrain assert(xmDataTypes&ESM::Land::DATA_VTEX)) + if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VTEX)) { - int tex = land->mLandData->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x]; + int tex = data->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x]; if (tex == 0) return std::make_pair(0,0); // vtex 0 is always the base texture, regardless of plugin - return std::make_pair(tex, land->mPlugin); + return std::make_pair(tex, getLand (cellX, cellY)->mPlugin); } else return std::make_pair(0,0); @@ -447,7 +456,7 @@ namespace ESMTerrain { assert(x < ESM::Land::LAND_SIZE); assert(y < ESM::Land::LAND_SIZE); - return land->mLandData->mHeights[y * ESM::Land::LAND_SIZE + x]; + return land->getLandData()->mHeights[y * ESM::Land::LAND_SIZE + x]; } Terrain::LayerInfo Storage::getLayerInfo(const std::string& texture) diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index debbc59b9..5b8ca953d 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -21,12 +21,17 @@ namespace ESMTerrain private: // Not implemented in this class, because we need different Store implementations for game and editor - virtual const ESM::Land* getLand (int cellX, int cellY) = 0; + virtual const ESM::Land* getLand (int cellX, int cellY)= 0; virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0; public: Storage(const VFS::Manager* vfs); + /// Data is loaded first, if necessary. Will return a 0-pointer if there is no data for + /// any of the data types specified via \a flags. Will also return a 0-pointer if there + /// is no land record for the coordinates \a cellX / \a cellY. + const ESM::Land::LandData *getLandData (int cellX, int cellY, int flags); + // Not implemented in this class, because we need different Store implementations for game and editor /// Get bounds of the whole terrain in cell units virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY) = 0; From 85f6bb892b7f61b95d297efcf67cfccaee134e54 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 31 Aug 2015 18:13:27 +0200 Subject: [PATCH 345/419] removed indirection in OpenMW-CS land record --- apps/opencs/model/doc/savingstages.cpp | 10 +++++----- apps/opencs/model/tools/mergestages.cpp | 2 +- apps/opencs/model/world/data.cpp | 7 ++++++- apps/opencs/model/world/data.hpp | 2 ++ apps/opencs/model/world/land.cpp | 16 ++-------------- apps/opencs/model/world/land.hpp | 10 ++-------- apps/opencs/view/render/cell.cpp | 15 ++++++++------- apps/opencs/view/render/terrainstorage.cpp | 7 +++---- 8 files changed, 29 insertions(+), 40 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index a21a28c99..894c479a4 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -416,16 +416,16 @@ void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) if (land.mState==CSMWorld::RecordBase::State_Modified || land.mState==CSMWorld::RecordBase::State_ModifiedOnly) { - CSMWorld::Land record = land.get(); + const CSMWorld::Land& record = land.get(); - mState.getWriter().startRecord (record.mLand->sRecordId); + mState.getWriter().startRecord (record.sRecordId); - record.mLand->save (mState.getWriter()); + record.save (mState.getWriter()); - if (const ESM::Land::LandData *data = record.mLand->getLandData (record.mLand->mDataTypes)) + if (const ESM::Land::LandData *data = record.getLandData (record.mDataTypes)) data->save (mState.getWriter()); - mState.getWriter().endRecord (record.mLand->sRecordId); + mState.getWriter().endRecord (record.sRecordId); } else if (land.mState==CSMWorld::RecordBase::State_Deleted) { diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 5bf0241ac..c624ff548 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -124,7 +124,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& if (!record.isDeleted()) { - ESM::Land& land = *record.get().mLand; + const ESM::Land& land = record.get(); // make sure record is loaded land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c12827b53..fe6d6ccbb 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -773,6 +773,11 @@ const CSMWorld::IdCollection& CSMWorld::Data::getLand() const return mLand; } +CSMWorld::IdCollection& CSMWorld::Data::getLand() +{ + return mLand; +} + const CSMWorld::IdCollection& CSMWorld::Data::getLandTextures() const { return mLandTextures; @@ -951,7 +956,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) int index = mLand.load(*mReader, mBase); if (index!=-1 && !mBase) - mLand.getRecord (index).mModified.mLand->loadData ( + mLand.getRecord (index).mModified.loadData ( ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 9a41ead42..c6623279a 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -232,6 +232,8 @@ namespace CSMWorld const IdCollection& getLand() const; + IdCollection& getLand(); + const IdCollection& getLandTextures() const; IdCollection& getLandTextures(); diff --git a/apps/opencs/model/world/land.cpp b/apps/opencs/model/world/land.cpp index 119e18761..222f9bc02 100644 --- a/apps/opencs/model/world/land.cpp +++ b/apps/opencs/model/world/land.cpp @@ -4,25 +4,13 @@ namespace CSMWorld { - - Land::Land() - { - mLand.reset(new ESM::Land()); - } - void Land::load(ESM::ESMReader &esm) { - mLand->load(esm); + ESM::Land::load(esm); std::ostringstream stream; - stream << "#" << mLand->mX << " " << mLand->mY; + stream << "#" << mX << " " << mY; mId = stream.str(); } - - void Land::blank() - { - /// \todo - } - } diff --git a/apps/opencs/model/world/land.hpp b/apps/opencs/model/world/land.hpp index e97a2d7dd..22cedb56d 100644 --- a/apps/opencs/model/world/land.hpp +++ b/apps/opencs/model/world/land.hpp @@ -2,7 +2,7 @@ #define CSM_WORLD_LAND_H #include -#include + #include namespace CSMWorld @@ -11,18 +11,12 @@ namespace CSMWorld /// /// \todo Add worldspace support to the Land record. /// \todo Add a proper copy constructor (currently worked around using shared_ptr) - struct Land + struct Land : public ESM::Land { - Land(); - - boost::shared_ptr mLand; - std::string mId; /// Loads the metadata and ID void load (ESM::ESMReader &esm); - - void blank(); }; } diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index fe2eab066..4425c193f 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -32,7 +32,7 @@ bool CSVRender::Cell::addObjects (int start, int end) bool modified = false; const CSMWorld::RefCollection& collection = mData.getReferences(); - + for (int i=start; i<=end; ++i) { std::string cell = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mCell); @@ -68,15 +68,16 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st int landIndex = land.searchId(mId); if (landIndex != -1) { - const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); - if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT) + const ESM::Land& esmLand = land.getRecord(mId).get(); + + if (esmLand.getLandData (ESM::Land::DATA_VHGT)) { mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Element_Terrain<<1)); - mTerrain->loadCell(esmLand->mX, - esmLand->mY); + mTerrain->loadCell(esmLand.mX, + esmLand.mY); - mX = esmLand->mX; - mY = esmLand->mY; + mX = esmLand.mX; + mY = esmLand.mY; } } } diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index a60678f88..b5b144fe4 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -20,11 +20,10 @@ namespace CSVRender if (index == -1) return NULL; - ESM::Land* land = mData.getLand().getRecord(index).get().mLand.get(); + const ESM::Land& land = mData.getLand().getRecord(index).get(); int mask = ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX; - if (!land->isDataLoaded(mask)) - land->loadData(mask); - return land; + land.loadData (mask); + return &land; } const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin) From a8dc1c119859abd0ad4cf16765abbf1f70fe6013 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 3 Sep 2015 16:15:00 +0200 Subject: [PATCH 346/419] merge land tables --- apps/opencs/model/tools/mergeoperation.cpp | 3 +- apps/opencs/model/tools/mergestages.cpp | 64 +++++++++++++++++++++- apps/opencs/model/tools/mergestages.hpp | 15 +++++ components/esm/loadland.cpp | 26 +++++++++ components/esm/loadland.hpp | 11 ++++ 5 files changed, 115 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 9e791683c..907d742ed 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -40,10 +40,9 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeReferencesStage (mState)); appendStage (new ListLandTexturesMergeStage (mState)); appendStage (new MergeLandTexturesStage (mState)); + appendStage (new MergeLandStage (mState)); appendStage (new FinishMergedDocumentStage (mState, encoding)); - - /// \todo Land } void CSMTools::MergeOperation::setTarget (std::auto_ptr document) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index c624ff548..f4cb42aa4 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -153,12 +153,20 @@ CSMTools::MergeLandTexturesStage::MergeLandTexturesStage (MergeState& state) int CSMTools::MergeLandTexturesStage::setup() { - mNext = mState.mTextureIndices.begin(); - return mState.mTextureIndices.size(); + // Should use the size of mState.mTextureIndices instead, but that is not available at this + // point. Unless there are any errors in the land and land texture records this will not + // make a difference. + return mState.mSource.getData().getLandTextures().getSize(); } void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& messages) { + if (stage==0) + mNext = mState.mTextureIndices.begin(); + + if (mNext==mState.mTextureIndices.end()) + return; + mNext->second = stage; std::ostringstream stream; @@ -183,3 +191,55 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes ++mNext; } + + +CSMTools::MergeLandStage::MergeLandStage (MergeState& state) : mState (state) {} + +int CSMTools::MergeLandStage::setup() +{ + return mState.mSource.getData().getLand().getSize(); +} + +void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages) +{ + const CSMWorld::Record& record = + mState.mSource.getData().getLand().getRecord (stage); + + if (!record.isDeleted()) + { + const CSMWorld::Land& land = record.get(); + + land.loadData (ESM::Land::DATA_VCLR | ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | + ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); + + CSMWorld::Land newLand (land); + + newLand.mEsm = 0; // avoid potential dangling pointer (ESMReader isn't needed anyway, + // because record is already fully loaded) + newLand.mPlugin = 0; + + // adjust land texture references + if (ESM::Land::LandData *data = newLand.getLandData()) + { + std::pair key; + key.second = land.mPlugin; + + for (int i=0; imTextures[i]; + std::map, int>::const_iterator iter = + mState.mTextureIndices.find (key); + + if (iter!=mState.mTextureIndices.end()) + data->mTextures[i] = iter->second; + else + data->mTextures[i] = 0; + } + } + + CSMWorld::Record newRecord ( + CSMWorld::RecordBase::State_ModifiedOnly, 0, &newLand); + + mState.mTarget->getData().getLand().appendRecord (newRecord); + } +} diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index f0ae99842..f88f5be9f 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -146,6 +146,21 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. }; + + class MergeLandStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + MergeLandStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; } #endif diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 770830fdd..784cfd407 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -256,4 +256,30 @@ bool Land::isDataLoaded(int flags) const { return mLandData; } + + Land::LandData *Land::getLandData() + { + return mLandData; + } + + void Land::add (int flags) + { + if (!mLandData) + mLandData = new LandData; + + mDataTypes |= flags; + mDataLoaded |= flags; + } + + void Land::remove (int flags) + { + mDataTypes &= ~flags; + mDataLoaded &= ~flags; + + if (!mDataLoaded) + { + delete mLandData; + mLandData = 0; + } + } } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 64d131ecb..56267a28c 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -127,6 +127,17 @@ struct Land /// Return land data without loading first anything. Can return a 0-pointer. const LandData *getLandData() const; + /// Return land data without loading first anything. Can return a 0-pointer. + LandData *getLandData(); + + /// \attention Must not be called on objects that aren't fully loaded. + /// + /// \note Added data fields will be uninitialised + void add (int flags); + + /// \attention Must not be called on objects that aren't fully loaded. + void remove (int flags); + private: /// Loads data and marks it as loaded From d11952c48a7f2055b1bba79bd06c5180d15411d8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Sep 2015 03:44:14 +0200 Subject: [PATCH 347/419] Stop rendering when the window is minimized --- apps/openmw/engine.cpp | 22 +++++++++++++++------- apps/openmw/mwbase/inputmanager.hpp | 2 ++ apps/openmw/mwinput/inputmanagerimp.cpp | 8 +++++++- apps/openmw/mwinput/inputmanagerimp.hpp | 3 +++ 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 32ff20ba7..6801363b1 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -92,10 +92,11 @@ void OMW::Engine::frame(float frametime) // update input mEnvironment.getInputManager()->update(frametime, false); - // When the window is minimized, pause everything. Currently this *has* to be here to work around a MyGUI bug. - // If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures. - //if (!mOgre->getWindow()->isActive() || !mOgre->getWindow()->isVisible()) - // return true; + // When the window is minimized, pause the game. Currently this *has* to be here to work around a MyGUI bug. + // If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures (fixed in MyGUI 3.3.2), + // and destroyed widgets will not be deleted (not fixed yet, https://github.com/MyGUI/mygui/issues/21) + if (!mEnvironment.getInputManager()->isWindowVisible()) + return; // sound if (mUseSound) @@ -689,9 +690,16 @@ void OMW::Engine::go() frame(dt); - mViewer->eventTraversal(); - mViewer->updateTraversal(); - mViewer->renderingTraversals(); + if (!mEnvironment.getInputManager()->isWindowVisible()) + { + OpenThreads::Thread::microSleep(5000); + } + else + { + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); + } } // Save user settings diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 79477d883..75c55e028 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -25,6 +25,8 @@ namespace MWBase virtual ~InputManager() {} + virtual bool isWindowVisible() = 0; + virtual void update(float dt, bool disableControls, bool disableEvents=false) = 0; virtual void changeInputMode(bool guiMode) = 0; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 74842e3e3..bd94d60c6 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -41,6 +41,7 @@ namespace MWInput const std::string& userFile, bool userFileExists, const std::string& controllerBindingsFile, bool grab) : mWindow(window) + , mWindowVisible(true) , mViewer(viewer) , mJoystickLastUsed(false) , mPlayer(NULL) @@ -156,6 +157,11 @@ namespace MWInput delete mVideoWrapper; } + bool InputManager::isWindowVisible() + { + return mWindowVisible; + } + void InputManager::setPlayerControlsEnabled(bool enabled) { int nPlayerChannels = 17; @@ -850,7 +856,7 @@ namespace MWInput void InputManager::windowVisibilityChange(bool visible) { - //TODO: Pause game? + mWindowVisible = visible; } void InputManager::windowResized(int x, int y) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index aec640736..62d0f413b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -83,6 +83,8 @@ namespace MWInput virtual ~InputManager(); + virtual bool isWindowVisible(); + /// Clear all savegame-specific data virtual void clear(); @@ -153,6 +155,7 @@ namespace MWInput private: SDL_Window* mWindow; + bool mWindowVisible; osg::ref_ptr mViewer; bool mJoystickLastUsed; From acbea2461b0eb6596a86154f584759d0dc18a842 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 4 Sep 2015 23:27:33 +0200 Subject: [PATCH 348/419] Fix a typo --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 788aaca62..f50991e24 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3156,7 +3156,7 @@ namespace MWWorld // Spawn the explosion orb effect const ESM::Static* areaStatic; - if (!effect->mCasting.empty()) + if (!effect->mArea.empty()) areaStatic = getStore().get().find (effect->mArea); else areaStatic = getStore().get().find ("VFX_DefaultArea"); From 96e3933ee9cdfbd17492ed2f2559b22e02b26909 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 6 Sep 2015 17:39:48 +1200 Subject: [PATCH 349/419] Fixed bug in smoothTurn() Now correctly handles changing direction from 178 to -178 degrees. --- apps/openmw/mwmechanics/steering.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/steering.cpp b/apps/openmw/mwmechanics/steering.cpp index 219a23655..1ef46e1ae 100644 --- a/apps/openmw/mwmechanics/steering.cpp +++ b/apps/openmw/mwmechanics/steering.cpp @@ -14,14 +14,16 @@ bool smoothTurn(const MWWorld::Ptr& actor, float targetAngleRadians, int axis, f { float currentAngle (actor.getRefData().getPosition().rot[axis]); float diff (targetAngleRadians - currentAngle); - if (diff >= osg::DegreesToRadians(180.f)) + if (std::abs(diff) >= osg::DegreesToRadians(180.f)) { - // Turning the other way would be a better idea - diff = diff-osg::DegreesToRadians(360.f); - } - else if (diff <= osg::DegreesToRadians(-180.f)) - { - diff = osg::DegreesToRadians(360.f)-diff; + if (diff >= 0) + { + diff = diff - osg::DegreesToRadians(360.f); + } + else + { + diff = osg::DegreesToRadians(360.f) + diff; + } } float absDiff = std::abs(diff); From b68f64ed97aff7c48d6878241ecd64d6acaba2f5 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Sun, 6 Sep 2015 21:46:05 +0200 Subject: [PATCH 350/419] adjust FindMyGUI.cmake to correctly handle REQUIRED and QUIETLY --- cmake/FindMyGUI.cmake | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index f85b6ba52..6e93a92ce 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -146,11 +146,12 @@ IF (MYGUI_FOUND) IF (NOT MYGUI_FIND_QUIETLY) MESSAGE(STATUS "MyGUI version: ${MYGUI_VERSION}") ENDIF (NOT MYGUI_FIND_QUIETLY) - -ELSE (MYGUI_FOUND) - IF (MYGUI_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find MYGUI") - ENDIF (MYGUI_FIND_REQUIRED) ENDIF (MYGUI_FOUND) +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(MyGUI DEFAULT_MSG + MYGUI_INCLUDE_DIRS + FREETYPE_LIBRARIES + MYGUI_LIBRARIES) + CMAKE_POLICY(POP) From 481f23d955a8802b36cf7cc13ecb35c6c574b551 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 16:05:51 +0200 Subject: [PATCH 351/419] Implement framerate limit setting The framerate limit can be used to reduce strain on the CPU and GPU, in a way similar to VSync, but without the increased input lag that is typical with VSync. --- apps/openmw/engine.cpp | 12 ++++++++++++ files/settings-default.cfg | 3 +++ 2 files changed, 15 insertions(+) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 6801363b1..79c8c4cc9 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -676,6 +676,7 @@ void OMW::Engine::go() // Start the main rendering loop osg::Timer frameTimer; double simulationTime = 0.0; + float framerateLimit = Settings::Manager::getFloat("framerate limit", "Video"); while (!mViewer->done() && !mEnvironment.getStateManager()->hasQuitRequest()) { double dt = frameTimer.time_s(); @@ -693,6 +694,7 @@ void OMW::Engine::go() if (!mEnvironment.getInputManager()->isWindowVisible()) { OpenThreads::Thread::microSleep(5000); + continue; } else { @@ -700,6 +702,16 @@ void OMW::Engine::go() mViewer->updateTraversal(); mViewer->renderingTraversals(); } + + if (framerateLimit > 0.f) + { + double thisFrameTime = frameTimer.time_s(); + double minFrameTime = 1.0 / framerateLimit; + if (thisFrameTime < minFrameTime) + { + OpenThreads::Thread::microSleep(1000*1000*(minFrameTime-thisFrameTime)); + } + } } // Save user settings diff --git a/files/settings-default.cfg b/files/settings-default.cfg index f2b6aa34f..c793225c2 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -20,6 +20,9 @@ vsync = false gamma = 1.00 contrast = 1.00 +# Maximum framerate in frames per second, 0 = unlimited +framerate limit = 0 + [GUI] scaling factor = 1.0 From 76fb68a9c0fceb2f7fc047ede26214ff18c5ea56 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 22:07:09 +0200 Subject: [PATCH 352/419] Handle particle systems that don't have emitters Fixes a crash in the Magic Diversity mod. --- components/nifosg/nifloader.cpp | 47 ++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index c98008394..54a02c950 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -825,30 +825,33 @@ namespace NifOsg partsys->setFreezeOnCull(true); - osg::ref_ptr emitter = handleParticleEmitter(partctrl); - emitter->setParticleSystem(partsys); - emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); - - // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. - // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. - // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. - - FindRecIndexVisitor find (partctrl->emitter->recIndex); - rootNode->accept(find); - if (!find.mFound) + if (!partctrl->emitter.empty()) { - std::cerr << "can't find emitter node, wrong node order? in " << mFilename << std::endl; - return; + osg::ref_ptr emitter = handleParticleEmitter(partctrl); + emitter->setParticleSystem(partsys); + emitter->setReferenceFrame(osgParticle::ParticleProcessor::RELATIVE_RF); + + // Note: we assume that the Emitter node is placed *before* the Particle node in the scene graph. + // This seems to be true for all NIF files in the game that I've checked, suggesting that NIFs work similar to OSG with regards to update order. + // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. + + FindRecIndexVisitor find (partctrl->emitter->recIndex); + rootNode->accept(find); + if (!find.mFound) + { + std::cerr << "can't find emitter node, wrong node order? in " << mFilename << std::endl; + return; + } + osg::Group* emitterNode = find.mFound; + + // Emitter attached to the emitter node. Note one side effect of the emitter using the CullVisitor is that hiding its node + // actually causes the emitter to stop firing. Convenient, because MW behaves this way too! + emitterNode->addChild(emitter); + + osg::ref_ptr callback(new ParticleSystemController(partctrl)); + setupController(partctrl, callback, animflags); + emitter->setUpdateCallback(callback); } - osg::Group* emitterNode = find.mFound; - - // Emitter attached to the emitter node. Note one side effect of the emitter using the CullVisitor is that hiding its node - // actually causes the emitter to stop firing. Convenient, because MW behaves this way too! - emitterNode->addChild(emitter); - - osg::ref_ptr callback(new ParticleSystemController(partctrl)); - setupController(partctrl, callback, animflags); - emitter->setUpdateCallback(callback); // affectors must be attached *after* the emitter in the scene graph for correct update order // attach to same node as the ParticleSystem, we need osgParticle Operators to get the correct From fd48c1d6f4312ca96a401f1cc6341835133a50d8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 21:32:28 +0200 Subject: [PATCH 353/419] Make the Equip script function "use" items (drink potion, use alchemy, etc) --- apps/openmw/mwbase/windowmanager.hpp | 3 +++ apps/openmw/mwgui/quickkeysmenu.cpp | 6 ++---- apps/openmw/mwgui/spellwindow.cpp | 3 +-- apps/openmw/mwgui/windowmanagerimp.cpp | 6 ++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 +++ apps/openmw/mwscript/containerextensions.cpp | 12 +++++++----- 6 files changed, 22 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index f8bf157c2..fb7eca4a3 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -148,6 +148,9 @@ namespace MWBase virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0; virtual MWGui::TradeWindow* getTradeWindow() = 0; + /// Make the player use an item, while updating GUI state accordingly + virtual void useItem(const MWWorld::Ptr& item) = 0; + virtual void updateSpellWindow() = 0; virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index f1e474a2f..f2ae8dd83 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -21,8 +21,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/actorutil.hpp" -#include "../mwgui/inventorywindow.hpp" - #include "itemselection.hpp" #include "spellview.hpp" #include "itemwidget.hpp" @@ -311,7 +309,7 @@ namespace MWGui else if (type == Type_Item) { MWWorld::Ptr item = *button->getUserData(); - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item); + MWBase::Environment::get().getWindowManager()->useItem(item); MWWorld::ContainerStoreIterator rightHand = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); // change draw state only if the item is in player's right hand if (rightHand != store.end() && item == *rightHand) @@ -337,7 +335,7 @@ namespace MWGui // equip, if it can be equipped if (!item.getClass().getEquipmentSlots(item).first.empty()) { - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item); + MWBase::Environment::get().getWindowManager()->useItem(item); // make sure that item was successfully equipped if (!store.isEquipped(item)) diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 68a604256..8422bb33f 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -18,7 +18,6 @@ #include "../mwmechanics/actorutil.hpp" #include "spellicons.hpp" -#include "inventorywindow.hpp" #include "confirmationdialog.hpp" #include "spellview.hpp" @@ -104,7 +103,7 @@ namespace MWGui if (!alreadyEquipped && !item.getClass().getEquipmentSlots(item).first.empty()) { - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item); + MWBase::Environment::get().getWindowManager()->useItem(item); // make sure that item was successfully equipped if (!store.isEquipped(item)) return; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 365f2c7a1..90a5f7481 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1327,6 +1327,12 @@ namespace MWGui MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; } + void WindowManager::useItem(const MWWorld::Ptr &item) + { + if (mInventoryWindow) + mInventoryWindow->useItem(item); + } + bool WindowManager::isAllowed (GuiWindow wnd) const { return (mAllowed & wnd) != 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 336a2a19a..a1f76683e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -173,6 +173,9 @@ namespace MWGui virtual MWGui::ConfirmationDialog* getConfirmationDialog(); virtual MWGui::TradeWindow* getTradeWindow(); + /// Make the player use an item, while updating GUI state accordingly + virtual void useItem(const MWWorld::Ptr& item); + virtual void updateSpellWindow(); virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 20ca2b580..ec14add9a 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -191,11 +191,13 @@ namespace MWScript if (it == invStore.end()) throw std::runtime_error("Item to equip not found"); - MWWorld::ActionEquip action (*it); - action.execute(ptr); - - if (ptr == MWMechanics::getPlayer() && !ptr.getClass().getScript(ptr).empty()) - ptr.getRefData().getLocals().setVarByInt(ptr.getClass().getScript(ptr), "onpcequip", 1); + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + MWBase::Environment::get().getWindowManager()->useItem(*it); + else + { + boost::shared_ptr action = it->getClass().use(*it); + action->execute(ptr); + } } }; From e5d54fb539e92ec2bf9754e4b06cceee9f90f1da Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 22:13:20 +0200 Subject: [PATCH 354/419] Check for actor being the player in various actions --- apps/openmw/mwworld/actionalchemy.cpp | 3 +++ apps/openmw/mwworld/actionapply.cpp | 2 +- apps/openmw/mwworld/actioneat.cpp | 2 +- apps/openmw/mwworld/actionread.cpp | 3 +++ apps/openmw/mwworld/actionrepair.cpp | 3 +++ apps/openmw/mwworld/actionsoulgem.cpp | 3 +++ 6 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/actionalchemy.cpp b/apps/openmw/mwworld/actionalchemy.cpp index bbba1081c..f413f1aed 100644 --- a/apps/openmw/mwworld/actionalchemy.cpp +++ b/apps/openmw/mwworld/actionalchemy.cpp @@ -10,6 +10,9 @@ namespace MWWorld { void ActionAlchemy::executeImp (const Ptr& actor) { + if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage3}"); return; diff --git a/apps/openmw/mwworld/actionapply.cpp b/apps/openmw/mwworld/actionapply.cpp index 00c9628ce..42757a41a 100644 --- a/apps/openmw/mwworld/actionapply.cpp +++ b/apps/openmw/mwworld/actionapply.cpp @@ -32,7 +32,7 @@ namespace MWWorld { MWBase::Environment::get().getWorld()->breakInvisibility(actor); - if (actor.getClass().apply (actor, mId, actor) && mUsageType!=-1) + if (actor.getClass().apply (actor, mId, actor) && mUsageType!=-1 && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) actor.getClass().skillUsageSucceeded (actor, mSkillIndex, mUsageType); actor.getClass().getContainerStore(actor).remove(getTarget(), 1, actor); diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index d9ca4aaf5..5339a113e 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -19,7 +19,7 @@ namespace MWWorld // apply to actor std::string id = getTarget().getClass().getId (getTarget()); - if (actor.getClass().apply (actor, id, actor)) + if (actor.getClass().apply (actor, id, actor) && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) actor.getClass().skillUsageSucceeded (actor, ESM::Skill::Alchemy, 1); } diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index cd0471a0e..d77ca73fd 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -18,6 +18,9 @@ namespace MWWorld void ActionRead::executeImp (const MWWorld::Ptr& actor) { + if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + //Ensure we're not in combat if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat() // Reading in combat is still allowed if the scroll/book is not in the player inventory yet diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp index 699440a01..993f32cde 100644 --- a/apps/openmw/mwworld/actionrepair.cpp +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -14,6 +14,9 @@ namespace MWWorld void ActionRepair::executeImp (const Ptr& actor) { + if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage2}"); return; diff --git a/apps/openmw/mwworld/actionsoulgem.cpp b/apps/openmw/mwworld/actionsoulgem.cpp index 7237fd334..f87c16482 100644 --- a/apps/openmw/mwworld/actionsoulgem.cpp +++ b/apps/openmw/mwworld/actionsoulgem.cpp @@ -16,6 +16,9 @@ namespace MWWorld void ActionSoulgem::executeImp(const Ptr &actor) { + if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage5}"); return; From 5aa33fde4300b8e165905d41534d37d85d915ac1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 22:16:15 +0200 Subject: [PATCH 355/419] Include cleanup --- apps/openmw/mwscript/containerextensions.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index ec14add9a..e33c7580f 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -23,7 +23,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwmechanics/actorutil.hpp" From 0442bc98f3e0a6fd52fdf9f7bd1a59cf3e87bddc Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 22:31:11 +0200 Subject: [PATCH 356/419] Update sleep interruption formula according to wiki, thanks Hrnchamd --- apps/openmw/mwgui/waitdialog.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 733fdd132..e8ac63bf6 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -158,11 +158,15 @@ namespace MWGui // figure out if player will be woken while sleeping int x = Misc::Rng::rollDice(hoursToWait); float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->getFloat(); - if (x < static_cast(fSleepRandMod * hoursToWait)) + if (x < fSleepRandMod * hoursToWait) { float fSleepRestMod = world->getStore().get().find("fSleepRestMod")->getFloat(); - mInterruptAt = hoursToWait - int(fSleepRestMod * hoursToWait); - mInterruptCreatureList = region->mSleepList; + int interruptAtHoursRemaining = int(fSleepRestMod * hoursToWait); + if (interruptAtHoursRemaining != 0) + { + mInterruptAt = hoursToWait - interruptAtHoursRemaining; + mInterruptCreatureList = region->mSleepList; + } } } } From b98a0760557c712bc1987b2646890027b6f185cb Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Sep 2015 23:27:14 +0200 Subject: [PATCH 357/419] Add documentation for ACTN ess-record (activation flags) --- apps/essimporter/importacdt.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index 9d881515d..a5f9d6eb3 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -10,7 +10,21 @@ namespace ESSImport void ActorData::load(ESM::ESMReader &esm) { if (esm.isNextSub("ACTN")) + { + /* + Activation flags: + ActivationFlag_UseEnabled = 1 + ActivationFlag_OnActivate = 2 + ActivationFlag_OnDeath = 10h + ActivationFlag_OnKnockout = 20h + ActivationFlag_OnMurder = 40h + ActivationFlag_DoorOpening = 100h + ActivationFlag_DoorClosing = 200h + ActivationFlag_DoorJammedOpening = 400h + ActivationFlag_DoorJammedClosing = 800h + */ esm.skipHSub(); + } if (esm.isNextSub("STPR")) esm.skipHSub(); From 73f6efddcc1b6f5816f9f775418c6317cf74ee20 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Sep 2015 15:33:15 +0200 Subject: [PATCH 358/419] fixed a texture indexing bug (only affects the editor) --- apps/opencs/model/tools/mergestages.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index f4cb42aa4..e24d1f911 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -179,6 +179,9 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes CSMWorld::LandTexture texture = mState.mSource.getData().getLandTextures().getRecord (index).get(); + std::ostringstream stream; + stream << mNext->second << "_0"; + texture.mIndex = mNext->second; texture.mId = stream.str(); From 09ec60fe2a7b2cce91ee5f2271db4479b97ae228 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Sep 2015 16:01:34 +0200 Subject: [PATCH 359/419] handle missing land texture records properly during merge --- apps/opencs/model/tools/mergestages.cpp | 49 ++++++++++++++----------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index e24d1f911..fab5fae71 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -164,35 +164,42 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes if (stage==0) mNext = mState.mTextureIndices.begin(); - if (mNext==mState.mTextureIndices.end()) - return; + bool found = false; - mNext->second = stage; - - std::ostringstream stream; - stream << mNext->first.first << "_" << mNext->first.second; - - int index = mState.mSource.getData().getLandTextures().searchId (stream.str()); - - if (index!=-1) + do { - CSMWorld::LandTexture texture = - mState.mSource.getData().getLandTextures().getRecord (index).get(); + if (mNext==mState.mTextureIndices.end()) + return; + + mNext->second = stage; std::ostringstream stream; - stream << mNext->second << "_0"; + stream << mNext->first.first << "_" << mNext->first.second; - texture.mIndex = mNext->second; - texture.mId = stream.str(); + int index = mState.mSource.getData().getLandTextures().searchId (stream.str()); - CSMWorld::Record newRecord ( - CSMWorld::RecordBase::State_ModifiedOnly, 0, &texture); + if (index!=-1) + { + CSMWorld::LandTexture texture = + mState.mSource.getData().getLandTextures().getRecord (index).get(); - mState.mTarget->getData().getLandTextures().appendRecord (newRecord); + std::ostringstream stream; + stream << mNext->second << "_0"; + + texture.mIndex = mNext->second; + texture.mId = stream.str(); + + CSMWorld::Record newRecord ( + CSMWorld::RecordBase::State_ModifiedOnly, 0, &texture); + + mState.mTarget->getData().getLandTextures().appendRecord (newRecord); + + found = true; + } + + ++mNext; } - /// \todo deal with missing textures (either abort merge or report and make sure OpenMW can deal with missing textures) - - ++mNext; + while (!found); } From 29d74f024910c36ad6a474dbca4ccffe7db2e073 Mon Sep 17 00:00:00 2001 From: slothlife Date: Tue, 8 Sep 2015 22:05:33 -0500 Subject: [PATCH 360/419] Improve thunderstorm support. Reversed settings for thunderstorms. Added thunder support to all weather types. Implemented a simple lightning flash effect similar to MW. --- apps/openmw/mwrender/sky.cpp | 14 --- apps/openmw/mwrender/sky.hpp | 2 - apps/openmw/mwworld/weather.cpp | 169 +++++++++++++++++--------------- apps/openmw/mwworld/weather.hpp | 32 +++--- 4 files changed, 109 insertions(+), 108 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 138365ae4..dba2e5b0e 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1181,20 +1181,6 @@ void SkyManager::setSecundaState(const MoonState& state) mSecunda->setState(state); } -void SkyManager::setLightningStrength(const float factor) -{ - if (!mCreated) return; - /* - if (factor > 0.f) - { - mLightning->setDiffuseColour (ColourValue(2*factor, 2*factor, 2*factor)); - mLightning->setVisible(true); - } - else - mLightning->setVisible(false); - */ -} - void SkyManager::setDate(int day, int month) { mDay = day; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 3855136a9..de27cf447 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -140,8 +140,6 @@ namespace MWRender void setMasserState(const MoonState& state); void setSecundaState(const MoonState& state); - void setLightningStrength(const float factor); - void setGlare(const float glare); void setGlareEnabled(bool enabled); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index e7c67d2e1..cdd0a8d79 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -80,15 +80,24 @@ Weather::Weather(const std::string& name, , mRainEffect(fallback.getFallbackBool("Weather_" + name + "_Using_Precip") ? "meshes\\raindrop.nif" : "") , mTransitionDelta(fallback.getFallbackFloat("Weather_" + name + "_Transition_Delta")) , mCloudsMaximumPercent(fallback.getFallbackFloat("Weather_" + name + "_Clouds_Maximum_Percent")) + , mThunderFrequency(fallback.getFallbackFloat("Weather_" + name + "_Thunder_Frequency")) + , mThunderThreshold(fallback.getFallbackFloat("Weather_" + name + "_Thunder_Threshold")) + , mThunderSoundID() + , mFlashDecrement(fallback.getFallbackFloat("Weather_" + name + "_Flash_Decrement")) + , mFlashBrightness(0.0f) { -/* -Unhandled: -Rain Diameter=600 ? -Rain Height Min=200 ? -Rain Height Max=700 ? -Rain Threshold=0.6 ? -Max Raindrops=650 ? -*/ + mThunderSoundID[0] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_0"); + mThunderSoundID[1] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_1"); + mThunderSoundID[2] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_2"); + mThunderSoundID[3] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_3"); + /* + Unhandled: + Rain Diameter=600 ? + Rain Height Min=200 ? + Rain Height Max=700 ? + Rain Threshold=0.6 ? + Max Raindrops=650 ? + */ } float Weather::transitionDelta() const @@ -98,12 +107,66 @@ float Weather::transitionDelta() const return mTransitionDelta; } -float Weather::cloudBlendFactor(float transitionRatio) const +float Weather::cloudBlendFactor(const float transitionRatio) const { // Clouds Maximum Percent affects how quickly the sky transitions from one sky texture to the next. return transitionRatio / mCloudsMaximumPercent; } +float Weather::calculateThunder(const float transitionRatio, const float elapsedSeconds, const bool isPaused) +{ + // When paused, the flash brightness remains the same and no new strikes can occur. + if(!isPaused) + { + // Morrowind doesn't appear to do any calculations unless the transition ratio is higher than the Thunder Threshold. + if(transitionRatio >= mThunderThreshold && mThunderFrequency > 0.0f) + { + flashDecrement(elapsedSeconds); + + if(Misc::Rng::rollProbability() <= thunderChance(transitionRatio, elapsedSeconds)) + { + lightningAndThunder(); + } + } + else + { + mFlashBrightness = 0.0f; + } + } + + return mFlashBrightness; +} + +inline void Weather::flashDecrement(const float elapsedSeconds) +{ + // The Flash Decrement is measured in whole units per second. This means that if the flash brightness was + // currently 1.0, then it should take approximately 0.25 seconds to decay to 0.0 (the minimum). + float decrement = mFlashDecrement * elapsedSeconds; + mFlashBrightness = decrement > mFlashBrightness ? 0.0f : mFlashBrightness - decrement; +} + +inline float Weather::thunderChance(const float transitionRatio, const float elapsedSeconds) const +{ + // This formula is reversed from the observation that with Thunder Frequency set to 1, there are roughly 10 strikes + // per minute. It doesn't appear to be tied to in game time as Timescale doesn't affect it. Various values of + // Thunder Frequency seem to change the average number of strikes in a linear fashion.. During a transition, it appears to + // scaled based on how far past it is past the Thunder Threshold. + float scaleFactor = (transitionRatio - mThunderThreshold) / (1.0f - mThunderThreshold); + return ((mThunderFrequency * 10.0f) / 60.0f) * elapsedSeconds * scaleFactor; +} + +inline void Weather::lightningAndThunder(void) +{ + // Morrowind seems to vary the intensity of the brightness based on which of the four sound IDs it selects. + // They appear to go from 0 (brightest, closest) to 3 (faintest, farthest). The value of 0.25 per distance + // was derived by setting the Flash Decrement to 0.1 and measuring how long each value took to decay to 0. + // TODO: Determine the distribution of each distance to see if it's evenly weighted. + unsigned int distance = Misc::Rng::rollDice(4); + // Flash brightness appears additive, since if multiple strikes occur, it takes longer for it to decay to 0. + mFlashBrightness += 1 - (distance * 0.25f); + MWBase::Environment::get().getSoundManager()->playSound(mThunderSoundID[distance], 1.0, 1.0); +} + RegionWeather::RegionWeather(const ESM::Region& region) : mWeather(invalidWeatherID) , mChances() @@ -378,19 +441,9 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mWeatherSettings() , mMasser("Masser", fallback) , mSecunda("Secunda", fallback) - , mThunderFrequency(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency")) - , mThunderThreshold(fallback.getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold")) - , mThunderSoundID0(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0")) - , mThunderSoundID1(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1")) - , mThunderSoundID2(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2")) - , mThunderSoundID3(fallback.getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3")) , mWindSpeed(0.f) , mIsStorm(false) , mStormDirection(0,1,0) - , mThunderSoundDelay(0.25) - , mThunderFlash(0) - , mThunderChance(0) - , mThunderChanceNeeded(50) , mCurrentRegion() , mTimePassed(0) , mFastForward(false) @@ -515,12 +568,11 @@ void WeatherManager::update(float duration, bool paused) if(!exterior) { mRendering.setSkyEnabled(false); - //mRendering->getSkyManager()->setLightningStrength(0.f); stopSounds(); return; } - calculateWeatherResult(time.getHour()); + calculateWeatherResult(time.getHour(), duration, paused); mWindSpeed = mResult.mWindSpeed; mIsStorm = mResult.mIsStorm; @@ -536,8 +588,6 @@ void WeatherManager::update(float duration, bool paused) mRendering.getSkyManager()->setStormDirection(mStormDirection); } - mRendering.configureFog(mResult.mFogDepth, mResult.mFogColor); - // disable sun during night if (time.getHour() >= mNightStart || time.getHour() <= mSunriseTime) mRendering.getSkyManager()->sunDisable(); @@ -577,56 +627,7 @@ void WeatherManager::update(float duration, bool paused) mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time)); mRendering.getSkyManager()->setSecundaState(mSecunda.calculateState(time)); - if (!paused) - { - if(mCurrentWeather == 5 && !inTransition()) - { - if (mThunderFlash > 0) - { - // play the sound after a delay - mThunderSoundDelay -= duration; - if (mThunderSoundDelay <= 0) - { - // pick a random sound - int sound = Misc::Rng::rollDice(4); - std::string* soundName = NULL; - if (sound == 0) soundName = &mThunderSoundID0; - else if (sound == 1) soundName = &mThunderSoundID1; - else if (sound == 2) soundName = &mThunderSoundID2; - else if (sound == 3) soundName = &mThunderSoundID3; - if (soundName) - MWBase::Environment::get().getSoundManager()->playSound(*soundName, 1.0, 1.0); - mThunderSoundDelay = 1000; - } - - mThunderFlash -= duration; - //if (mThunderFlash > 0) - //mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); - //else - { - mThunderChanceNeeded = static_cast(Misc::Rng::rollDice(100)); - mThunderChance = 0; - //mRendering->getSkyManager()->setLightningStrength( 0.f ); - } - } - else - { - // no thunder active - mThunderChance += duration*4; // chance increases by 4 percent every second - if (mThunderChance >= mThunderChanceNeeded) - { - mThunderFlash = mThunderThreshold; - - //mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); - - mThunderSoundDelay = 0.25; - } - } - } - //else - //mRendering->getSkyManager()->setLightningStrength(0.f); - } - + mRendering.configureFog(mResult.mFogDepth, mResult.mFogColor); mRendering.setAmbientColour(mResult.mAmbientColor); mRendering.setSunColour(mResult.mSunColor); @@ -765,10 +766,6 @@ void WeatherManager::clear() { stopSounds(); - mThunderFlash = 0.0; - mThunderChance = 0.0; - mThunderChanceNeeded = 50.0; - mCurrentRegion = ""; mTimePassed = 0.0f; mWeatherUpdateTime = 0.0f; @@ -921,16 +918,32 @@ inline void WeatherManager::addWeatherTransition(const int weatherID) } } -inline void WeatherManager::calculateWeatherResult(const float gameHour) +inline void WeatherManager::calculateWeatherResult(const float gameHour, + const float elapsedSeconds, + const bool isPaused) { + float flash = 0.0f; if(!inTransition()) { calculateResult(mCurrentWeather, gameHour); + flash = mWeatherSettings[mCurrentWeather].calculateThunder(1.0f, elapsedSeconds, isPaused); } else { calculateTransitionResult(1 - mTransitionFactor, gameHour); + float currentFlash = mWeatherSettings[mCurrentWeather].calculateThunder(mTransitionFactor, + elapsedSeconds, + isPaused); + float nextFlash = mWeatherSettings[mNextWeather].calculateThunder(1 - mTransitionFactor, + elapsedSeconds, + isPaused); + flash = currentFlash + nextFlash; } + osg::Vec4f flashColor(flash, flash, flash, 0.0f); + + mResult.mFogColor += flashColor; + mResult.mAmbientColor += flashColor; + mResult.mSunColor += flashColor; } inline void WeatherManager::calculateResult(const int weatherID, const float gameHour) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index c808b029b..a0c93a460 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -113,11 +113,27 @@ namespace MWWorld // is broken in the vanilla game and was disabled. float transitionDelta() const; - float cloudBlendFactor(float transitionRatio) const; + float cloudBlendFactor(const float transitionRatio) const; + + float calculateThunder(const float transitionRatio, const float elapsedSeconds, const bool isPaused); private: float mTransitionDelta; float mCloudsMaximumPercent; + + // Note: In MW, only thunderstorms support these attributes, but in the interest of making weather more + // flexible, these settings are imported for all weather types. Only thunderstorms will normally have any + // non-zero values. + float mThunderFrequency; + float mThunderThreshold; + std::string mThunderSoundID[4]; + float mFlashDecrement; + + float mFlashBrightness; + + void flashDecrement(const float elapsedSeconds); + float thunderChance(const float transitionRatio, const float elapsedSeconds) const; + void lightningAndThunder(void); }; /// A class for storing a region's weather. @@ -242,22 +258,10 @@ namespace MWWorld MoonModel mMasser; MoonModel mSecunda; - float mThunderFrequency; - float mThunderThreshold; - std::string mThunderSoundID0; - std::string mThunderSoundID1; - std::string mThunderSoundID2; - std::string mThunderSoundID3; - float mWindSpeed; bool mIsStorm; osg::Vec3f mStormDirection; - float mThunderSoundDelay; - float mThunderFlash; - float mThunderChance; - float mThunderChanceNeeded; - std::string mCurrentRegion; float mTimePassed; bool mFastForward; @@ -288,7 +292,7 @@ namespace MWWorld bool inTransition(); void addWeatherTransition(const int weatherID); - void calculateWeatherResult(const float gameHour); + void calculateWeatherResult(const float gameHour, const float elapsedSeconds, const bool isPaused); void calculateResult(const int weatherID, const float gameHour); void calculateTransitionResult(const float factor, const float gameHour); }; From e9c796166ae6866a118b0fec8a045373e5dc4577 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 10 Sep 2015 18:48:34 +1200 Subject: [PATCH 361/419] Added MWMechanics::isPlayerInCombat() --- apps/openmw/mwmechanics/actorutil.cpp | 7 +++++++ apps/openmw/mwmechanics/actorutil.hpp | 1 + apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwworld/actionalchemy.cpp | 5 +++-- apps/openmw/mwworld/actionapply.cpp | 4 +++- apps/openmw/mwworld/actioneat.cpp | 4 +++- apps/openmw/mwworld/actionread.cpp | 5 +++-- apps/openmw/mwworld/actionrepair.cpp | 5 +++-- apps/openmw/mwworld/actionsoulgem.cpp | 5 +++-- 9 files changed, 27 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/actorutil.cpp b/apps/openmw/mwmechanics/actorutil.cpp index dc3770556..537f27197 100644 --- a/apps/openmw/mwmechanics/actorutil.cpp +++ b/apps/openmw/mwmechanics/actorutil.cpp @@ -3,10 +3,17 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" +#include "../mwworld/player.hpp" + namespace MWMechanics { MWWorld::Ptr getPlayer() { return MWBase::Environment::get().getWorld()->getPlayerPtr(); } + + bool isPlayerInCombat() + { + return MWBase::Environment::get().getWorld()->getPlayer().isInCombat(); + } } diff --git a/apps/openmw/mwmechanics/actorutil.hpp b/apps/openmw/mwmechanics/actorutil.hpp index 95172b9f9..3c6dc940c 100644 --- a/apps/openmw/mwmechanics/actorutil.hpp +++ b/apps/openmw/mwmechanics/actorutil.hpp @@ -9,6 +9,7 @@ namespace MWWorld namespace MWMechanics { MWWorld::Ptr getPlayer(); + bool isPlayerInCombat(); } #endif diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 711ecdbd2..12927101d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -927,7 +927,7 @@ namespace MWMechanics return true; } - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { + if(MWMechanics::isPlayerInCombat()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage2}"); return true; } diff --git a/apps/openmw/mwworld/actionalchemy.cpp b/apps/openmw/mwworld/actionalchemy.cpp index f413f1aed..53ed1ad84 100644 --- a/apps/openmw/mwworld/actionalchemy.cpp +++ b/apps/openmw/mwworld/actionalchemy.cpp @@ -5,15 +5,16 @@ #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWWorld { void ActionAlchemy::executeImp (const Ptr& actor) { - if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor != MWMechanics::getPlayer()) return; - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat + if(MWMechanics::isPlayerInCombat()) { //Ensure we're not in combat MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage3}"); return; } diff --git a/apps/openmw/mwworld/actionapply.cpp b/apps/openmw/mwworld/actionapply.cpp index 42757a41a..e3699a6ac 100644 --- a/apps/openmw/mwworld/actionapply.cpp +++ b/apps/openmw/mwworld/actionapply.cpp @@ -7,6 +7,8 @@ #include "../mwworld/containerstore.hpp" +#include "../mwmechanics/actorutil.hpp" + namespace MWWorld { ActionApply::ActionApply (const Ptr& object, const std::string& id) @@ -32,7 +34,7 @@ namespace MWWorld { MWBase::Environment::get().getWorld()->breakInvisibility(actor); - if (actor.getClass().apply (actor, mId, actor) && mUsageType!=-1 && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor.getClass().apply (actor, mId, actor) && mUsageType!=-1 && actor == MWMechanics::getPlayer()) actor.getClass().skillUsageSucceeded (actor, mSkillIndex, mUsageType); actor.getClass().getContainerStore(actor).remove(getTarget(), 1, actor); diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 5339a113e..82c7fb80e 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -7,6 +7,8 @@ #include "../mwworld/containerstore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "class.hpp" namespace MWWorld @@ -19,7 +21,7 @@ namespace MWWorld // apply to actor std::string id = getTarget().getClass().getId (getTarget()); - if (actor.getClass().apply (actor, id, actor) && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor.getClass().apply (actor, id, actor) && actor == MWMechanics::getPlayer()) actor.getClass().skillUsageSucceeded (actor, ESM::Skill::Alchemy, 1); } diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index d77ca73fd..90e9a375b 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -5,6 +5,7 @@ #include "../mwbase/world.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "player.hpp" #include "class.hpp" @@ -18,11 +19,11 @@ namespace MWWorld void ActionRead::executeImp (const MWWorld::Ptr& actor) { - if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor != MWMechanics::getPlayer()) return; //Ensure we're not in combat - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat() + if(MWMechanics::isPlayerInCombat() // Reading in combat is still allowed if the scroll/book is not in the player inventory yet // (since otherwise, there would be no way to pick it up) && getTarget().getContainerStore() == &actor.getClass().getContainerStore(actor) diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp index 993f32cde..8e19927b8 100644 --- a/apps/openmw/mwworld/actionrepair.cpp +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -4,6 +4,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWWorld { @@ -14,10 +15,10 @@ namespace MWWorld void ActionRepair::executeImp (const Ptr& actor) { - if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor != MWMechanics::getPlayer()) return; - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { + if(MWMechanics::isPlayerInCombat()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage2}"); return; } diff --git a/apps/openmw/mwworld/actionsoulgem.cpp b/apps/openmw/mwworld/actionsoulgem.cpp index f87c16482..98fe8ee34 100644 --- a/apps/openmw/mwworld/actionsoulgem.cpp +++ b/apps/openmw/mwworld/actionsoulgem.cpp @@ -4,6 +4,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWWorld { @@ -16,10 +17,10 @@ namespace MWWorld void ActionSoulgem::executeImp(const Ptr &actor) { - if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor != MWMechanics::getPlayer()) return; - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat + if(MWMechanics::isPlayerInCombat()) { //Ensure we're not in combat MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage5}"); return; } From 573a14993ac1d41979c805cd6298bd9f82227a64 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 10 Sep 2015 21:53:31 +1200 Subject: [PATCH 362/419] Moved isActorNearInactiveCell() logic to own function. Also, triggers when actor is near edge of cell, not when less than 1/2 way to edge. --- apps/openmw/mwmechanics/aipackage.cpp | 62 ++++++++++++++------------- apps/openmw/mwmechanics/aipackage.hpp | 1 + 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index b6b240833..e5da16865 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -16,6 +16,7 @@ #include "steering.hpp" #include "actorutil.hpp" +#include "coordinateconverter.hpp" MWMechanics::AiPackage::~AiPackage() {} @@ -32,45 +33,24 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po ESM::Position pos = actor.getRefData().getPosition(); //position of the actor /// Stops the actor when it gets too close to a unloaded cell - const ESM::Cell *cell = actor.getCell()->getCell(); + //... At current time, this test is unnecessary. AI shuts down when actor is more than 7168 + //... units from player, and exterior cells are 8192 units long and wide. + //... But AI processing distance may increase in the future. + if (isActorNearInactiveCell(pos)) { - MWWorld::Ptr player = getPlayer(); - Movement &movement = actor.getClass().getMovementSettings(actor); - - //Ensure pursuer doesn't leave loaded cells - if(cell->mData.mX != player.getCell()->getCell()->mData.mX) - { - int sideX = PathFinder::sgn(cell->mData.mX - player.getCell()->getCell()->mData.mX); - //check if actor is near the border of an inactive cell. If so, stop walking. - if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f)) - { - movement.mPosition[1] = 0; - return false; - } - } - if(cell->mData.mY != player.getCell()->getCell()->mData.mY) - { - int sideY = PathFinder::sgn(cell->mData.mY - player.getCell()->getCell()->mData.mY); - //check if actor is near the border of an inactive cell. If so, stop walking. - if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f)) - { - movement.mPosition[1] = 0; - return false; - } - } + actor.getClass().getMovementSettings(actor).mPosition[1] = 0; + return false; } - //Start position - ESM::Pathgrid::Point start = pos.pos; - //*********************** /// Checks if you can't get to the end position at all, adds end position to end of path /// Rebuilds path every quarter of a second, in case the target has moved //*********************** if(mTimer > 0.25) { + const ESM::Cell *cell = actor.getCell()->getCell(); if (doesPathNeedRecalc(dest, cell)) { //Only rebuild path if it's moved - mPathFinder.buildSyncedPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved + mPathFinder.buildSyncedPath(pos.pos, dest, actor.getCell(), true); //Rebuild path, in case the target has moved mPrevDest = dest; } @@ -133,3 +113,27 @@ bool MWMechanics::AiPackage::isTargetMagicallyHidden(const MWWorld::Ptr& target) return (magicEffects.get(ESM::MagicEffect::Invisibility).getMagnitude() > 0) || (magicEffects.get(ESM::MagicEffect::Chameleon).getMagnitude() > 75); } + +bool MWMechanics::AiPackage::isActorNearInactiveCell(const ESM::Position& actorPos) +{ + const ESM::Cell* playerCell(getPlayer().getCell()->getCell()); + if (playerCell->isExterior()) + { + // get actor's distance from origin of center cell + osg::Vec3f actorOffset(actorPos.asVec3()); + CoordinateConverter(playerCell).ToLocal(actorOffset); + + // currently assumes 3 x 3 grid for exterior cells, with player at center cell. + // ToDo: (Maybe) use "exterior cell load distance" setting to get count of actual active cells + // While AI Process distance is 7168, AI shuts down actors before they reach edges of 3 x 3 grid. + const float distanceFromEdge = 200.0; + float minThreshold = (-1.0f * ESM::Land::REAL_SIZE) + distanceFromEdge; + float maxThreshold = (2.0f * ESM::Land::REAL_SIZE) - distanceFromEdge; + return (actorOffset[0] < minThreshold) || (maxThreshold < actorOffset[0]) + || (actorOffset[1] < minThreshold) || (maxThreshold < actorOffset[1]); + } + else + { + return false; + } +} \ No newline at end of file diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 4f919edbc..befd159bf 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -88,6 +88,7 @@ namespace MWMechanics private: void evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos); + bool isActorNearInactiveCell(const ESM::Position& actorPos); }; } From 6f97187bb6558c44978d106b1394fe2c353406c1 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 10 Sep 2015 22:26:33 +1200 Subject: [PATCH 363/419] Fix travis warning about no newline at end of file. --- apps/openmw/mwmechanics/aipackage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index e5da16865..c4091c63e 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -136,4 +136,4 @@ bool MWMechanics::AiPackage::isActorNearInactiveCell(const ESM::Position& actorP { return false; } -} \ No newline at end of file +} From 584a7a66b97739c91c38cf8f17922ba29d5536e2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 10 Sep 2015 12:41:31 +0200 Subject: [PATCH 364/419] various minor fixes --- apps/opencs/model/tools/mergestages.cpp | 31 ++++++++++++++----------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index fab5fae71..f7c3b8dc0 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -124,7 +124,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& if (!record.isDeleted()) { - const ESM::Land& land = record.get(); + const CSMWorld::Land& land = record.get(); // make sure record is loaded land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | @@ -228,22 +228,25 @@ void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages) // because record is already fully loaded) newLand.mPlugin = 0; - // adjust land texture references - if (ESM::Land::LandData *data = newLand.getLandData()) + if (land.mDataTypes & ESM::Land::DATA_VTEX) { - std::pair key; - key.second = land.mPlugin; - - for (int i=0; imTextures[i]; - std::map, int>::const_iterator iter = - mState.mTextureIndices.find (key); + std::pair key; + key.second = land.mPlugin; - if (iter!=mState.mTextureIndices.end()) - data->mTextures[i] = iter->second; - else - data->mTextures[i] = 0; + for (int i=0; imTextures[i]; + std::map, int>::const_iterator iter = + mState.mTextureIndices.find (key); + + if (iter!=mState.mTextureIndices.end()) + data->mTextures[i] = iter->second; + else + data->mTextures[i] = 0; + } } } From 10eabc9d519d27d5a02c66e7c7bb886ad55228b2 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 11 Sep 2015 18:43:06 +1200 Subject: [PATCH 365/419] actorutil.hpp includes mwworld/ptr.hpp As pointed out by Scrawl, fixes compiler error if getPlayer() is called before MWWorld::Ptr is defined, because getPlayer() returns a Ptr by value. --- apps/openmw/mwmechanics/actorutil.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actorutil.hpp b/apps/openmw/mwmechanics/actorutil.hpp index 3c6dc940c..510e41db3 100644 --- a/apps/openmw/mwmechanics/actorutil.hpp +++ b/apps/openmw/mwmechanics/actorutil.hpp @@ -1,10 +1,7 @@ #ifndef OPENMW_MWMECHANICS_ACTORUTIL_H #define OPENMW_MWMECHANICS_ACTORUTIL_H -namespace MWWorld -{ - class Ptr; -} +#include "../mwworld/ptr.hpp" namespace MWMechanics { From 23fde87816644912c9896920b80348429a045003 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 Sep 2015 10:50:19 +0200 Subject: [PATCH 366/419] fixed an indexing error --- apps/opencs/model/tools/mergestages.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index f7c3b8dc0..52e1e6964 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -171,10 +171,10 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes if (mNext==mState.mTextureIndices.end()) return; - mNext->second = stage; + mNext->second = stage+1; std::ostringstream stream; - stream << mNext->first.first << "_" << mNext->first.second; + stream << mNext->first.first-1 << "_" << mNext->first.second; int index = mState.mSource.getData().getLandTextures().searchId (stream.str()); @@ -184,9 +184,9 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes mState.mSource.getData().getLandTextures().getRecord (index).get(); std::ostringstream stream; - stream << mNext->second << "_0"; + stream << mNext->second-1 << "_0"; - texture.mIndex = mNext->second; + texture.mIndex = mNext->second-1; texture.mId = stream.str(); CSMWorld::Record newRecord ( From 5be176ee85da349163e161f86693f836fb1b5fdc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 11 Sep 2015 13:02:24 +0200 Subject: [PATCH 367/419] disable on-demand loading of land data (for now, maybe) --- apps/opencs/model/world/data.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index fe6d6ccbb..a95761929 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -955,8 +955,10 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) { int index = mLand.load(*mReader, mBase); - if (index!=-1 && !mBase) - mLand.getRecord (index).mModified.loadData ( + // Load all land data for now. A future optimisation may only load non-base data + // if a suitable mechanism for avoiding race conditions can be established. + if (index!=-1/* && !mBase*/) + mLand.getRecord (index).get().loadData ( ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); From 5252dbcf1f4dc311419ca9f7d5f32a765771d1e0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Sep 2015 21:09:54 +0200 Subject: [PATCH 368/419] Add some comments to ESM::Land --- components/esm/loadland.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 56267a28c..8ec4f74ea 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -76,17 +76,29 @@ struct Land struct LandData { + // Initial reference height for the first vertex, only needed for filling mHeights float mHeightOffset; + // Height in world space for each vertex float mHeights[LAND_NUM_VERTS]; + + // 24-bit normals, these aren't always correct though. Edge and corner normals may be garbage. VNML mNormals[LAND_NUM_VERTS * 3]; + + // 2D array of texture indices. An index can be used to look up an ESM::LandTexture, + // but to do so you must subtract 1 from the index first! + // An index of 0 indicates the default texture. uint16_t mTextures[LAND_NUM_TEXTURES]; + // 24-bit RGB color for each vertex unsigned char mColours[3 * LAND_NUM_VERTS]; + + // DataTypes available in this LandData, accessing data that is not available is an undefined operation int mDataTypes; // low-LOD heightmap (used for rendering the global map) signed char mWnam[81]; + // ??? short mUnk1; uint8_t mUnk2; From 258b2ba29abedf329db1db2c5660cf213445c999 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 12 Sep 2015 09:04:43 +1000 Subject: [PATCH 369/419] Ensure ColumnId names are unique. Filter parser calls Columns::getId() which implies that these should be unique. --- apps/opencs/model/world/columns.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 045438bef..e6dabc4d7 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -265,7 +265,7 @@ namespace CSMWorld { ColumnId_LevelledList,"Levelled List" }, { ColumnId_LevelledItemId,"Levelled Item" }, - { ColumnId_LevelledItemLevel,"Level" }, + { ColumnId_LevelledItemLevel,"Item Level" }, { ColumnId_LevelledItemType, "Calculate all levels <= player" }, { ColumnId_LevelledItemTypeEach, "Select a new item each instance" }, { ColumnId_LevelledItemChanceNone, "Chance None" }, @@ -281,26 +281,26 @@ namespace CSMWorld { ColumnId_InfoCondValue, "Values" }, { ColumnId_OriginalCell, "Original Cell" }, - { ColumnId_NpcAttributes, "Attributes" }, - { ColumnId_NpcSkills, "Skills" }, + { ColumnId_NpcAttributes, "NPC Attributes" }, + { ColumnId_NpcSkills, "NPC Skill" }, { ColumnId_UChar, "Value [0..255]" }, - { ColumnId_NpcMisc, "Misc" }, + { ColumnId_NpcMisc, "NPC Misc" }, { ColumnId_NpcLevel, "Level" }, { ColumnId_NpcFactionID, "Faction ID" }, - { ColumnId_NpcHealth, "Health" }, + { ColumnId_NpcHealth, "NPC Health" }, { ColumnId_NpcMana, "Mana" }, { ColumnId_NpcFatigue, "Fatigue" }, - { ColumnId_NpcDisposition, "Disposition" }, + { ColumnId_NpcDisposition, "NPC Disposition" }, { ColumnId_NpcReputation, "Reputation" }, - { ColumnId_NpcRank, "Rank" }, + { ColumnId_NpcRank, "NPC Rank" }, { ColumnId_NpcGold, "Gold" }, { ColumnId_NpcPersistence, "Persistent" }, - { ColumnId_RaceAttributes, "Attributes" }, - { ColumnId_RaceMaleValue, "Male" }, - { ColumnId_RaceFemaleValue, "Female" }, + { ColumnId_RaceAttributes, "Race Attributes" }, + { ColumnId_RaceMaleValue, "Male Attrib" }, + { ColumnId_RaceFemaleValue, "Female Attrib" }, { ColumnId_RaceSkillBonus, "Skill Bonus" }, - { ColumnId_RaceSkill, "Skills" }, + { ColumnId_RaceSkill, "Race Skill" }, { ColumnId_RaceBonus, "Bonus" }, { ColumnId_Interior, "Interior" }, From c4a900ca2c9b98267c9a507bb887829373fc9193 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 12 Sep 2015 09:33:11 +1000 Subject: [PATCH 370/419] Rationalise the use of ColumnIds --- apps/opencs/model/world/columns.cpp | 15 +++++---------- apps/opencs/model/world/columns.hpp | 14 +++++++------- apps/opencs/model/world/data.cpp | 4 ++-- apps/opencs/model/world/nestedcoladapterimp.cpp | 2 +- apps/opencs/model/world/refidadapterimp.cpp | 15 ++------------- apps/opencs/model/world/refidcollection.cpp | 14 +++++++------- apps/opencs/view/doc/viewmanager.cpp | 1 - 7 files changed, 24 insertions(+), 41 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index e6dabc4d7..9f39be5f3 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -199,8 +199,6 @@ namespace CSMWorld { ColumnId_RotY, "Rotation Y"}, { ColumnId_RotZ, "Rotation Z"}, - { ColumnId_Skill, "Skill" }, - { ColumnId_OwnerGlobal, "Owner Global" }, { ColumnId_DefaultProfile, "Default Profile" }, { ColumnId_BypassNewGame, "Bypass New Game" }, @@ -271,7 +269,7 @@ namespace CSMWorld { ColumnId_LevelledItemChanceNone, "Chance None" }, { ColumnId_PowerList, "Powers" }, - { ColumnId_SkillImpact, "Skills" }, + { ColumnId_SkillImpact, "Skill" }, { ColumnId_InfoList, "Info List" }, { ColumnId_InfoCondition, "Info Conditions" }, @@ -285,22 +283,20 @@ namespace CSMWorld { ColumnId_NpcSkills, "NPC Skill" }, { ColumnId_UChar, "Value [0..255]" }, { ColumnId_NpcMisc, "NPC Misc" }, - { ColumnId_NpcLevel, "Level" }, + { ColumnId_Level, "Level" }, { ColumnId_NpcFactionID, "Faction ID" }, - { ColumnId_NpcHealth, "NPC Health" }, - { ColumnId_NpcMana, "Mana" }, - { ColumnId_NpcFatigue, "Fatigue" }, + { ColumnId_Mana, "Mana" }, + { ColumnId_Fatigue, "Fatigue" }, { ColumnId_NpcDisposition, "NPC Disposition" }, { ColumnId_NpcReputation, "Reputation" }, { ColumnId_NpcRank, "NPC Rank" }, - { ColumnId_NpcGold, "Gold" }, + { ColumnId_Gold, "Gold" }, { ColumnId_NpcPersistence, "Persistent" }, { ColumnId_RaceAttributes, "Race Attributes" }, { ColumnId_RaceMaleValue, "Male Attrib" }, { ColumnId_RaceFemaleValue, "Female Attrib" }, { ColumnId_RaceSkillBonus, "Skill Bonus" }, - { ColumnId_RaceSkill, "Race Skill" }, { ColumnId_RaceBonus, "Bonus" }, { ColumnId_Interior, "Interior" }, @@ -579,7 +575,6 @@ namespace // FIXME: don't have dynamic value enum delegate, use Display_String for now //case CSMWorld::Columns::ColumnId_InfoCond: return sInfoCond; case CSMWorld::Columns::ColumnId_InfoCondComp: return sInfoCondComp; - case CSMWorld::Columns::ColumnId_RaceSkill: return sSkills; default: return 0; } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 2f66542b1..5deaf65cb 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -189,7 +189,7 @@ namespace CSMWorld ColumnId_RotX = 174, ColumnId_RotY = 175, ColumnId_RotZ = 176, - ColumnId_Skill = 177, + // unused ColumnId_OwnerGlobal = 178, ColumnId_DefaultProfile = 179, ColumnId_BypassNewGame = 180, @@ -276,22 +276,22 @@ namespace CSMWorld ColumnId_NpcSkills = 249, ColumnId_UChar = 250, ColumnId_NpcMisc = 251, - ColumnId_NpcLevel = 252, + ColumnId_Level = 252, ColumnId_NpcFactionID = 253, - ColumnId_NpcHealth = 254, - ColumnId_NpcMana = 255, - ColumnId_NpcFatigue = 256, + // unused + ColumnId_Mana = 255, + ColumnId_Fatigue = 256, ColumnId_NpcDisposition = 257, ColumnId_NpcReputation = 258, ColumnId_NpcRank = 259, - ColumnId_NpcGold = 260, + ColumnId_Gold = 260, ColumnId_NpcPersistence = 261, ColumnId_RaceAttributes = 262, ColumnId_RaceMaleValue = 263, ColumnId_RaceFemaleValue = 264, ColumnId_RaceSkillBonus = 265, - ColumnId_RaceSkill = 266, + // unused ColumnId_RaceBonus = 267, ColumnId_Interior = 268, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index ab9c8f74e..a27ab5094 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -140,7 +140,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceAttributeAdapter())); mRaces.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_RaceAttributes, ColumnBase::Display_String, + new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute, ColumnBase::Flag_Dialogue, false)); mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_RaceMaleValue, ColumnBase::Display_Integer)); @@ -151,7 +151,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceSkillsBonusAdapter())); mRaces.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_RaceSkill, ColumnBase::Display_RaceSkill)); + new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact)); mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_RaceBonus, ColumnBase::Display_Integer)); diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index dc5cd2299..002838c67 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -922,7 +922,7 @@ namespace CSMWorld switch (subColIndex) { - case 0: return QString(ESM::Attribute::sAttributeNames[subRowIndex].c_str()); + case 0: return subRowIndex; case 1: return race.mData.mAttributeValues[subRowIndex].mMale; case 2: return race.mData.mAttributeValues[subRowIndex].mFemale; default: throw std::runtime_error("Race Attribute subcolumn index out of range"); diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index c8cca5c3d..6a881d0af 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -694,18 +694,7 @@ QVariant CSMWorld::NpcAttributesRefIdAdapter::getNestedData (const RefIdColumn * const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt52; if (subColIndex == 0) - switch (subRowIndex) - { - case 0: return QString("Strength"); - case 1: return QString("Intelligence"); - case 2: return QString("Willpower"); - case 3: return QString("Agility"); - case 4: return QString("Speed"); - case 5: return QString("Endurance"); - case 6: return QString("Personality"); - case 7: return QString("Luck"); - default: return QVariant(); // throw an exception here? - } + return subRowIndex; else if (subColIndex == 1) switch (subRowIndex) { @@ -815,7 +804,7 @@ QVariant CSMWorld::NpcSkillsRefIdAdapter::getNestedData (const RefIdColumn *colu throw std::runtime_error ("index out of range"); if (subColIndex == 0) - return QString(ESM::Skill::sSkillNames[subRowIndex].c_str()); + return subRowIndex; else if (subColIndex == 1) return static_cast(npcStruct.mSkills[subRowIndex]); else diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index c4d110754..b20e12fef 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -439,7 +439,7 @@ CSMWorld::RefIdCollection::RefIdCollection() attrMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcAttributesRefIdAdapter())); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), attrMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcAttributes, CSMWorld::ColumnBase::Display_String, false, false)); + new RefIdColumn (Columns::ColumnId_Attribute, CSMWorld::ColumnBase::Display_Attribute, false, false)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_Integer)); @@ -451,7 +451,7 @@ CSMWorld::RefIdCollection::RefIdCollection() skillsMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcSkillsRefIdAdapter())); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), skillsMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcSkills, CSMWorld::ColumnBase::Display_String, false, false)); + new RefIdColumn (Columns::ColumnId_SkillImpact, CSMWorld::ColumnBase::Display_SkillImpact, false, false)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_Integer)); @@ -463,15 +463,15 @@ CSMWorld::RefIdCollection::RefIdCollection() miscMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcMiscRefIdAdapter())); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), miscMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcLevel, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_Level, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_NpcFactionID, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcHealth, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_Health, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcMana, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_Mana, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcFatigue, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_Fatigue, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_NpcDisposition, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( @@ -479,7 +479,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_NpcRank, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcGold, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_Gold, CSMWorld::ColumnBase::Display_Integer)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_NpcPersistence, CSMWorld::ColumnBase::Display_Boolean)); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 60219d319..ca4ad2d00 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -104,7 +104,6 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_AiPackageType, CSMWorld::Columns::ColumnId_AiPackageType, false }, { CSMWorld::ColumnBase::Display_InfoCondFunc, CSMWorld::Columns::ColumnId_InfoCondFunc, false }, { CSMWorld::ColumnBase::Display_InfoCondComp, CSMWorld::Columns::ColumnId_InfoCondComp, false }, - { CSMWorld::ColumnBase::Display_RaceSkill, CSMWorld::Columns::ColumnId_RaceSkill, true }, }; for (std::size_t i=0; i Date: Sat, 12 Sep 2015 10:00:23 +1000 Subject: [PATCH 371/419] Add missing fields for editing creatures. - Should resolve resolve bugs #2878 (level), #2901 (gold) and #2889 (health). - Moved Soul, Combat, Magic and Stealth editing to dialogue only (to be consistent with editing NPCs) --- apps/opencs/model/world/columns.cpp | 7 + apps/opencs/model/world/columns.hpp | 7 + apps/opencs/model/world/refidadapterimp.cpp | 313 ++++++++++++++++++-- apps/opencs/model/world/refidadapterimp.hpp | 98 +++++- apps/opencs/model/world/refidcollection.cpp | 64 +++- 5 files changed, 453 insertions(+), 36 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 9f39be5f3..44ec9d384 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -311,6 +311,13 @@ namespace CSMWorld { ColumnId_FileDescription, "File Description" }, { ColumnId_Author, "Author" }, + { ColumnId_CreatureAttributes, "Creature Attributes" }, + { ColumnId_AttributeValue, "Attrib Value" }, + { ColumnId_CreatureAttack, "Creature Attack" }, + { ColumnId_MinAttack, "Min Attack" }, + { ColumnId_MaxAttack, "Max Attack" }, + { ColumnId_CreatureMisc, "Creature Misc" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 5deaf65cb..981599e53 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -309,6 +309,13 @@ namespace CSMWorld ColumnId_MinMagnitude = 278, ColumnId_MaxMagnitude = 279, + ColumnId_CreatureAttributes = 280, + ColumnId_AttributeValue = 281, + ColumnId_CreatureAttack = 282, + ColumnId_MinAttack = 283, + ColumnId_MaxAttack = 284, + ColumnId_CreatureMisc = 285, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 6a881d0af..da0cc0760 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -296,12 +296,11 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns) : ActorColumns (actorColumns), mType(NULL), - mSoul(NULL), mScale(NULL), mOriginal(NULL), - mCombat(NULL), - mMagic(NULL), - mStealth(NULL) + mAttributes(NULL), + mAttacks(NULL), + mMisc(NULL) {} CSMWorld::CreatureRefIdAdapter::CreatureRefIdAdapter (const CreatureColumns& columns) @@ -317,23 +316,20 @@ QVariant CSMWorld::CreatureRefIdAdapter::getData (const RefIdColumn *column, con if (column==mColumns.mType) return record.get().mData.mType; - if (column==mColumns.mSoul) - return record.get().mData.mSoul; - if (column==mColumns.mScale) return record.get().mScale; if (column==mColumns.mOriginal) return QString::fromUtf8 (record.get().mOriginal.c_str()); - if (column==mColumns.mCombat) - return static_cast (record.get().mData.mCombat); + if (column==mColumns.mAttributes) + return true; // Required to show nested tables in dialogue subview - if (column==mColumns.mMagic) - return static_cast (record.get().mData.mMagic); + if (column==mColumns.mAttacks) + return true; // Required to show nested tables in dialogue subview - if (column==mColumns.mStealth) - return static_cast (record.get().mData.mStealth); + if (column==mColumns.mMisc) + return true; // Required to show nested items in dialogue subview std::map::const_iterator iter = mColumns.mFlags.find (column); @@ -354,18 +350,10 @@ void CSMWorld::CreatureRefIdAdapter::setData (const RefIdColumn *column, RefIdDa if (column==mColumns.mType) creature.mData.mType = value.toInt(); - else if (column==mColumns.mSoul) - creature.mData.mSoul = value.toInt(); else if (column==mColumns.mScale) creature.mScale = value.toFloat(); else if (column==mColumns.mOriginal) creature.mOriginal = value.toString().toUtf8().constData(); - else if (column==mColumns.mCombat) - creature.mData.mCombat = value.toInt(); - else if (column==mColumns.mMagic) - creature.mData.mMagic = value.toInt(); - else if (column==mColumns.mStealth) - creature.mData.mStealth = value.toInt(); else { std::map::const_iterator iter = @@ -964,6 +952,289 @@ int CSMWorld::NpcMiscRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, return 1; // fixed at size 1 } +CSMWorld::CreatureAttributesRefIdAdapter::CreatureAttributesRefIdAdapter() +{} + +void CSMWorld::CreatureAttributesRefIdAdapter::addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::CreatureAttributesRefIdAdapter::removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::CreatureAttributesRefIdAdapter::setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + ESM::Creature creature = record.get(); + + // store the whole struct + creature.mData = + static_cast > &>(nestedTable).mNestedTable.at(0); + + record.setModified (creature); +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::CreatureAttributesRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + + // return the whole struct + std::vector wrap; + wrap.push_back(record.get().mData); + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(wrap); +} + +QVariant CSMWorld::CreatureAttributesRefIdAdapter::getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + + const ESM::Creature creature = record.get(); + + if (subColIndex == 0) + return subRowIndex; + else if (subColIndex == 1) + switch (subRowIndex) + { + case 0: return creature.mData.mStrength; + case 1: return creature.mData.mIntelligence; + case 2: return creature.mData.mWillpower; + case 3: return creature.mData.mAgility; + case 4: return creature.mData.mSpeed; + case 5: return creature.mData.mEndurance; + case 6: return creature.mData.mPersonality; + case 7: return creature.mData.mLuck; + default: return QVariant(); // throw an exception here? + } + else + return QVariant(); // throw an exception here? +} + +void CSMWorld::CreatureAttributesRefIdAdapter::setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Creature))); + ESM::Creature creature = record.get(); + + if (subColIndex == 1) + switch(subRowIndex) + { + case 0: creature.mData.mStrength = value.toInt(); break; + case 1: creature.mData.mIntelligence = value.toInt(); break; + case 2: creature.mData.mWillpower = value.toInt(); break; + case 3: creature.mData.mAgility = value.toInt(); break; + case 4: creature.mData.mSpeed = value.toInt(); break; + case 5: creature.mData.mEndurance = value.toInt(); break; + case 6: creature.mData.mPersonality = value.toInt(); break; + case 7: creature.mData.mLuck = value.toInt(); break; + default: return; // throw an exception here? + } + else + return; // throw an exception here? + + record.setModified (creature); +} + +int CSMWorld::CreatureAttributesRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return 2; +} + +int CSMWorld::CreatureAttributesRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + // There are 8 attributes + return 8; +} + +CSMWorld::CreatureAttackRefIdAdapter::CreatureAttackRefIdAdapter() +{} + +void CSMWorld::CreatureAttackRefIdAdapter::addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::CreatureAttackRefIdAdapter::removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::CreatureAttackRefIdAdapter::setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + ESM::Creature creature = record.get(); + + // store the whole struct + creature.mData = + static_cast > &>(nestedTable).mNestedTable.at(0); + + record.setModified (creature); +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::CreatureAttackRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + + // return the whole struct + std::vector wrap; + wrap.push_back(record.get().mData); + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(wrap); +} + +QVariant CSMWorld::CreatureAttackRefIdAdapter::getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + + const ESM::Creature creature = record.get(); + + if (subRowIndex < 0 || subRowIndex > 2 || subColIndex < 0 || subColIndex > 2) + throw std::runtime_error ("index out of range"); + + if (subColIndex == 0) + return subRowIndex + 1; + else if (subColIndex < 3) // 1 or 2 + return creature.mData.mAttack[(subRowIndex * 2) + (subColIndex - 1)]; + else + return QVariant(); // throw an exception here? +} + +void CSMWorld::CreatureAttackRefIdAdapter::setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Creature))); + ESM::Creature creature = record.get(); + + if (subRowIndex < 0 || subRowIndex > 2) + throw std::runtime_error ("index out of range"); + + if (subColIndex == 1 || subColIndex == 2) + creature.mData.mAttack[(subRowIndex * 2) + (subColIndex - 1)] = value.toInt(); + else + return; // throw an exception here? + + record.setModified (creature); +} + +int CSMWorld::CreatureAttackRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return 3; +} + +int CSMWorld::CreatureAttackRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + // There are 3 attacks + return 3; +} + +CSMWorld::CreatureMiscRefIdAdapter::CreatureMiscRefIdAdapter() +{} + +CSMWorld::CreatureMiscRefIdAdapter::~CreatureMiscRefIdAdapter() +{} + +void CSMWorld::CreatureMiscRefIdAdapter::addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const +{ + throw std::logic_error ("cannot add a row to a fixed table"); +} + +void CSMWorld::CreatureMiscRefIdAdapter::removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const +{ + throw std::logic_error ("cannot remove a row to a fixed table"); +} + +void CSMWorld::CreatureMiscRefIdAdapter::setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const +{ + throw std::logic_error ("table operation not supported"); +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::CreatureMiscRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const +{ + throw std::logic_error ("table operation not supported"); +} + +QVariant CSMWorld::CreatureMiscRefIdAdapter::getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); + + const ESM::Creature creature = record.get(); + + switch (subColIndex) + { + case 0: return creature.mData.mLevel; + case 1: return creature.mData.mHealth; + case 2: return creature.mData.mMana; + case 3: return creature.mData.mFatigue; + case 4: return creature.mData.mSoul; + case 5: return creature.mData.mCombat; + case 6: return creature.mData.mMagic; + case 7: return creature.mData.mStealth; + case 8: return creature.mData.mGold; + default: return QVariant(); // throw an exception here? + } +} + +void CSMWorld::CreatureMiscRefIdAdapter::setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Creature))); + ESM::Creature creature = record.get(); + + switch(subColIndex) + { + case 0: creature.mData.mLevel = value.toInt(); break; + case 1: creature.mData.mHealth = value.toInt(); break; + case 2: creature.mData.mMana = value.toInt(); break; + case 3: creature.mData.mFatigue = value.toInt(); break; + case 4: creature.mData.mSoul = value.toInt(); break; + case 5: creature.mData.mCombat = value.toInt(); break; + case 6: creature.mData.mMagic = value.toInt(); break; + case 7: creature.mData.mStealth = value.toInt(); break; + case 8: creature.mData.mGold = value.toInt(); break; + default: return; // throw an exception here? + } + + record.setModified (creature); +} + +int CSMWorld::CreatureMiscRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return 9; // Level, Health, Mana, Fatigue, Soul, Combat, Magic, Steath, Gold +} + +int CSMWorld::CreatureMiscRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + return 1; // fixed at size 1 +} + CSMWorld::WeaponColumns::WeaponColumns (const EnchantableColumns& columns) : EnchantableColumns (columns) {} diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 5ceb3325a..41f254355 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -696,12 +696,11 @@ namespace CSMWorld { std::map mFlags; const RefIdColumn *mType; - const RefIdColumn *mSoul; const RefIdColumn *mScale; const RefIdColumn *mOriginal; - const RefIdColumn *mCombat; - const RefIdColumn *mMagic; - const RefIdColumn *mStealth; + const RefIdColumn *mAttributes; + const RefIdColumn *mAttack; + const RefIdColumn *mMisc; CreatureColumns (const ActorColumns& actorColumns); }; @@ -938,6 +937,97 @@ namespace CSMWorld virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; }; + class CreatureAttributesRefIdAdapter : public NestedRefIdAdapterBase + { + public: + + CreatureAttributesRefIdAdapter (); + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const; + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const; + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const; + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const; + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + }; + + class CreatureAttackRefIdAdapter : public NestedRefIdAdapterBase + { + public: + + CreatureAttackRefIdAdapter (); + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const; + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const; + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const; + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const; + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + }; + + class CreatureMiscRefIdAdapter : public NestedRefIdAdapterBase + { + CreatureMiscRefIdAdapter (const CreatureMiscRefIdAdapter&); + CreatureMiscRefIdAdapter& operator= (const CreatureMiscRefIdAdapter&); + + public: + + CreatureMiscRefIdAdapter (); + virtual ~CreatureMiscRefIdAdapter(); + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const; + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const; + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const; + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const; + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + }; + template class EffectsListAdapter; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index b20e12fef..f8c9e28fe 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -297,21 +297,10 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_CreatureType, ColumnBase::Display_CreatureType)); creatureColumns.mType = &mColumns.back(); - mColumns.push_back (RefIdColumn (Columns::ColumnId_SoulPoints, ColumnBase::Display_Integer)); - creatureColumns.mSoul = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_Scale, ColumnBase::Display_Float)); creatureColumns.mScale = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_OriginalCreature, ColumnBase::Display_Creature)); creatureColumns.mOriginal = &mColumns.back(); - mColumns.push_back ( - RefIdColumn (Columns::ColumnId_CombatState, ColumnBase::Display_Integer)); - creatureColumns.mCombat = &mColumns.back(); - mColumns.push_back ( - RefIdColumn (Columns::ColumnId_MagicState, ColumnBase::Display_Integer)); - creatureColumns.mMagic = &mColumns.back(); - mColumns.push_back ( - RefIdColumn (Columns::ColumnId_StealthState, ColumnBase::Display_Integer)); - creatureColumns.mStealth = &mColumns.back(); static const struct { @@ -350,6 +339,59 @@ CSMWorld::RefIdCollection::RefIdCollection() creatureColumns.mFlags.insert (std::make_pair (respawn, ESM::Creature::Respawn)); + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureAttributes, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + creatureColumns.mAttributes = &mColumns.back(); + std::map creaAttrMap; + creaAttrMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureAttributesRefIdAdapter())); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), creaAttrMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Attribute, CSMWorld::ColumnBase::Display_Attribute, false, false)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_AttributeValue, CSMWorld::ColumnBase::Display_Integer)); + + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureAttack, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + creatureColumns.mAttacks = &mColumns.back(); + std::map attackMap; + attackMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureAttackRefIdAdapter())); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), attackMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_CreatureAttack, CSMWorld::ColumnBase::Display_Integer, false, false)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_MinAttack, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_MaxAttack, CSMWorld::ColumnBase::Display_Integer)); + + // Nested list + mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureMisc, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List)); + creatureColumns.mMisc = &mColumns.back(); + std::map creaMiscMap; + creaMiscMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureMiscRefIdAdapter())); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), creaMiscMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Level, CSMWorld::ColumnBase::Display_Integer, + ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Health, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Mana, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Fatigue, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_SoulPoints, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_CombatState, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_MagicState, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_StealthState, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_Gold, CSMWorld::ColumnBase::Display_Integer)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_OpenSound, ColumnBase::Display_Sound)); const RefIdColumn *openSound = &mColumns.back(); From 45aee1b5088cb110e06540356670b806887f7372 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 12 Sep 2015 10:15:32 +1000 Subject: [PATCH 372/419] Remove AI flag from the UI and instead auto-detect whether to save AIDT records. Should resolve bug #2879. --- apps/opencs/model/world/columns.cpp | 1 - apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/refidadapterimp.hpp | 8 +------- apps/opencs/model/world/refidcollection.cpp | 2 -- components/esm/loadcrea.cpp | 7 ++++++- components/esm/loadnpc.cpp | 7 ++++++- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 44ec9d384..2e0a697a5 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -71,7 +71,6 @@ namespace CSMWorld { ColumnId_Weight, "Weight" }, { ColumnId_EnchantmentPoints, "Enchantment Points" }, { ColumnId_Quality, "Quality" }, - { ColumnId_Ai, "AI" }, { ColumnId_AiHello, "AI Hello" }, { ColumnId_AiFlee, "AI Flee" }, { ColumnId_AiFight, "AI Fight" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 981599e53..fb25004ec 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -65,7 +65,7 @@ namespace CSMWorld ColumnId_Weight = 50, ColumnId_EnchantmentPoints = 51, ColumnId_Quality = 52, - ColumnId_Ai = 53, + // unused ColumnId_AiHello = 54, ColumnId_AiFlee = 55, ColumnId_AiFight = 56, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 41f254355..ae446599e 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -479,7 +479,6 @@ namespace CSMWorld struct ActorColumns : public NameColumns { - const RefIdColumn *mHasAi; const RefIdColumn *mHello; const RefIdColumn *mFlee; const RefIdColumn *mFight; @@ -524,9 +523,6 @@ namespace CSMWorld const Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); - if (column==mActors.mHasAi) - return record.get().mHasAI!=0; - if (column==mActors.mHello) return record.get().mAiData.mHello; @@ -568,9 +564,7 @@ namespace CSMWorld data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); RecordT record2 = record.get(); - if (column==mActors.mHasAi) - record2.mHasAI = value.toInt(); - else if (column==mActors.mHello) + if (column==mActors.mHello) record2.mAiData.mHello = value.toInt(); else if (column==mActors.mFlee) record2.mAiData.mFlee = value.toInt(); diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index f8c9e28fe..d7b7cedfa 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -113,8 +113,6 @@ CSMWorld::RefIdCollection::RefIdCollection() ActorColumns actorsColumns (nameColumns); - mColumns.push_back (RefIdColumn (Columns::ColumnId_Ai, ColumnBase::Display_Boolean)); - actorsColumns.mHasAi = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_AiHello, ColumnBase::Display_Integer)); actorsColumns.mHello = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_AiFlee, ColumnBase::Display_Integer)); diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 50c47349c..8c4f49e45 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -96,7 +96,12 @@ namespace ESM { mInventory.save(esm); mSpells.save(esm); - if (mHasAI) { + if (mAiData.mHello != 0 + || mAiData.mFight != 0 + || mAiData.mFlee != 0 + || mAiData.mAlarm != 0 + || mAiData.mServices != 0) + { esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); } mTransport.save(esm); diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 44d298785..67a437176 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -121,7 +121,12 @@ namespace ESM mInventory.save(esm); mSpells.save(esm); - if (mHasAI) { + if (mAiData.mHello != 0 + || mAiData.mFight != 0 + || mAiData.mFlee != 0 + || mAiData.mAlarm != 0 + || mAiData.mServices != 0) + { esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); } From 192f01e3ac5db4f0d1d9d78c2a419b274f307bb1 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 12 Sep 2015 10:17:14 +1000 Subject: [PATCH 373/419] Set default creature scale to 1. Partially resolves bug #2880. (no creature verifier yet) --- components/esm/loadcrea.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 8c4f49e45..fb235e6b3 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -120,7 +120,7 @@ namespace ESM { for (int i=0; i<6; ++i) mData.mAttack[i] = 0; mData.mGold = 0; mFlags = 0; - mScale = 0; + mScale = 1.f; mModel.clear(); mName.clear(); mScript.clear(); From 1365b8edd1f0a20e97ccb9a30cd74a6dc97c44bd Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 12 Sep 2015 11:18:07 +1000 Subject: [PATCH 374/419] Fix typo. --- apps/opencs/model/world/refidadapterimp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index ae446599e..53da63806 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -693,7 +693,7 @@ namespace CSMWorld const RefIdColumn *mScale; const RefIdColumn *mOriginal; const RefIdColumn *mAttributes; - const RefIdColumn *mAttack; + const RefIdColumn *mAttacks; const RefIdColumn *mMisc; CreatureColumns (const ActorColumns& actorColumns); From 8e2fe1985d8a794aaf70173c71e7c63cd4ac3f1a Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 12 Sep 2015 14:17:46 +1200 Subject: [PATCH 375/419] Fixed errors pointed out by Zini. 1. Removed "Actor" from name of function isActorNearInactiveCell(). 2. Corrected case of CoordinateConverter member function names. --- apps/openmw/mwmechanics/aipackage.cpp | 6 +++--- apps/openmw/mwmechanics/aipackage.hpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 4 ++-- apps/openmw/mwmechanics/coordinateconverter.cpp | 8 ++++---- apps/openmw/mwmechanics/coordinateconverter.hpp | 8 ++++---- apps/openmw/mwmechanics/pathfinding.cpp | 8 ++++---- apps/openmw/mwrender/pathgrid.cpp | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index c4091c63e..1af0f1c5a 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -36,7 +36,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po //... At current time, this test is unnecessary. AI shuts down when actor is more than 7168 //... units from player, and exterior cells are 8192 units long and wide. //... But AI processing distance may increase in the future. - if (isActorNearInactiveCell(pos)) + if (isNearInactiveCell(pos)) { actor.getClass().getMovementSettings(actor).mPosition[1] = 0; return false; @@ -114,14 +114,14 @@ bool MWMechanics::AiPackage::isTargetMagicallyHidden(const MWWorld::Ptr& target) || (magicEffects.get(ESM::MagicEffect::Chameleon).getMagnitude() > 75); } -bool MWMechanics::AiPackage::isActorNearInactiveCell(const ESM::Position& actorPos) +bool MWMechanics::AiPackage::isNearInactiveCell(const ESM::Position& actorPos) { const ESM::Cell* playerCell(getPlayer().getCell()->getCell()); if (playerCell->isExterior()) { // get actor's distance from origin of center cell osg::Vec3f actorOffset(actorPos.asVec3()); - CoordinateConverter(playerCell).ToLocal(actorOffset); + CoordinateConverter(playerCell).toLocal(actorOffset); // currently assumes 3 x 3 grid for exterior cells, with player at center cell. // ToDo: (Maybe) use "exterior cell load distance" setting to get count of actual active cells diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index befd159bf..e16d66dbe 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -88,7 +88,7 @@ namespace MWMechanics private: void evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos); - bool isActorNearInactiveCell(const ESM::Position& actorPos); + bool isNearInactiveCell(const ESM::Position& actorPos); }; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b789c4428..a3fdc69cc 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -588,7 +588,7 @@ namespace MWMechanics void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell) { - CoordinateConverter(cell).ToWorld(point); + CoordinateConverter(cell).toWorld(point); } void AiWander::trimAllowedNodes(std::vector& nodes, @@ -746,7 +746,7 @@ namespace MWMechanics { // get NPC's position in local (i.e. cell) co-ordinates osg::Vec3f npcPos(mInitialActorPosition); - CoordinateConverter(cell).ToLocal(npcPos); + CoordinateConverter(cell).toLocal(npcPos); // mAllowedNodes for this actor with pathgrid point indexes based on mDistance // NOTE: mPoints and mAllowedNodes are in local co-ordinates diff --git a/apps/openmw/mwmechanics/coordinateconverter.cpp b/apps/openmw/mwmechanics/coordinateconverter.cpp index 583ac41c5..0a2d99f92 100644 --- a/apps/openmw/mwmechanics/coordinateconverter.cpp +++ b/apps/openmw/mwmechanics/coordinateconverter.cpp @@ -15,25 +15,25 @@ namespace MWMechanics } } - void CoordinateConverter::ToWorld(ESM::Pathgrid::Point& point) + void CoordinateConverter::toWorld(ESM::Pathgrid::Point& point) { point.mX += mCellX; point.mY += mCellY; } - void CoordinateConverter::ToWorld(osg::Vec3f& point) + void CoordinateConverter::toWorld(osg::Vec3f& point) { point.x() += static_cast(mCellX); point.y() += static_cast(mCellY); } - void CoordinateConverter::ToLocal(osg::Vec3f& point) + void CoordinateConverter::toLocal(osg::Vec3f& point) { point.x() -= static_cast(mCellX); point.y() -= static_cast(mCellY); } - osg::Vec3f CoordinateConverter::ToLocalVec3(const ESM::Pathgrid::Point& point) + osg::Vec3f CoordinateConverter::toLocalVec3(const ESM::Pathgrid::Point& point) { return osg::Vec3f( static_cast(point.mX - mCellX), diff --git a/apps/openmw/mwmechanics/coordinateconverter.hpp b/apps/openmw/mwmechanics/coordinateconverter.hpp index 2c4d3d3ba..cd855e84a 100644 --- a/apps/openmw/mwmechanics/coordinateconverter.hpp +++ b/apps/openmw/mwmechanics/coordinateconverter.hpp @@ -18,15 +18,15 @@ namespace MWMechanics CoordinateConverter(const ESM::Cell* cell); /// in-place conversion from local to world - void ToWorld(ESM::Pathgrid::Point& point); + void toWorld(ESM::Pathgrid::Point& point); /// in-place conversion from local to world - void ToWorld(osg::Vec3f& point); + void toWorld(osg::Vec3f& point); /// in-place conversion from world to local - void ToLocal(osg::Vec3f& point); + void toLocal(osg::Vec3f& point); - osg::Vec3f ToLocalVec3(const ESM::Pathgrid::Point& point); + osg::Vec3f toLocalVec3(const ESM::Pathgrid::Point& point); private: int mCellX; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index daab32136..f26d3e109 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -207,10 +207,10 @@ namespace MWMechanics // outside an area enclosed by walls, but there is a pathgrid // point right behind the wall that is closer than any pathgrid // point outside the wall - osg::Vec3f startPointInLocalCoords(converter.ToLocalVec3(startPoint)); + osg::Vec3f startPointInLocalCoords(converter.toLocalVec3(startPoint)); int startNode = getClosestPoint(mPathgrid, startPointInLocalCoords); - osg::Vec3f endPointInLocalCoords(converter.ToLocalVec3(endPoint)); + osg::Vec3f endPointInLocalCoords(converter.toLocalVec3(endPoint)); std::pair endNode = getClosestReachablePoint(mPathgrid, cell, endPointInLocalCoords, startNode); @@ -223,7 +223,7 @@ namespace MWMechanics if(startNode == endNode.first) { ESM::Pathgrid::Point temp(mPathgrid->mPoints[startNode]); - converter.ToWorld(temp); + converter.toWorld(temp); mPath.push_back(temp); } else @@ -233,7 +233,7 @@ namespace MWMechanics // convert supplied path to world co-ordinates for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) { - converter.ToWorld(*iter); + converter.toWorld(*iter); } } diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index bd22446de..ae8bda1fb 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -208,7 +208,7 @@ void Pathgrid::enableCellPathgrid(const MWWorld::CellStore *store) if (!pathgrid) return; osg::Vec3f cellPathGridPos(0, 0, 0); - MWMechanics::CoordinateConverter(store->getCell()).ToWorld(cellPathGridPos); + MWMechanics::CoordinateConverter(store->getCell()).toWorld(cellPathGridPos); osg::ref_ptr cellPathGrid = new osg::PositionAttitudeTransform; cellPathGrid->setPosition(cellPathGridPos); From 0feae19140f6c869fc025772432183a00059e570 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 14 Sep 2015 19:57:22 +1200 Subject: [PATCH 376/419] AiCombat use evadeObstacles() from AiPackage. --- apps/openmw/mwmechanics/aicombat.cpp | 7 +++---- apps/openmw/mwmechanics/aicombat.hpp | 2 +- apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwmechanics/aipackage.hpp | 3 ++- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 5ea3ba6a3..58f74a87f 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -200,7 +200,7 @@ namespace MWMechanics //Update every frame storage.updateCombatMove(duration); - updateActorsMovement(actor, storage.mMovement); + updateActorsMovement(actor, duration, storage.mMovement); storage.updateAttack(characterController); storage.mActionCooldown -= duration; @@ -494,7 +494,7 @@ namespace MWMechanics return false; } - void AiCombat::updateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& desiredMovement) + void AiCombat::updateActorsMovement(const MWWorld::Ptr& actor, float duration, MWMechanics::Movement& desiredMovement) { MWMechanics::Movement& actorMovementSettings = actor.getClass().getMovementSettings(actor); if (mPathFinder.isPathConstructed()) @@ -506,8 +506,7 @@ namespace MWMechanics } else { - zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); - actorMovementSettings.mPosition[1] = 1; + evadeObstacles(actor, duration, pos); } } else diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 73d0254f3..93d630529 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -65,7 +65,7 @@ namespace MWMechanics AiCombatStorage& storage, MWWorld::Ptr target); /// Transfer desired movement (from AiCombatStorage) to Actor - void updateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& movement); + void updateActorsMovement(const MWWorld::Ptr& actor, float duration, MWMechanics::Movement& movement); void rotateActorOnAxis(const MWWorld::Ptr& actor, int axis, MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement); }; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 1af0f1c5a..1cd9649f7 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -77,7 +77,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po return false; } -void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos) +void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float duration, const ESM::Position& pos) { zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index e16d66dbe..3f227a49a 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -78,6 +78,8 @@ namespace MWMechanics virtual bool doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell); + void evadeObstacles(const MWWorld::Ptr& actor, float duration, const ESM::Position& pos); + // TODO: all this does not belong here, move into temporary storage PathFinder mPathFinder; ObstacleCheck mObstacleCheck; @@ -87,7 +89,6 @@ namespace MWMechanics ESM::Pathgrid::Point mPrevDest; private: - void evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos); bool isNearInactiveCell(const ESM::Position& actorPos); }; From 6c6fc662ef80b5c99fc2b3723faa410edb37868c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Sep 2015 15:14:18 +0200 Subject: [PATCH 377/419] Add CONTRIBUTING.md --- CONTRIBUTING.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..879113a51 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,16 @@ +Description +=========== + +Your pull request description should include: + +* Summary of the changes made +* Reasoning / motivation behind the change +* What testing you have carried out to verify the change +* If applicable, a link back to the bug report or forum discussion that prompted the change + +Other notes +=========== + +* Separate your work into multiple pull requests whenever possible. As a rule of thumb, each feature and each bugfix should go into a separate PR, unless they are closely related or dependent upon each other. Small pull requests are easier to review, and are less likely to require further changes before we can merge them. A "mega" pull request with lots of unrelated commits in it is likely to get held up in review for a long time. +* Feel free to submit incomplete pull requests. Even if the work can not be merged yet, pull requests are a great place to collect early feedback. Just make sure to mark it as *[Incomplete]* or *[Do not merge yet]* in the title. +* If you plan on contributing often, please read the [Developer Reference](https://wiki.openmw.org/index.php?title=Developer_Reference) on our wiki, especially the [Policies and Standards](https://wiki.openmw.org/index.php?title=Policies_and_Standards). From 5fde9149594f6503c192f9d949d8f0bb3f3df5ba Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 14 Sep 2015 17:17:38 +0200 Subject: [PATCH 378/419] CONTRIBUTING.md: clarify "if applicable" --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 879113a51..a9cd6a690 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,12 +1,12 @@ Description =========== -Your pull request description should include: +Your pull request description should include (if applicable): +* A link back to the bug report or forum discussion that prompted the change * Summary of the changes made * Reasoning / motivation behind the change * What testing you have carried out to verify the change -* If applicable, a link back to the bug report or forum discussion that prompted the change Other notes =========== From 2a981a5272e4d9bc513c3555c9dbcb0de2a31879 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Sep 2015 13:58:07 +0200 Subject: [PATCH 379/419] make sure local variables are loaded when trying to access them from outside of a script (Fixes #2659) --- apps/openmw/mwscript/globalscripts.cpp | 11 +++---- apps/openmw/mwscript/locals.cpp | 39 +++++++++++++++++++++-- apps/openmw/mwscript/locals.hpp | 26 +++++++++++++-- apps/openmw/mwscript/scriptmanagerimp.cpp | 2 +- apps/openmw/mwworld/refdata.cpp | 23 ++++--------- apps/openmw/mwworld/refdata.hpp | 6 ++-- 6 files changed, 75 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index f339fa520..6074a12d0 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -198,13 +198,12 @@ namespace MWScript if (iter==mScripts.end()) { - if (const ESM::Script *script = mStore.get().find (name)) - { - GlobalScriptDesc desc; - desc.mLocals.configure (*script); + const ESM::Script *script = mStore.get().find (name); - iter = mScripts.insert (std::make_pair (name, desc)).first; - } + GlobalScriptDesc desc; + desc.mLocals.configure (*script); + + iter = mScripts.insert (std::make_pair (name2, desc)).first; } return iter->second.mLocals; diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index a18d0d5ae..ee93ea2e7 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -9,13 +9,32 @@ #include "../mwbase/environment.hpp" #include "../mwbase/scriptmanager.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/esmstore.hpp" #include namespace MWScript { - void Locals::configure (const ESM::Script& script) + void Locals::ensure (const std::string& scriptName) { + if (!mInitialised) + { + const ESM::Script *script = MWBase::Environment::get().getWorld()->getStore(). + get().find (scriptName); + + configure (*script); + } + } + + Locals::Locals() : mInitialised (false) {} + + bool Locals::configure (const ESM::Script& script) + { + if (mInitialised) + return false; + const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals (script.mId); @@ -25,6 +44,9 @@ namespace MWScript mLongs.resize (locals.get ('l').size(), 0); mFloats.clear(); mFloats.resize (locals.get ('f').size(), 0); + + mInitialised = true; + return true; } bool Locals::isEmpty() const @@ -36,6 +58,8 @@ namespace MWScript { try { + ensure (script); + const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script); int index = locals.getIndex(var); @@ -49,6 +73,8 @@ namespace MWScript int Locals::getIntVar(const std::string &script, const std::string &var) { + ensure (script); + const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script); int index = locals.getIndex(var); char type = locals.getType(var); @@ -73,6 +99,8 @@ namespace MWScript bool Locals::setVarByInt(const std::string& script, const std::string& var, int val) { + ensure (script); + const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script); int index = locals.getIndex(var); char type = locals.getType(var); @@ -94,8 +122,11 @@ namespace MWScript return false; } - void Locals::write (ESM::Locals& locals, const std::string& script) const + bool Locals::write (ESM::Locals& locals, const std::string& script) const { + if (!mInitialised) + return false; + try { const Compiler::Locals& declarations = @@ -132,10 +163,14 @@ namespace MWScript catch (const Compiler::SourceException&) { } + + return true; } void Locals::read (const ESM::Locals& locals, const std::string& script) { + ensure (script); + try { const Compiler::Locals& declarations = diff --git a/apps/openmw/mwscript/locals.hpp b/apps/openmw/mwscript/locals.hpp index a9fcf317c..bb4df42bf 100644 --- a/apps/openmw/mwscript/locals.hpp +++ b/apps/openmw/mwscript/locals.hpp @@ -15,30 +15,50 @@ namespace MWScript { class Locals { + bool mInitialised; + + void ensure (const std::string& scriptName); + public: std::vector mShorts; std::vector mLongs; std::vector mFloats; + Locals(); + /// Are there any locals? + /// + /// \note Will return false, if locals have not been configured yet. bool isEmpty() const; - void configure (const ESM::Script& script); + /// \return Did the state of *this change from uninitialised to initialised? + bool configure (const ESM::Script& script); /// @note var needs to be in lowercase + /// + /// \note Locals will be automatically configured first, if necessary bool setVarByInt(const std::string& script, const std::string& var, int val); + /// \note Locals will be automatically configured first, if necessary + // + // \note If it can not be determined if the variable exists, the error will be + // ignored and false will be returned. bool hasVar(const std::string& script, const std::string& var); /// if var does not exist, returns 0 /// @note var needs to be in lowercase + /// + /// \note Locals will be automatically configured first, if necessary int getIntVar (const std::string& script, const std::string& var); - void write (ESM::Locals& locals, const std::string& script) const; + /// \note If locals have not been configured yet, no data is written. + /// + /// \return Locals written? + bool write (ESM::Locals& locals, const std::string& script) const; + /// \note Locals will be automatically configured first, if necessary void read (const ESM::Locals& locals, const std::string& script); }; } #endif - diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 084beb812..b73c9a642 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -170,7 +170,7 @@ namespace MWScript return iter->second; } - if (const ESM::Script *script = mStore.get().find (name2)) + if (const ESM::Script *script = mStore.get().search (name2)) { if (mVerbose) std::cout diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 2062e78d9..88a6fa353 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -14,7 +14,6 @@ namespace MWWorld { mBaseNode = refData.mBaseNode; mLocals = refData.mLocals; - mHasLocals = refData.mHasLocals; mEnabled = refData.mEnabled; mCount = refData.mCount; mPosition = refData.mPosition; @@ -34,7 +33,7 @@ namespace MWWorld } RefData::RefData() - : mBaseNode(0), mDeleted(false), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) + : mBaseNode(0), mDeleted(false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) { for (int i=0; i<3; ++i) { @@ -45,7 +44,7 @@ namespace MWWorld } RefData::RefData (const ESM::CellRef& cellRef) - : mBaseNode(0), mDeleted(false), mHasLocals (false), mEnabled (true), + : mBaseNode(0), mDeleted(false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), mCustomData (0), mChanged(false) // Loading from ESM/ESP files -> assume unchanged @@ -56,13 +55,13 @@ namespace MWWorld } RefData::RefData (const ESM::ObjectState& objectState) - : mBaseNode(0), mDeleted(false), mHasLocals (false), + : mBaseNode(0), mDeleted(false), mEnabled (objectState.mEnabled != 0), mCount (objectState.mCount), mPosition (objectState.mPosition), mCustomData (0), mChanged(true) // Loading from a savegame -> assume changed - { + { for (int i=0; i<3; ++i) mLocalRotation.rot[i] = objectState.mLocalRotation[i]; } @@ -83,10 +82,7 @@ namespace MWWorld void RefData::write (ESM::ObjectState& objectState, const std::string& scriptId) const { - objectState.mHasLocals = mHasLocals; - - if (mHasLocals) - mLocals.write (objectState.mLocals, scriptId); + objectState.mHasLocals = mLocals.write (objectState.mLocals, scriptId); objectState.mEnabled = mEnabled; objectState.mCount = mCount; @@ -139,13 +135,8 @@ namespace MWWorld void RefData::setLocals (const ESM::Script& script) { - if (!mHasLocals) - { - mLocals.configure (script); - mHasLocals = true; - if (!mLocals.isEmpty()) - mChanged = true; - } + if (mLocals.configure (script) && !mLocals.isEmpty()) + mChanged = true; } void RefData::setCount (int count) diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 61055aa73..4075f62ce 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -31,11 +31,9 @@ namespace MWWorld { osg::PositionAttitudeTransform* mBaseNode; - MWScript::Locals mLocals; // if we find the overhead of heaving a locals - // object in the refdata of refs without a script, - // we can make this a pointer later. + MWScript::Locals mLocals; + bool mDeleted; // separate delete flag used for deletion by a content file - bool mHasLocals; bool mEnabled; int mCount; // 0: deleted From 4d94f38f4b7255fd1abbcdc8d2bd388e604bec04 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Sep 2015 14:57:07 +0200 Subject: [PATCH 380/419] replaced context-sensitive implementation of allowing digits at the beginning of names with a more general implementation (Fixes #1730) --- components/compiler/fileparser.cpp | 2 -- components/compiler/scanner.cpp | 38 +++++++++++++++++------------- components/compiler/scanner.hpp | 3 --- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/components/compiler/fileparser.cpp b/components/compiler/fileparser.cpp index c8a512340..8711d92fe 100644 --- a/components/compiler/fileparser.cpp +++ b/components/compiler/fileparser.cpp @@ -63,7 +63,6 @@ namespace Compiler if (mState==BeginState && keyword==Scanner::K_begin) { mState = NameState; - scanner.allowNameStartingwithDigit(); return true; } @@ -110,7 +109,6 @@ namespace Compiler scanner.scan (mScriptParser); mState = EndNameState; - scanner.allowNameStartingwithDigit(); return true; } diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 5af396d27..f25e69e39 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -47,9 +47,6 @@ namespace Compiler bool Scanner::scanToken (Parser& parser) { - bool allowDigit = mNameStartingWithDigit; - mNameStartingWithDigit = false; - switch (mPutback) { case Putback_Special: @@ -114,7 +111,6 @@ namespace Compiler else if (isWhitespace (c)) { mLoc.mLiteral.clear(); - mNameStartingWithDigit = allowDigit; return true; } else if (c==':') @@ -123,7 +119,7 @@ namespace Compiler mLoc.mLiteral.clear(); return true; } - else if (std::isalpha (c) || c=='_' || c=='"' || (allowDigit && std::isdigit (c))) + else if (std::isalpha (c) || c=='_' || c=='"') { bool cont = false; @@ -179,10 +175,18 @@ namespace Compiler { value += c; } - else if (std::isalpha (c) || c=='_') - error = true; - else if (c=='.' && !error) + else if (isStringCharacter (c)) { + error = true; + value += c; + } + else if (c=='.') + { + if (error) + { + putback (c); + break; + } return scanFloat (value, parser, cont); } else @@ -193,7 +197,15 @@ namespace Compiler } if (error) - return false; + { + /// workaround that allows names to begin with digits + /// \todo disable + TokenLoc loc (mLoc); + mLoc.mLiteral.clear(); + cont = parser.parseName (value, loc, *this); + return true; +// return false; + } TokenLoc loc (mLoc); mLoc.mLiteral.clear(); @@ -555,8 +567,7 @@ namespace Compiler Scanner::Scanner (ErrorHandler& errorHandler, std::istream& inputStream, const Extensions *extensions) : mErrorHandler (errorHandler), mStream (inputStream), mExtensions (extensions), - mPutback (Putback_None), mPutbackCode(0), mPutbackInteger(0), mPutbackFloat(0), - mNameStartingWithDigit (false) + mPutback (Putback_None), mPutbackCode(0), mPutbackInteger(0), mPutbackFloat(0) { } @@ -608,9 +619,4 @@ namespace Compiler if (mExtensions) mExtensions->listKeywords (keywords); } - - void Scanner::allowNameStartingwithDigit() - { - mNameStartingWithDigit = true; - } } diff --git a/components/compiler/scanner.hpp b/components/compiler/scanner.hpp index ed01bbe44..847895978 100644 --- a/components/compiler/scanner.hpp +++ b/components/compiler/scanner.hpp @@ -124,9 +124,6 @@ namespace Compiler void listKeywords (std::vector& keywords); ///< Append all known keywords to \a kaywords. - - /// For the next token allow names to start with a digit. - void allowNameStartingwithDigit(); }; } From 84747fbdd764eb00dde424b4ac6e9201b8beb3f7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Sep 2015 15:37:36 +0200 Subject: [PATCH 381/419] Use the actual sneak state to determine visibility of indicator (Fixes #2915) --- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/character.cpp | 11 ++++++++++- apps/openmw/mwmechanics/character.hpp | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index fcda6fa08..1c26c7dd1 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1094,7 +1094,7 @@ namespace MWMechanics static float sneakTimer = 0.f; // times update of sneak icon // if player is in sneak state see if anyone detects him - if (player.getClass().getCreatureStats(player).getMovementFlag(MWMechanics::CreatureStats::Flag_Sneak)) + if (playerCharacter && playerCharacter->isSneaking()) { static float sneakSkillTimer = 0.f; // times sneak skill progress from "avoid notice" diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3837e9a75..4a826043b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1768,7 +1768,7 @@ void CharacterController::update(float duration) if(mAnimQueue.empty() || inwater || sneak) { - idlestate = (inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)); + idlestate = (inwater ? CharState_IdleSwim : (sneak && !inJump ? CharState_IdleSneak : CharState_Idle)); } else if(mAnimQueue.size() > 1) { @@ -2048,6 +2048,15 @@ bool CharacterController::isKnockedOut() const return mHitState == CharState_KnockOut; } +bool CharacterController::isSneaking() const +{ + return mIdleState == CharState_IdleSneak || + mMovementState == CharState_SneakForward || + mMovementState == CharState_SneakBack || + mMovementState == CharState_SneakLeft || + mMovementState == CharState_SneakRight; +} + void CharacterController::setAttackingOrSpell(bool attackingOrSpell) { mAttackingOrSpell = attackingOrSpell; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 98c181749..4448467f7 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -241,6 +241,7 @@ public: bool isReadyToBlock() const; bool isKnockedOut() const; + bool isSneaking() const; void setAttackingOrSpell(bool attackingOrSpell); From 5692ef1eae83cf80b21a643782ecfe80eab087b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Sep 2015 15:43:42 +0200 Subject: [PATCH 382/419] Add convenience operator [] to AnimPriority --- apps/openmw/mwmechanics/character.cpp | 4 ++-- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/animation.hpp | 10 ++++++++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4a826043b..0d7c0ff26 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -278,7 +278,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mHitState = CharState_Block; mCurrentHit = "shield"; MWRender::Animation::AnimPriority priorityBlock (Priority_Hit); - priorityBlock.mPriority[MWRender::Animation::BoneGroup_LeftArm] = Priority_Block; + priorityBlock[MWRender::Animation::BoneGroup_LeftArm] = Priority_Block; mAnimation->play(mCurrentHit, priorityBlock, MWRender::Animation::BlendMask_All, true, 1, "block start", "block stop", 0.0f, 0); } @@ -1063,7 +1063,7 @@ bool CharacterController::updateWeaponState() } MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon); - priorityWeapon.mPriority[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody; + priorityWeapon[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody; bool forcestateupdate = false; if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c1ae5fed5..b14e629d0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -680,7 +680,7 @@ namespace MWRender if(!(state->second.mBlendMask&(1<second.mPriority.mPriority[blendMask] < state->second.mPriority.mPriority[blendMask]) + if(active == mStates.end() || active->second.mPriority[blendMask] < state->second.mPriority[blendMask]) active = state; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 30b6d156a..ef572c7c3 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -105,6 +105,16 @@ public: return true; } + int& operator[] (int n) + { + return mPriority[n]; + } + + const int& operator[] (int n) const + { + return mPriority[n]; + } + bool contains(int priority) const { for (unsigned int i=0; i Date: Wed, 16 Sep 2015 16:14:17 +0200 Subject: [PATCH 383/419] Keep playing IdleSneak on the lower body when casting spells / using weapons --- apps/openmw/mwmechanics/character.cpp | 3 +++ apps/openmw/mwmechanics/character.hpp | 1 + apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/animation.hpp | 4 ++-- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 0d7c0ff26..49e40349b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -483,7 +483,10 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat idlePriority = Priority_SwimIdle; } else if(mIdleState == CharState_IdleSneak && mAnimation->hasAnimation("idlesneak")) + { idle = "idlesneak"; + idlePriority[MWRender::Animation::BoneGroup_LowerBody] = Priority_SneakIdleLowerBody; + } else if(mIdleState != CharState_None) { idle = "idle"; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 4448467f7..fee7b959c 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -29,6 +29,7 @@ class CreatureStats; enum Priority { Priority_Default, Priority_WeaponLowerBody, + Priority_SneakIdleLowerBody, Priority_SwimIdle, Priority_Jump, Priority_Movement, diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b14e629d0..078d136f1 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -680,7 +680,7 @@ namespace MWRender if(!(state->second.mBlendMask&(1<second.mPriority[blendMask] < state->second.mPriority[blendMask]) + if(active == mStates.end() || active->second.mPriority[(BoneGroup)blendMask] < state->second.mPriority[(BoneGroup)blendMask]) active = state; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ef572c7c3..e64879a75 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -105,12 +105,12 @@ public: return true; } - int& operator[] (int n) + int& operator[] (BoneGroup n) { return mPriority[n]; } - const int& operator[] (int n) const + const int& operator[] (BoneGroup n) const { return mPriority[n]; } From f8d4bc378ff1ef08de7547877deb8b3a6f0b3d4d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Sep 2015 16:15:55 +0200 Subject: [PATCH 384/419] Move setAlpha from NpcAnimation to Animation (Fixes #2917) --- apps/openmw/mwrender/animation.cpp | 34 +++++++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 5 +++- apps/openmw/mwrender/npcanimation.cpp | 36 --------------------------- apps/openmw/mwrender/npcanimation.hpp | 4 --- 4 files changed, 38 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 078d136f1..24d540e20 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include @@ -292,6 +294,7 @@ namespace MWRender , mTextKeyListener(NULL) , mHeadYawRadians(0.f) , mHeadPitchRadians(0.f) + , mAlpha(1.f) { for(size_t i = 0;i < sNumBlendMasks;i++) mAnimationTimePtr[i].reset(new AnimationTime); @@ -1247,6 +1250,37 @@ namespace MWRender return found->second; } + void Animation::setAlpha(float alpha) + { + if (alpha == mAlpha) + return; + mAlpha = alpha; + + if (alpha != 1.f) + { + osg::StateSet* stateset (new osg::StateSet); + + osg::BlendFunc* blendfunc (new osg::BlendFunc); + stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + // FIXME: overriding diffuse/ambient/emissive colors + osg::Material* material (new osg::Material); + material->setColorMode(osg::Material::OFF); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,alpha)); + material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + stateset->setAttributeAndModes(material, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + stateset->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); + stateset->setNestRenderBins(false); + mObjectRoot->setStateSet(stateset); + } + else + { + mObjectRoot->setStateSet(NULL); + } + } + void Animation::setLightEffect(float effect) { if (effect == 0) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index e64879a75..94b792c0d 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -253,6 +253,8 @@ protected: osg::ref_ptr mGlowLight; + float mAlpha; + /* Sets the appropriate animations on the bone groups based on priority. */ void resetActiveGroups(); @@ -419,7 +421,8 @@ public: virtual void showCarriedLeft(bool show) {} virtual void setWeaponGroup(const std::string& group) {} virtual void setVampire(bool vampire) {} - virtual void setAlpha(float alpha) {} + /// A value < 1 makes the animation translucent, 1.f = fully opaque + void setAlpha(float alpha); virtual void setPitchFactor(float factor) {} virtual void attachArrow() {} virtual void releaseArrow(float attackStrength) {} diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 66a3d3ec6..99ee886e1 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -2,8 +2,6 @@ #include #include -#include -#include #include @@ -278,7 +276,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par mShowWeapons(false), mShowCarriedLeft(true), mNpcType(Type_Normal), - mAlpha(1.f), mSoundsDisabled(disableSounds) { mNpc = mPtr.get()->mBase; @@ -422,7 +419,6 @@ void NpcAnimation::updateParts() if (!mObjectRoot.get()) return; - mAlpha = 1.f; const MWWorld::Class &cls = mPtr.getClass(); NpcType curType = Type_Normal; @@ -902,7 +898,6 @@ void NpcAnimation::showWeapons(bool showWeapon) { removeIndividualPart(ESM::PRT_Weapon); } - mAlpha = 1.f; } void NpcAnimation::showCarriedLeft(bool show) @@ -988,37 +983,6 @@ void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, boo } } -void NpcAnimation::setAlpha(float alpha) -{ - if (alpha == mAlpha) - return; - mAlpha = alpha; - - if (alpha != 1.f) - { - osg::StateSet* stateset (new osg::StateSet); - - osg::BlendFunc* blendfunc (new osg::BlendFunc); - stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - - // FIXME: overriding diffuse/ambient/emissive colors - osg::Material* material (new osg::Material); - material->setColorMode(osg::Material::OFF); - material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,alpha)); - material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); - stateset->setAttributeAndModes(material, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - - stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - stateset->setRenderBinMode(osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); - stateset->setNestRenderBins(false); - mObjectRoot->setStateSet(stateset); - } - else - { - mObjectRoot->setStateSet(NULL); - } -} - void NpcAnimation::enableHeadAnimation(bool enable) { mHeadAnimationTime->setEnabled(enable); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 6462c53c3..06f40f847 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -65,7 +65,6 @@ private: boost::shared_ptr mHeadAnimationTime; boost::shared_ptr mWeaponAnimationTime; - float mAlpha; bool mSoundsDisabled; void updateNpcBase(); @@ -134,9 +133,6 @@ public: /// Get the inventory slot that the given node path leads into, or -1 if not found. int getSlot(const osg::NodePath& path) const; - /// Make the NPC only partially visible - virtual void setAlpha(float alpha); - virtual void setVampire(bool vampire); /// Set a translation offset (in object root space) to apply to meshes when in first person mode. From 47e29480ce9c46f5787885183537ef7774742656 Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Wed, 16 Sep 2015 16:04:25 +0200 Subject: [PATCH 385/419] show duration of light sources in tooltip I had forgotten light sources disappear after a while, this way at least you know it's normal ! --- apps/openmw/mwclass/light.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index c532b5d65..cbd051fdb 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -169,6 +169,7 @@ namespace MWClass std::string text; + text += "\nDuration: " + MWGui::ToolTips::toString(ptr.getClass().getRemainingUsageTime(ptr)); if (ref->mBase->mData.mWeight != 0) { text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); From 1472711583358f633d17cc055a24edfb970e85eb Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Wed, 16 Sep 2015 17:32:00 +0200 Subject: [PATCH 386/419] add duration to spell icons too and use gmststrings instead of direct strings in tooltips durations can display minutes and hours I don't know any effect lasting an hour or more but you never know... --- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwgui/spellicons.cpp | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index cbd051fdb..98d86e5ae 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -169,7 +169,7 @@ namespace MWClass std::string text; - text += "\nDuration: " + MWGui::ToolTips::toString(ptr.getClass().getRemainingUsageTime(ptr)); + text += "\n#{sDuration}: " + MWGui::ToolTips::toString(ptr.getClass().getRemainingUsageTime(ptr)); if (ref->mBase->mData.mWeight != 0) { text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index b2995af3c..f132cd73e 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -133,6 +133,23 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", "") : MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "") ); } + if (effectIt->mRemainingTime > -1) { + sourcesDescription += " #{sDuration}: "; + float duration = effectIt->mRemainingTime; + if (duration > 3600) { + int hour = duration / 3600; + duration -= hour*3600; + sourcesDescription += MWGui::ToolTips::toString(hour) + "h"; + } + if (duration > 60) { + int minute = duration / 60; + duration -= minute*60; + sourcesDescription += MWGui::ToolTips::toString(minute) + "m"; + } + if (duration > 0.1) { + sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; + } + } } } From b0d373f7e6ffec07b8f356dfeb2ec3805f31574c Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Wed, 16 Sep 2015 19:18:01 +0200 Subject: [PATCH 387/419] durations in tooltips : water walking effects is seen differently so move the duration info out of this block... --- apps/openmw/mwgui/spellicons.cpp | 34 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index f132cd73e..632baeb19 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -133,24 +133,24 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", "") : MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "") ); } - if (effectIt->mRemainingTime > -1) { - sourcesDescription += " #{sDuration}: "; - float duration = effectIt->mRemainingTime; - if (duration > 3600) { - int hour = duration / 3600; - duration -= hour*3600; - sourcesDescription += MWGui::ToolTips::toString(hour) + "h"; - } - if (duration > 60) { - int minute = duration / 60; - duration -= minute*60; - sourcesDescription += MWGui::ToolTips::toString(minute) + "m"; - } - if (duration > 0.1) { - sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; - } - } } + if (effectIt->mRemainingTime > -1) { + sourcesDescription += " #{sDuration}: "; + float duration = effectIt->mRemainingTime; + if (duration > 3600) { + int hour = duration / 3600; + duration -= hour*3600; + sourcesDescription += MWGui::ToolTips::toString(hour) + "h"; + } + if (duration > 60) { + int minute = duration / 60; + duration -= minute*60; + sourcesDescription += MWGui::ToolTips::toString(minute) + "m"; + } + if (duration > 0.1) { + sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; + } + } } if (remainingDuration > 0.f) From a47617c21f11c33e10b8a635292c3b1a4d8d5769 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Sep 2015 20:45:37 +0200 Subject: [PATCH 388/419] Fix tab indentations in apps/ and components/ --- apps/esmtool/record.cpp | 30 +++++++++---------- apps/esmtool/record.hpp | 2 +- .../model/world/infotableproxymodel.cpp | 2 +- apps/opencs/view/widget/droplineedit.cpp | 2 +- apps/openmw/android_commandLine.cpp | 26 ++++++++-------- apps/openmw/android_main.c | 20 ++++++------- apps/openmw/crashcatcher.cpp | 4 +-- apps/openmw/mwgui/debugwindow.cpp | 8 ++--- apps/openmw/mwgui/tooltips.hpp | 2 +- apps/openmw/mwgui/widgets.cpp | 4 +-- apps/openmw/mwinput/inputmanagerimp.cpp | 14 ++++----- apps/openmw/mwmechanics/aicombat.cpp | 2 +- apps/openmw/mwphysics/physicssystem.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- components/compiler/extensions0.hpp | 2 +- components/esm/loadmgef.hpp | 4 +-- components/files/configurationmanager.hpp | 10 +++---- components/sdlutil/sdlinputwrapper.hpp | 4 +-- 18 files changed, 70 insertions(+), 70 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 76c14e728..5fe6471b0 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -493,14 +493,14 @@ void Record::print() std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl; if (mPrintPlain) { - std::cout << " Text:" << std::endl; - std::cout << "START--------------------------------------" << std::endl; - std::cout << mData.mText << std::endl; - std::cout << "END----------------------------------------" << std::endl; + std::cout << " Text:" << std::endl; + std::cout << "START--------------------------------------" << std::endl; + std::cout << mData.mText << std::endl; + std::cout << "END----------------------------------------" << std::endl; } else { - std::cout << " Text: [skipped]" << std::endl; + std::cout << " Text: [skipped]" << std::endl; } } @@ -799,14 +799,14 @@ void Record::print() { if (mPrintPlain) { - std::cout << " Result Script:" << std::endl; - std::cout << "START--------------------------------------" << std::endl; - std::cout << mData.mResultScript << std::endl; - std::cout << "END----------------------------------------" << std::endl; + std::cout << " Result Script:" << std::endl; + std::cout << "START--------------------------------------" << std::endl; + std::cout << mData.mResultScript << std::endl; + std::cout << "END----------------------------------------" << std::endl; } else { - std::cout << " Result Script: [skipped]" << std::endl; + std::cout << " Result Script: [skipped]" << std::endl; } } } @@ -1201,14 +1201,14 @@ void Record::print() if (mPrintPlain) { - std::cout << " Script:" << std::endl; - std::cout << "START--------------------------------------" << std::endl; - std::cout << mData.mScriptText << std::endl; - std::cout << "END----------------------------------------" << std::endl; + std::cout << " Script:" << std::endl; + std::cout << "START--------------------------------------" << std::endl; + std::cout << mData.mScriptText << std::endl; + std::cout << "END----------------------------------------" << std::endl; } else { - std::cout << " Script: [skipped]" << std::endl; + std::cout << " Script: [skipped]" << std::endl; } } diff --git a/apps/esmtool/record.hpp b/apps/esmtool/record.hpp index c1b90ac2b..5e03c64db 100644 --- a/apps/esmtool/record.hpp +++ b/apps/esmtool/record.hpp @@ -53,7 +53,7 @@ namespace EsmTool } void setPrintPlain(bool plain) { - mPrintPlain = plain; + mPrintPlain = plain; } virtual void load(ESM::ESMReader &esm) = 0; diff --git a/apps/opencs/model/world/infotableproxymodel.cpp b/apps/opencs/model/world/infotableproxymodel.cpp index f55f775ab..4f0b2e752 100644 --- a/apps/opencs/model/world/infotableproxymodel.cpp +++ b/apps/opencs/model/world/infotableproxymodel.cpp @@ -16,7 +16,7 @@ namespace CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent) : IdTableProxyModel(parent), mType(type), - mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic : + mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic : Columns::ColumnId_Journal), mInfoColumnIndex(-1), mLastAddedSourceRow(-1) diff --git a/apps/opencs/view/widget/droplineedit.cpp b/apps/opencs/view/widget/droplineedit.cpp index 1df598cb8..2ca306461 100644 --- a/apps/opencs/view/widget/droplineedit.cpp +++ b/apps/opencs/view/widget/droplineedit.cpp @@ -35,7 +35,7 @@ void CSVWidget::DropLineEdit::dropEvent(QDropEvent *event) if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType)) { CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, mDropType); - setText(QString::fromUtf8(id.getId().c_str())); + setText(QString::fromUtf8(id.getId().c_str())); emit tableMimeDataDropped(id, CSVWorld::DragDropUtils::getTableMimeData(*event)->getDocumentPtr()); } } diff --git a/apps/openmw/android_commandLine.cpp b/apps/openmw/android_commandLine.cpp index ebfff28ca..7e7f368e0 100644 --- a/apps/openmw/android_commandLine.cpp +++ b/apps/openmw/android_commandLine.cpp @@ -7,21 +7,21 @@ int argcData; extern "C" void releaseArgv(); void releaseArgv() { - delete[] argvData; + delete[] argvData; } JNIEXPORT void JNICALL Java_ui_activity_GameActivity_commandLine(JNIEnv *env, - jobject obj, jint argc, jobjectArray stringArray) { - jboolean iscopy; - argcData = (int) argc; - argvData = new const char *[argcData + 1]; - argvData[0] = "openmw"; - for (int i = 1; i < argcData + 1; i++) { - jstring string = (jstring) (env)->GetObjectArrayElement(stringArray, - i - 1); - argvData[i] = (env)->GetStringUTFChars(string, &iscopy); - (env)->DeleteLocalRef(string); - } - (env)->DeleteLocalRef(stringArray); + jobject obj, jint argc, jobjectArray stringArray) { + jboolean iscopy; + argcData = (int) argc; + argvData = new const char *[argcData + 1]; + argvData[0] = "openmw"; + for (int i = 1; i < argcData + 1; i++) { + jstring string = (jstring) (env)->GetObjectArrayElement(stringArray, + i - 1); + argvData[i] = (env)->GetStringUTFChars(string, &iscopy); + (env)->DeleteLocalRef(string); + } + (env)->DeleteLocalRef(stringArray); } diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index 1b2839519..47b77a8b3 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -16,22 +16,22 @@ extern const char **argvData; void releaseArgv(); int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, - jobject obj) { + jobject obj) { - SDL_Android_Init(env, cls); + SDL_Android_Init(env, cls); - SDL_SetMainReady(); + SDL_SetMainReady(); - /* Run the application code! */ + /* Run the application code! */ - int status; + int status; - status = main(argcData+1, argvData); - releaseArgv(); - /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ - /* exit(status); */ + status = main(argcData+1, argvData); + releaseArgv(); + /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ + /* exit(status); */ - return status; + return status; } #endif /* __ANDROID__ */ diff --git a/apps/openmw/crashcatcher.cpp b/apps/openmw/crashcatcher.cpp index 8f25d041c..373d78746 100644 --- a/apps/openmw/crashcatcher.cpp +++ b/apps/openmw/crashcatcher.cpp @@ -37,8 +37,8 @@ static const char pipe_err[] = "!!! Failed to create pipe\n"; static const char fork_err[] = "!!! Failed to fork debug process\n"; static const char exec_err[] = "!!! Failed to exec debug process\n"; -#ifndef PATH_MAX /* Not all platforms (GNU Hurd) have this. */ -# define PATH_MAX 256 +#ifndef PATH_MAX /* Not all platforms (GNU Hurd) have this. */ +# define PATH_MAX 256 #endif static char argv0[PATH_MAX]; diff --git a/apps/openmw/mwgui/debugwindow.cpp b/apps/openmw/mwgui/debugwindow.cpp index a6dab66c1..37ea3470d 100644 --- a/apps/openmw/mwgui/debugwindow.cpp +++ b/apps/openmw/mwgui/debugwindow.cpp @@ -18,9 +18,9 @@ namespace float accumulated_time=0,parent_time = pit->Is_Root() ? CProfileManager::Get_Time_Since_Reset() : pit->Get_Current_Parent_Total_Time(); int i,j; int frames_since_reset = CProfileManager::Get_Frame_Count_Since_Reset(); - for (i=0;iGet_Current_Parent_Name())+" (total running time: "+MyGUI::utility::toString(parent_time,3)+" ms) ---\n"; os << s; @@ -35,7 +35,7 @@ namespace accumulated_time += current_total_time; float fraction = parent_time > SIMD_EPSILON ? (current_total_time / parent_time) * 100 : 0.f; - for (j=0;jGet_Current_Name()+" ("+MyGUI::utility::toString(fraction,2)+" %) :: "+MyGUI::utility::toString(ms,3)+" ms / frame ("+MyGUI::utility::toString(pit->Get_Current_Total_Calls())+" calls)\n"; os << s; @@ -47,7 +47,7 @@ namespace { os << "what's wrong\n"; } - for (i=0;i SIMD_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f; s = "Unaccounted: ("+MyGUI::utility::toString(unaccounted,3)+" %) :: "+MyGUI::utility::toString(parent_time - accumulated_time,3)+" ms\n"; os << s; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 384bccfea..983b50fe2 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -109,7 +109,7 @@ namespace MWGui static std::string sSchoolNames[6]; - int mHorizontalScrollIndex; + int mHorizontalScrollIndex; float mDelay; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 481ffaade..695337cde 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -605,7 +605,7 @@ namespace MWGui controller->eventRepeatClick += newDelegate(this, &MWScrollBar::repeatClick); controller->setEnabled(mEnableRepeat); controller->setRepeat(mRepeatTriggerTime, mRepeatStepTime); - MyGUI::ControllerManager::getInstance().addItem(this, controller); + MyGUI::ControllerManager::getInstance().addItem(this, controller); } void MWScrollBar::onDecreaseButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) @@ -621,7 +621,7 @@ namespace MWGui controller->eventRepeatClick += newDelegate(this, &MWScrollBar::repeatClick); controller->setEnabled(mEnableRepeat); controller->setRepeat(mRepeatTriggerTime, mRepeatStepTime); - MyGUI::ControllerManager::getInstance().addItem(this, controller); + MyGUI::ControllerManager::getInstance().addItem(this, controller); } void MWScrollBar::onIncreaseButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index bd94d60c6..ad5fe35bd 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -102,9 +102,9 @@ namespace MWInput mControlSwitch["playerviewswitch"] = true; mControlSwitch["vanitymode"] = true; - /* Joystick Init */ + /* Joystick Init */ - //Load controller mappings + // Load controller mappings #if SDL_VERSION_ATLEAST(2,0,2) if(controllerBindingsFile!="") { @@ -112,10 +112,10 @@ namespace MWInput } #endif - //Open all presently connected sticks - int numSticks = SDL_NumJoysticks(); - for(int i = 0; i < numSticks; i++) - { + // Open all presently connected sticks + int numSticks = SDL_NumJoysticks(); + for(int i = 0; i < numSticks; i++) + { if(SDL_IsGameController(i)) { SDL_ControllerDeviceEvent evt; @@ -126,7 +126,7 @@ namespace MWInput { //ICS_LOG(std::string("Unusable controller plugged in: ")+SDL_JoystickNameForIndex(i)); } - } + } float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); if (uiScale != 0.f) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 58f74a87f..45a6cce6d 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -57,7 +57,7 @@ namespace osg::Vec3f dir = to - from; dir.z() = 0; dir.normalize(); - float verticalOffset = 200; // instead of '200' here we want the height of the actor + float verticalOffset = 200; // instead of '200' here we want the height of the actor osg::Vec3f _from = from + dir*offsetXY + osg::Vec3f(0,0,1) * verticalOffset; // cast up-down ray and find height in world space of hit diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index c4fec7256..e666161da 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -747,7 +747,7 @@ namespace MWPhysics { } - virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) + virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) { if (rayResult.m_collisionObject == mMe) return 1.f; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f50991e24..f812fd8fd 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -287,7 +287,7 @@ namespace MWWorld if (mPlayer) { - mPlayer->clear(); + mPlayer->clear(); mPlayer->setCell(0); mPlayer->getPlayer().getRefData() = RefData(); mPlayer->set(mStore.get().find ("player")); diff --git a/components/compiler/extensions0.hpp b/components/compiler/extensions0.hpp index 83f3a44fa..e9ce6a6d6 100644 --- a/components/compiler/extensions0.hpp +++ b/components/compiler/extensions0.hpp @@ -44,7 +44,7 @@ namespace Compiler namespace Gui { - void registerExtensions (Extensions& extensions); + void registerExtensions (Extensions& extensions); } namespace Misc diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp index 32b8a85a6..eeb4268c2 100644 --- a/components/esm/loadmgef.hpp +++ b/components/esm/loadmgef.hpp @@ -31,9 +31,9 @@ struct MagicEffect CastTouch = 0x80, // Allows range - cast on touch. CastTarget = 0x100, // Allows range - cast on target. UncappedDamage = 0x1000, // Negates multiple cap behaviours. Allows an effect to reduce an attribute below zero; removes the normal minimum effect duration of 1 second. - NonRecastable = 0x4000, // Does not land if parent spell is already affecting target. Shows "you cannot re-cast" message for self target. + NonRecastable = 0x4000, // Does not land if parent spell is already affecting target. Shows "you cannot re-cast" message for self target. Unreflectable = 0x10000, // Cannot be reflected, the effect always lands normally. - CasterLinked = 0x20000, // Must quench if caster is dead, or not an NPC/creature. Not allowed in containter/door trap spells. + CasterLinked = 0x20000, // Must quench if caster is dead, or not an NPC/creature. Not allowed in containter/door trap spells. // Originally modifiable flags AllowSpellmaking = 0x200, // Can be used for spellmaking diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 5f0062c2e..102f7c3cb 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -52,11 +52,11 @@ struct ConfigurationManager typedef Files::FixedPath<> FixedPathType; typedef const boost::filesystem::path& (FixedPathType::*path_type_f)() const; - #if defined HAVE_UNORDERED_MAP - typedef std::unordered_map TokensMappingContainer; - #else - typedef std::tr1::unordered_map TokensMappingContainer; - #endif + #if defined HAVE_UNORDERED_MAP + typedef std::unordered_map TokensMappingContainer; + #else + typedef std::tr1::unordered_map TokensMappingContainer; + #endif void loadConfig(const boost::filesystem::path& path, boost::program_options::variables_map& variables, diff --git a/components/sdlutil/sdlinputwrapper.hpp b/components/sdlutil/sdlinputwrapper.hpp index bdb5842ae..a821b9012 100644 --- a/components/sdlutil/sdlinputwrapper.hpp +++ b/components/sdlutil/sdlinputwrapper.hpp @@ -30,8 +30,8 @@ namespace SDLUtil void setControllerEventCallback(ControllerListener* listen) { mConListener = listen; } void capture(bool windowEventsOnly); - bool isModifierHeld(SDL_Keymod mod); - bool isKeyDown(SDL_Scancode key); + bool isModifierHeld(SDL_Keymod mod); + bool isKeyDown(SDL_Scancode key); void setMouseVisible (bool visible); void setMouseRelative(bool relative); From 29a84452ab71886d1e97d6110844ad88e2cb48f4 Mon Sep 17 00:00:00 2001 From: Emmanuel Anne Date: Wed, 16 Sep 2015 22:41:42 +0200 Subject: [PATCH 389/419] durations in tooltips : use "show effect duration" setting --- apps/openmw/mwclass/light.cpp | 4 +++- apps/openmw/mwgui/spellicons.cpp | 36 +++++++++++++++++--------------- files/settings-default.cfg | 2 ++ 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 98d86e5ae..f1dd18acc 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -169,7 +170,8 @@ namespace MWClass std::string text; - text += "\n#{sDuration}: " + MWGui::ToolTips::toString(ptr.getClass().getRemainingUsageTime(ptr)); + if (Settings::Manager::getBool("show effect duration","Game")) + text += "\n#{sDuration}: " + MWGui::ToolTips::toString(ptr.getClass().getRemainingUsageTime(ptr)); if (ref->mBase->mData.mWeight != 0) { text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 632baeb19..27896381e 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -134,23 +135,24 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "") ); } } - if (effectIt->mRemainingTime > -1) { - sourcesDescription += " #{sDuration}: "; - float duration = effectIt->mRemainingTime; - if (duration > 3600) { - int hour = duration / 3600; - duration -= hour*3600; - sourcesDescription += MWGui::ToolTips::toString(hour) + "h"; - } - if (duration > 60) { - int minute = duration / 60; - duration -= minute*60; - sourcesDescription += MWGui::ToolTips::toString(minute) + "m"; - } - if (duration > 0.1) { - sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; - } - } + if (effectIt->mRemainingTime > -1 && + Settings::Manager::getBool("show effect duration","Game")) { + sourcesDescription += " #{sDuration}: "; + float duration = effectIt->mRemainingTime; + if (duration > 3600) { + int hour = duration / 3600; + duration -= hour*3600; + sourcesDescription += MWGui::ToolTips::toString(hour) + "h"; + } + if (duration > 60) { + int minute = duration / 60; + duration -= minute*60; + sourcesDescription += MWGui::ToolTips::toString(minute) + "m"; + } + if (duration > 0.1) { + sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; + } + } } if (remainingDuration > 0.f) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index c793225c2..274a31315 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -175,6 +175,8 @@ difficulty = 0 #2: tint crosshair #3: both show owned = 0 +# Show the remaining duration of magic effects and lights +show effect duration = false [Saves] character = From ab97a90c760fb3a558f25bd49527bf69fbba8d64 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Sep 2015 20:50:57 +0200 Subject: [PATCH 390/419] Add travis-ci script to detect tab characters in the code --- .travis.yml | 2 +- CI/check_tabs.sh | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100755 CI/check_tabs.sh diff --git a/.travis.yml b/.travis.yml index 80277f8ba..69879bd78 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,8 +40,8 @@ script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j2; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi -after_script: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi + - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi notifications: recipients: - corrmage+travis-ci@gmail.com diff --git a/CI/check_tabs.sh b/CI/check_tabs.sh new file mode 100755 index 000000000..91f81e2a1 --- /dev/null +++ b/CI/check_tabs.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +OUTPUT=$(grep -nRP '\t' --include=\*.{cpp,hpp,c,h} apps components) + +if [[ $OUTPUT ]] ; then + echo "Error: Tab characters found!" + echo $OUTPUT + exit 1 +fi From c4b5a41ac396fc0e69df339513217ee0d5ba5ba9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Sep 2015 01:08:16 +0200 Subject: [PATCH 391/419] Improve combat AI vertical aiming (Fixes #1366, Fixes #1330) --- apps/openmw/mwbase/world.hpp | 4 +++ apps/openmw/mwmechanics/aicombat.cpp | 29 ++++++++-------- apps/openmw/mwphysics/physicssystem.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 44 ++++++++++++------------- apps/openmw/mwworld/worldimp.hpp | 4 +++ 5 files changed, 45 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a3d293d95..1622e1537 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -541,6 +541,10 @@ namespace MWBase virtual void resetActors() = 0; virtual bool isWalkingOnWater (const MWWorld::Ptr& actor) = 0; + + /// Return a vector aiming the actor's weapon towards a target. + /// @note The length of the vector is the distance between actor and target. + virtual osg::Vec3f aimToTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) = 0; }; } diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 58f74a87f..93b4e0ee7 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -34,10 +34,9 @@ namespace return std::atan2(dir.x(), dir.y()); } - float getXAngleToDir(const osg::Vec3f& dir, float dirLen = 0.0f) + float getXAngleToDir(const osg::Vec3f& dir) { - float len = (dirLen > 0.0f)? dirLen : dir.length(); - return -std::asin(dir.z() / len); + return -std::asin(dir.z() / dir.length()); } const float REACTION_INTERVAL = 0.25f; @@ -346,8 +345,9 @@ namespace MWMechanics ESM::Position pos = actor.getRefData().getPosition(); osg::Vec3f vActorPos(pos.asVec3()); osg::Vec3f vTargetPos(target.getRefData().getPosition().asVec3()); - osg::Vec3f vDirToTarget = vTargetPos - vActorPos; - float distToTarget = vDirToTarget.length(); + + osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target); + float distToTarget = (vTargetPos - vActorPos).length(); osg::Vec3f& lastActorPos = storage.mLastActorPos; bool& followTarget = storage.mFollowTarget; @@ -388,7 +388,7 @@ namespace MWMechanics if (distantCombat) { osg::Vec3f& lastTargetPos = storage.mLastTargetPos; - osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, REACTION_INTERVAL, weaptype, + vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, REACTION_INTERVAL, weaptype, storage.mStrength); lastTargetPos = vTargetPos; movement.mRotation[0] = getXAngleToDir(vAimDir); @@ -396,8 +396,8 @@ namespace MWMechanics } else { - movement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); - movement.mRotation[2] = getZAngleToDir(vDirToTarget); + movement.mRotation[0] = getXAngleToDir(vAimDir); + movement.mRotation[2] = getZAngleToDir((vTargetPos-vActorPos)); // using vAimDir results in spastic movements since the head is animated } // (not quite attack dist while following) @@ -431,19 +431,19 @@ namespace MWMechanics if(speed == 0.0f) speed = actorClass.getSpeed(actor); // maximum dist before pit/obstacle for actor to avoid them depending on his speed float maxAvoidDist = REACTION_INTERVAL * speed + speed / MAX_VEL_ANGULAR_RADIANS * 2; // *2 - for reliability - preferShortcut = checkWayIsClear(vActorPos, vTargetPos, osg::Vec3f(vDirToTarget.x(), vDirToTarget.y(), 0).length() > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); + preferShortcut = checkWayIsClear(vActorPos, vTargetPos, osg::Vec3f(vAimDir.x(), vAimDir.y(), 0).length() > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); } // don't use pathgrid when actor can move in 3 dimensions if (canMoveByZ) { preferShortcut = true; - movement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget); + movement.mRotation[0] = getXAngleToDir(vAimDir); } if(preferShortcut) { - movement.mRotation[2] = getZAngleToDir(vDirToTarget); + movement.mRotation[2] = getZAngleToDir((vTargetPos-vActorPos)); forceNoShortcut = false; shortcutFailPos.pos[0] = shortcutFailPos.pos[1] = shortcutFailPos.pos[2] = 0; mPathFinder.clearPath(); @@ -478,7 +478,7 @@ namespace MWMechanics // if there is no new path, then go straight on target if (!mPathFinder.isPathConstructed()) { - movement.mRotation[2] = getZAngleToDir(vDirToTarget); + movement.mRotation[2] = getZAngleToDir((vTargetPos-vActorPos)); } } @@ -779,9 +779,8 @@ osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& t // idea: perpendicular to dir to target speed components of target move vector and projectile vector should be the same - osg::Vec3f vActorPos = actor.getRefData().getPosition().asVec3(); osg::Vec3f vTargetPos = target.getRefData().getPosition().asVec3(); - osg::Vec3f vDirToTarget = vTargetPos - vActorPos; + osg::Vec3f vDirToTarget = MWBase::Environment::get().getWorld()->aimToTarget(actor, target); float distToTarget = vDirToTarget.length(); osg::Vec3f vTargetMoveDir = vTargetPos - vLastTargetPos; @@ -812,7 +811,7 @@ osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& t t_collision = projDistDiff / (std::sqrt(projVelDirSquared) - velDir); else t_collision = 0; // speed of projectile is not enough to reach moving target - return vTargetPos + vTargetMoveDir * t_collision - vActorPos; + return vDirToTarget + vTargetMoveDir * t_collision; } } diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index ee9378ea4..db8da2886 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -107,6 +107,7 @@ namespace MWPhysics bool isOnGround (const MWWorld::Ptr& actor); + /// Get physical half extents (scaled) of the given actor. osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor); /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f50991e24..b3e1c6ecb 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1018,14 +1018,11 @@ namespace MWWorld return facedObject; } - std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) + osg::Vec3f getActorHeadPosition(const MWWorld::Ptr& actor, MWRender::RenderingManager* rendering) { - const ESM::Position &posdata = ptr.getRefData().getPosition(); + osg::Vec3f origin(actor.getRefData().getPosition().asVec3()); - osg::Quat rot = osg::Quat(posdata.rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(posdata.rot[2], osg::Vec3f(0,0,-1)); - osg::Vec3f pos (posdata.asVec3()); - - MWRender::Animation* anim = mRendering->getAnimation(ptr); + MWRender::Animation* anim = rendering->getAnimation(actor); if (anim != NULL) { const osg::Node* node = anim->getNode("Head"); @@ -1035,9 +1032,18 @@ namespace MWWorld { osg::MatrixList mats = node->getWorldMatrices(); if (mats.size()) - pos = mats[0].getTrans(); + origin = mats[0].getTrans(); } } + return origin; + } + + std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) + { + const ESM::Position &posdata = ptr.getRefData().getPosition(); + + osg::Quat rot = osg::Quat(posdata.rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(posdata.rot[2], osg::Vec3f(0,0,-1)); + osg::Vec3f pos = getActorHeadPosition(ptr, mRendering); std::pair result = mPhysics->getHitContact(ptr, pos, rot, distance); if(result.first.isEmpty()) @@ -2608,21 +2614,7 @@ namespace MWWorld MWWorld::Ptr target; float distance = 192.f; // ?? osg::Vec3f hitPosition = actor.getRefData().getPosition().asVec3(); - osg::Vec3f origin(actor.getRefData().getPosition().asVec3()); - - MWRender::Animation* anim = mRendering->getAnimation(actor); - if (anim != NULL) - { - const osg::Node* node = anim->getNode("Head"); - if (node == NULL) - node = anim->getNode("Bip01 Head"); - if (node != NULL) - { - osg::MatrixList mats = node->getWorldMatrices(); - if (mats.size()) - origin = mats[0].getTrans(); - } - } + osg::Vec3f origin = getActorHeadPosition(actor, mRendering); osg::Quat orient = osg::Quat(actor.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0)) * osg::Quat(actor.getRefData().getPosition().rot[2], osg::Vec3f(0,0,-1)); @@ -3262,4 +3254,12 @@ namespace MWWorld return true; return false; } + + osg::Vec3f World::aimToTarget(const Ptr &actor, const MWWorld::Ptr& target) + { + osg::Vec3f weaponPos = getActorHeadPosition(actor, mRendering); + osg::Vec3f targetPos = target.getRefData().getPosition().asVec3(); + targetPos.z() += mPhysics->getHalfExtents(target).z(); + return (targetPos - weaponPos); + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 241dacc8a..26153086a 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -630,6 +630,10 @@ namespace MWWorld virtual void resetActors(); virtual bool isWalkingOnWater (const MWWorld::Ptr& actor); + + /// Return a vector aiming the actor's weapon towards a target. + /// @note The length of the vector is the distance between actor and target. + virtual osg::Vec3f aimToTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); }; } From a7f898057ba345d1c06f1f9071f1e067ab02bda4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Sep 2015 04:30:55 +0200 Subject: [PATCH 392/419] Don't activate the initial death animation when skipAnim is set (Fixes #2513) --- apps/openmw/mwmechanics/character.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3837e9a75..e80d6f4d0 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -701,8 +701,9 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mIdleState = CharState_Idle; else { - int deathindex = mPtr.getClass().getCreatureStats(mPtr).getDeathAnimation(); - playDeath(1.0f, CharacterState(CharState_Death1 + deathindex)); + // Set the death state, but don't play it yet + // We will play it in the first frame, but only if no script set the skipAnim flag + mDeathState = static_cast(CharState_Death1 + mPtr.getClass().getCreatureStats(mPtr).getDeathAnimation()); } } else @@ -1835,6 +1836,13 @@ void CharacterController::update(float duration) } else if(cls.getCreatureStats(mPtr).isDead()) { + // initial start of death animation for actors that started the game as dead + // not done in constructor since we need to give scripts a chance to set the mSkipAnim flag + if (!mSkipAnim && mDeathState != CharState_None && mCurrentDeath.empty()) + { + playDeath(1.f, mDeathState); + } + world->queueMovement(mPtr, osg::Vec3f(0.f, 0.f, 0.f)); } From 56163dcb2a33fdf67bd78dc63a6134c4f408505a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 17 Sep 2015 09:39:42 +0200 Subject: [PATCH 393/419] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 16c888239..8e9d35cf2 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -113,6 +113,7 @@ Programmers viadanna Vincent Heuken vocollapse + zelurker Manual ------ From b3b4fb3efbaf84a31b9a62203f9767b08328b671 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 17 Sep 2015 11:27:55 +0200 Subject: [PATCH 394/419] removed some left-over signal slot stuff that shouldn't have been there in the first place --- apps/opencs/view/world/scenesubview.cpp | 7 ------- apps/opencs/view/world/scenesubview.hpp | 8 -------- 2 files changed, 15 deletions(-) diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 2ca2548c0..b698d9034 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -247,8 +247,6 @@ void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceW mToolbar = toolbar; connect (mScene, SIGNAL (focusToolbarRequest()), mToolbar, SLOT (setFocus())); - connect (this, SIGNAL (updateSceneUserSetting(const QString &, const QStringList &)), - mScene, SLOT (updateUserSetting(const QString &, const QStringList &))); connect (mToolbar, SIGNAL (focusSceneRequest()), mScene, SLOT (setFocus())); mLayout->addWidget (mToolbar, 0); @@ -257,8 +255,3 @@ void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceW mScene->selectDefaultNavigationMode(); setFocusProxy (mScene); } - -void CSVWorld::SceneSubView::updateUserSetting (const QString &key, const QStringList &list) -{ - emit updateSceneUserSetting(key, list); -} diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index fc45347d0..65aaca999 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -83,14 +83,6 @@ namespace CSVWorld void cellSelectionChanged (const CSMWorld::UniversalId& id); void handleDrop(const std::vector& data); - - public slots: - - void updateUserSetting (const QString &, const QStringList &); - - signals: - - void updateSceneUserSetting (const QString &, const QStringList &); }; } From 659b87b25faec71089ae5f8b96b4283d58abaab7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 17 Sep 2015 11:31:25 +0200 Subject: [PATCH 395/419] more cleanup --- apps/opencs/view/doc/view.hpp | 3 --- apps/opencs/view/world/scenesubview.cpp | 5 ----- apps/opencs/view/world/scenesubview.hpp | 2 -- 3 files changed, 10 deletions(-) diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index adda73526..2dd717440 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -115,9 +115,6 @@ namespace CSVDoc Operations *getOperations() const; - /// Function called by view manager when user preferences are updated - void updateEditorSetting (const QString &, const QString &); - signals: void newGameRequest(); diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index b698d9034..c2f3442f8 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -132,11 +132,6 @@ void CSVWorld::SceneSubView::setEditLock (bool locked) } -void CSVWorld::SceneSubView::updateEditorSetting(const QString &settingName, const QString &settingValue) -{ - -} - void CSVWorld::SceneSubView::setStatusBar (bool show) { mBottom->setStatusBar (show); diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index 65aaca999..a34d71901 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -52,8 +52,6 @@ namespace CSVWorld virtual void setEditLock (bool locked); - virtual void updateEditorSetting (const QString& key, const QString& value); - virtual void setStatusBar (bool show); virtual void useHint (const std::string& hint); From 1aa926c7e0e151e2744ab90174d8b62caacb9dfe Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 17 Sep 2015 12:41:56 +0200 Subject: [PATCH 396/419] restored T-shortcut (focus toolbar) in scene widget --- apps/opencs/view/render/scenewidget.cpp | 4 ++++ apps/opencs/view/render/scenewidget.hpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index d91c075e1..59cc71855 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -143,6 +143,10 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys mView->setLightingMode(osgViewer::View::NO_LIGHT); setLighting(&mLightingDay); + + /// \todo make shortcut configurable + QShortcut *focusToolbar = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut); + connect (focusToolbar, SIGNAL (activated()), this, SIGNAL (focusToolbarRequest())); } SceneWidget::~SceneWidget() diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index f5c36b641..54f001c15 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -88,6 +88,10 @@ namespace CSVRender private slots: void selectLightingMode (const std::string& mode); + + signals: + + void focusToolbarRequest(); }; From 169fc6a61b2c2d2eed99c3e28156d53367e9312a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Sep 2015 18:29:22 +0200 Subject: [PATCH 397/419] OpenCS: Remove margin around the render window --- apps/opencs/view/render/scenewidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 59cc71855..0a5087998 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -52,6 +52,7 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) osg::ref_ptr window = new osgQt::GraphicsWindowQt(traits.get()); QLayout* layout = new QHBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(window->getGLWidget()); setLayout(layout); From dac3b33efba7872ab5ff1f458e3248632e4d2edf Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Sep 2015 18:29:40 +0200 Subject: [PATCH 398/419] OpenCS: Pass events from the QGLWidget to the RenderWidget --- apps/opencs/view/render/scenewidget.cpp | 21 +++++++++++++++++++++ apps/opencs/view/render/scenewidget.hpp | 2 ++ 2 files changed, 23 insertions(+) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 0a5087998..fb3bcb3c3 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -56,6 +56,9 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) layout->addWidget(window->getGLWidget()); setLayout(layout); + // Pass events through this widget first + window->getGLWidget()->installEventFilter(this); + mView->getCamera()->setGraphicsContext(window); mView->getCamera()->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) ); mView->getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); @@ -94,6 +97,24 @@ void RenderWidget::setVisibilityMask(int mask) mView->getCamera()->setCullMask(mask<<1); } +bool RenderWidget::eventFilter(QObject* obj, QEvent* event) +{ + // handle event in this widget, is there a better way to do this? + if (event->type() == QEvent::MouseButtonPress) + mousePressEvent(static_cast(event)); + if (event->type() == QEvent::MouseButtonRelease) + mouseReleaseEvent(static_cast(event)); + if (event->type() == QEvent::MouseMove) + mouseMoveEvent(static_cast(event)); + if (event->type() == QEvent::KeyPress) + keyPressEvent(static_cast(event)); + if (event->type() == QEvent::KeyRelease) + keyReleaseEvent(static_cast(event)); + + // Always pass the event on to GLWidget, i.e. to OSG event queue + return QObject::eventFilter(obj, event); +} + // -------------------------------------------------- CompositeViewer::CompositeViewer() diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 54f001c15..63da01a45 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -45,6 +45,8 @@ namespace CSVRender void setVisibilityMask(int mask); + bool eventFilter(QObject *, QEvent *); + protected: osg::ref_ptr mView; From 41ea76fd836eb956b9a7517c2181181c7c8ea115 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Sep 2015 18:31:05 +0200 Subject: [PATCH 399/419] OpenCS: Add selection outline effect to CSVRender::Object --- apps/opencs/view/render/object.cpp | 26 +++++++++++++++++++++++++- apps/opencs/view/render/object.hpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 973893a71..f05e311f9 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include "../../model/world/data.hpp" #include "../../model/world/ref.hpp" #include "../../model/world/refidcollection.hpp" @@ -116,9 +118,14 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, bool forceBaseToZero) -: mData (data), mBaseNode(0), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero) +: mData (data), mBaseNode(0), mSelected(false), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero) { mBaseNode = new osg::PositionAttitudeTransform; + mOutline = new osgFX::Scribe; + mOutline->addChild(mBaseNode); + + mBaseNode->setUserData(new ObjectHolder(this)); + parentNode->addChild(mBaseNode); // 0x1 reserved for separating cull and update visitors @@ -145,6 +152,23 @@ CSVRender::Object::~Object() mParentNode->removeChild(mBaseNode); } +void CSVRender::Object::setSelected(bool selected) +{ + mSelected = selected; + + mParentNode->removeChild(mOutline); + mParentNode->removeChild(mBaseNode); + if (selected) + mParentNode->addChild(mOutline); + else + mParentNode->addChild(mBaseNode); +} + +bool CSVRender::Object::getSelected() const +{ + return mSelected; +} + bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 9f411ffc6..9b3749069 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -6,6 +6,7 @@ #include #include +#include class QModelIndex; @@ -16,6 +17,11 @@ namespace osg class Group; } +namespace osgFX +{ + class Scribe; +} + namespace Resource { class ResourceSystem; @@ -29,12 +35,29 @@ namespace CSMWorld namespace CSVRender { + + class Object; + + // An object to attach as user data to the osg::Node, allows us to get an Object back from a Node when we are doing a ray query + class ObjectHolder : public osg::Referenced + { + public: + ObjectHolder(Object* obj) + : mObject(obj) + { + } + + Object* mObject; + }; + class Object { const CSMWorld::Data& mData; std::string mReferenceId; std::string mReferenceableId; osg::ref_ptr mBaseNode; + osg::ref_ptr mOutline; + bool mSelected; osg::Group* mParentNode; Resource::ResourceSystem* mResourceSystem; bool mForceBaseToZero; @@ -68,6 +91,11 @@ namespace CSVRender ~Object(); + /// Mark the object as selected, selected objects show an outline effect + void setSelected(bool selected); + + bool getSelected() const; + /// \return Did this call result in a modification of the visual representation of /// this object? bool referenceableDataChanged (const QModelIndex& topLeft, From 18d0cae801e77f9c10dc4f26124b32e5372697e1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Sep 2015 18:31:33 +0200 Subject: [PATCH 400/419] OpenCS: Select objects with the right mouse button --- apps/opencs/view/render/worldspacewidget.cpp | 48 ++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index d45fc45a8..a1f0f6bf2 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -1,6 +1,7 @@ #include "worldspacewidget.hpp" #include +#include #include #include @@ -12,6 +13,8 @@ #include #include +#include + #include "../../model/world/universalid.hpp" #include "../../model/world/idtable.hpp" @@ -19,6 +22,7 @@ #include "../widget/scenetooltoggle2.hpp" #include "../widget/scenetoolrun.hpp" +#include "object.hpp" #include "elements.hpp" #include "editmode.hpp" @@ -370,11 +374,49 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { - if(event->buttons() & Qt::RightButton) + if (event->button() != Qt::RightButton) + return; + + // (0,0) is considered the lower left corner of an OpenGL window + int x = event->x(); + int y = height() - event->y(); + + osg::ref_ptr intersector (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x, y)); + + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT); + osgUtil::IntersectionVisitor visitor(intersector); + + visitor.setTraversalMask(getInteractionMask() << 1); + + mView->getCamera()->accept(visitor); + + for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin(); + it != intersector->getIntersections().end(); ++it) { - //mMouse->mousePressEvent(event); + osgUtil::LineSegmentIntersector::Intersection intersection = *it; + + // reject back-facing polygons + osg::Vec3f normal = intersection.getWorldIntersectNormal(); + normal = osg::Matrix::transform3x3(normal, mView->getCamera()->getViewMatrix()); + if (normal.z() < 0) + continue; + + for (std::vector::iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) + { + osg::Node* node = *it; + if (CSVRender::ObjectHolder* holder = dynamic_cast(node->getUserData())) + { + // hit an Object, toggle its selection state + CSVRender::Object* obj = holder->mObject; + obj->setSelected(!obj->getSelected()); + return; + } + } + + // must be terrain, report coordinates + std::cout << "Terrain hit at " << intersection.getWorldIntersectPoint().x() << " " << intersection.getWorldIntersectPoint().y() << std::endl; + return; } - //SceneWidget::mousePressEvent(event); } void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) From a37dee09e2f074a76ce1b2c38c1473b3a3e03334 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 18 Sep 2015 21:29:32 +0200 Subject: [PATCH 401/419] Fix invisibility effect disappearing after a view mode switch --- apps/openmw/mwrender/animation.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 24d540e20..37ec4c213 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -935,8 +935,10 @@ namespace MWRender void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature) { + osg::ref_ptr previousStateset; if (mObjectRoot) { + previousStateset = mObjectRoot->getStateSet(); mObjectRoot->getParent(0)->removeChild(mObjectRoot); } mObjectRoot = NULL; @@ -961,6 +963,9 @@ namespace MWRender mObjectRoot = newObjectRoot; } + if (previousStateset) + mObjectRoot->setStateSet(previousStateset); + if (baseonly) { RemoveDrawableVisitor removeDrawableVisitor; From 5369d206822def39fac0d6b7674fb8e1537cb82d Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 19 Sep 2015 15:34:02 +1200 Subject: [PATCH 402/419] Moved pathfinding logic from AiCombat to Pathfinding. --- apps/openmw/mwmechanics/aicombat.cpp | 24 +++--------------------- apps/openmw/mwmechanics/pathfinding.cpp | 11 +++++++++++ 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index b42c3bdcc..6270779a4 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -458,28 +458,10 @@ namespace MWMechanics followTarget = false; - buildNewPath(actor, target); //may fail to build a path, check before use + buildNewPath(actor, target); - // if current actor pos is closer to target then last point of path (excluding target itself) then go straight on target - // This works on the borders between the path grid and areas with no waypoints. - if(inLOS && mPathFinder.getPath().size() > 1) - { - // get point just before target - std::list::const_iterator pntIter = --mPathFinder.getPath().end(); - --pntIter; - osg::Vec3f vBeforeTarget(PathFinder::MakeOsgVec3(*pntIter)); - - if(distToTarget <= (vTargetPos - vBeforeTarget).length()) - { - mPathFinder.clearPath(); - } - } - - // if there is no new path, then go straight on target - if (!mPathFinder.isPathConstructed()) - { - movement.mRotation[2] = getZAngleToDir((vTargetPos-vActorPos)); - } + // should always return a path (even if it's just go straight on target.) + assert(mPathFinder.isPathConstructed()); } if (readyToAttack) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f26d3e109..dbe20fdc0 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -215,6 +215,17 @@ namespace MWMechanics endPointInLocalCoords, startNode); + // if it's shorter for actor to travel from start to end, than to travel from either + // start or end to nearest pathgrid point, just travel from start to end. + float startToEndLength2 = (endPointInLocalCoords - startPointInLocalCoords).length2(); + float endTolastNodeLength2 = distanceSquared(mPathgrid->mPoints[endNode.first], endPointInLocalCoords); + float startTo1stNodeLength2 = distanceSquared(mPathgrid->mPoints[startNode], startPointInLocalCoords); + if ((startToEndLength2 < startTo1stNodeLength2) || (startToEndLength2 < endTolastNodeLength2)) + { + mPath.push_back(endPoint); + return; + } + // AiWander has logic that depends on whether a path was created, // deleting allowed nodes if not. Hence a path needs to be created // even if the start and the end points are the same. From 60d0ad928386e4d77aa08add8e763fcc4c9ab170 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sat, 19 Sep 2015 16:14:00 +1200 Subject: [PATCH 403/419] When stuck, try moving backwards as well as to side. --- apps/openmw/mwmechanics/obstacle.cpp | 20 ++++++++++++++++---- apps/openmw/mwmechanics/obstacle.hpp | 7 ++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index fe3d68a58..53f12a982 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -15,6 +15,14 @@ namespace MWMechanics static const float DURATION_SAME_SPOT = 1.0f; static const float DURATION_TO_EVADE = 0.4f; + const float ObstacleCheck::evadeDirections[NUM_EVADE_DIRECTIONS][2] = + { + { 1.0f, 0.0f }, // move to side + { 1.0f, -1.0f }, // move to side and backwards + { -1.0f, 0.0f }, // move to other side + { -1.0f, -1.0f } // move to side and backwards + }; + // Proximity check function for interior doors. Given that most interior cells // do not have many doors performance shouldn't be too much of an issue. // @@ -69,7 +77,7 @@ namespace MWMechanics , mStuckDuration(0) , mEvadeDuration(0) , mDistSameSpot(-1) // avoid calculating it each time - , mEvadeDirection(1.0f) + , mEvadeDirectionIndex(0) { } @@ -176,8 +184,8 @@ namespace MWMechanics void ObstacleCheck::takeEvasiveAction(MWMechanics::Movement& actorMovement) { - actorMovement.mPosition[0] = mEvadeDirection; - actorMovement.mPosition[1] = 0; + actorMovement.mPosition[0] = evadeDirections[mEvadeDirectionIndex][0]; + actorMovement.mPosition[1] = evadeDirections[mEvadeDirectionIndex][1]; } void ObstacleCheck::chooseEvasionDirection(bool samePosition) @@ -185,7 +193,11 @@ namespace MWMechanics // change direction if attempt didn't work if (samePosition && (0 < mEvadeDuration)) { - mEvadeDirection = mEvadeDirection == 1.0f ? -1.0f : 1.0f; + ++mEvadeDirectionIndex; + if (mEvadeDirectionIndex == NUM_EVADE_DIRECTIONS) + { + mEvadeDirectionIndex = 0; + } } } diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index ef3e29e8b..ecff00a5c 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -13,6 +13,8 @@ namespace MWMechanics /// NOTE: determined empirically based on in-game behaviour static const float MIN_DIST_TO_DOOR_SQUARED = 128*128; + static const int NUM_EVADE_DIRECTIONS = 4; + /// tests actor's proximity to a closed door by default bool proximityToDoor(const MWWorld::Ptr& actor, float minSqr = MIN_DIST_TO_DOOR_SQUARED, @@ -47,6 +49,9 @@ namespace MWMechanics float mPrevX; float mPrevY; + // directions to try moving in when get stuck + static const float evadeDirections[NUM_EVADE_DIRECTIONS][2]; + enum WalkState { State_Norm, @@ -58,7 +63,7 @@ namespace MWMechanics float mStuckDuration; // accumulate time here while in same spot float mEvadeDuration; float mDistSameSpot; // take account of actor's speed - float mEvadeDirection; + int mEvadeDirectionIndex; void chooseEvasionDirection(bool samePosition); }; From 8de3ce90a7e0d219137eaf61ec120c24f8419c2c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Sep 2015 18:04:24 +0200 Subject: [PATCH 404/419] Add comments for weather IDs --- apps/openmw/mwworld/weather.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index cdd0a8d79..b0e617f2b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -458,16 +458,16 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mPlayingSoundID() { mWeatherSettings.reserve(10); - addWeather("Clear", fallback); - addWeather("Cloudy", fallback); - addWeather("Foggy", fallback); - addWeather("Overcast", fallback); - addWeather("Rain", fallback, "rain"); - addWeather("Thunderstorm", fallback, "rain heavy"); - addWeather("Ashstorm", fallback, "ashstorm", "meshes\\ashcloud.nif"); - addWeather("Blight", fallback, "blight", "meshes\\blightcloud.nif"); - addWeather("Snow", fallback, "", "meshes\\snow.nif"); - addWeather("Blizzard", fallback, "BM Blizzard", "meshes\\blizzard.nif"); + addWeather("Clear", fallback); // 0 + addWeather("Cloudy", fallback); // 1 + addWeather("Foggy", fallback); // 2 + addWeather("Overcast", fallback); // 3 + addWeather("Rain", fallback, "rain"); // 4 + addWeather("Thunderstorm", fallback, "rain heavy"); // 5 + addWeather("Ashstorm", fallback, "ashstorm", "meshes\\ashcloud.nif"); // 6 + addWeather("Blight", fallback, "blight", "meshes\\blightcloud.nif"); // 7 + addWeather("Snow", fallback, "", "meshes\\snow.nif"); // 8 + addWeather("Blizzard", fallback, "BM Blizzard", "meshes\\blizzard.nif"); // 9 Store::iterator it = store.get().begin(); for(; it != store.get().end(); ++it) From 6bafa564d4b96a7336490d6ea4be8b96438ee72b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Sep 2015 18:08:31 +0200 Subject: [PATCH 405/419] Move sun texture setting out of the Updater class so we can reuse the Updater for fading the flash texture --- apps/openmw/mwrender/sky.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index dba2e5b0e..67e842c8d 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -359,14 +359,20 @@ class Sun : public CelestialBody public: Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) : CelestialBody(parentNode, 1.0f, 1) - , mUpdater(new Updater(textureManager)) + , mUpdater(new Updater) { - mGeode->addUpdateCallback(mUpdater); + mTransform->addUpdateCallback(mUpdater); + + osg::ref_ptr sunTex = textureManager.getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, + osg::Texture::CLAMP); + + mGeode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); } ~Sun() { - mGeode->removeUpdateCallback(mUpdater); + mTransform->removeUpdateCallback(mUpdater); } virtual void adjustTransparency(const float ratio) @@ -387,22 +393,15 @@ public: private: struct Updater : public SceneUtil::StateSetUpdater { - Resource::TextureManager& mTextureManager; osg::Vec4f mColor; - Updater(Resource::TextureManager& textureManager) - : mTextureManager(textureManager) - , mColor(0.0f, 0.0f, 0.0f, 1.0f) + Updater() + : mColor(1.f, 1.f, 1.f, 1.0f) { } virtual void setDefaults(osg::StateSet* stateset) { - osg::ref_ptr tex = mTextureManager.getTexture2D("textures/tx_sun_05.dds", - osg::Texture::CLAMP, - osg::Texture::CLAMP); - - stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); } From d191a528470b990be094bf243b697694ad159dda Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Sep 2015 18:10:02 +0200 Subject: [PATCH 406/419] Create occlusion query nodes for the sun flash --- apps/openmw/mwrender/sky.cpp | 57 ++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 67e842c8d..3d2b35c37 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include #include #include @@ -368,6 +371,18 @@ public: osg::Texture::CLAMP); mGeode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); + + // Slightly downscale the query geometry since the sun quad has a transparent texture that doesn't cover the whole area + osg::ref_ptr queryTransform (new osg::PositionAttitudeTransform); + queryTransform->setScale(osg::Vec3f(0.5f, 0.5f, 0.5f)); + // Need to render after the world geometry so we can correctly test for occlusions + queryTransform->getOrCreateStateSet()->setRenderBinDetails(10, "RenderBin"); + queryTransform->getOrCreateStateSet()->setNestRenderBins(false); + + mTransform->addChild(queryTransform); + + mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryTransform, true); + mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryTransform, false); } ~Sun() @@ -391,6 +406,46 @@ public: } private: + /// @param queryVisible If true, queries the amount of visible pixels. If false, queries the total amount of pixels. + osg::ref_ptr createOcclusionQueryNode(osg::Group* parent, bool queryVisible) + { + osg::ref_ptr oqn = new osg::OcclusionQueryNode; + oqn->setQueriesEnabled(true); + + // Make it fast! A DYNAMIC query geometry means we can't break frame until the flare is rendered (which is rendered after all the other geometry, + // so that would be pretty bad). STATIC should be safe, since our node's local bounds are static, thus computeBounds() which modifies the queryGeometry + // is only called once. + // Note the debug geometry setDebugDisplay(true) is always DYNAMIC and that can't be changed, not a big deal. + oqn->getQueryGeometry()->setDataVariance(osg::Object::STATIC); + + osg::ref_ptr queryGeode = osg::clone(mGeode.get(), osg::CopyOp::DEEP_COPY_ALL); + // Disable writing to the color buffer. We are using this geode for visibility tests only. + osg::ref_ptr colormask (new osg::ColorMask(0, 0, 0, 0)); + queryGeode->getOrCreateStateSet()->setAttributeAndModes(colormask, osg::StateAttribute::ON); + + oqn->addChild(queryGeode); + + if (queryVisible) + { + osg::ref_ptr depth (new osg::Depth); + depth->setFunction(osg::Depth::LESS); + // This is a trick to make fragments written by the query always use the maximum depth value, + // without having to retrieve the current far clipping distance. + // We want the sun glare to be "infinitely" far away. + depth->setZNear(1.0); + depth->setZFar(1.0); + oqn->getQueryStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); + } + else + { + oqn->getQueryStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + } + + parent->addChild(oqn); + + return oqn; + } + struct Updater : public SceneUtil::StateSetUpdater { osg::Vec4f mColor; @@ -414,6 +469,8 @@ private: }; osg::ref_ptr mUpdater; + osg::ref_ptr mOcclusionQueryVisiblePixels; + osg::ref_ptr mOcclusionQueryTotalPixels; }; class Moon : public CelestialBody From 89d9323c2b6d870d7ea5d0b3d33a84a834916ef5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Sep 2015 18:19:36 +0200 Subject: [PATCH 407/419] Document RenderBin numbers in a common header to keep them organised --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwrender/renderbin.hpp | 20 ++++++++++++++++++++ apps/openmw/mwrender/sky.cpp | 5 +++-- apps/openmw/mwrender/water.cpp | 3 ++- 4 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 apps/openmw/mwrender/renderbin.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 2dd16a4e6..5a9b52cb2 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -23,6 +23,7 @@ add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation + renderbin ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/renderbin.hpp b/apps/openmw/mwrender/renderbin.hpp new file mode 100644 index 000000000..63ccdd259 --- /dev/null +++ b/apps/openmw/mwrender/renderbin.hpp @@ -0,0 +1,20 @@ +#ifndef OPENMW_MWRENDER_RENDERBIN_H +#define OPENMW_MWRENDER_RENDERBIN_H + +namespace MWRender +{ + + /// Defines the render bin numbers used in the OpenMW scene graph. The bin with the lowest number is rendered first. + /// Beware of RenderBin nesting, in most cases you will want to use setNestRenderBins(false). + enum RenderBins + { + RenderBin_Sky = -1, + RenderBin_Default = 0, + RenderBin_Water = 9, + RenderBin_OcclusionQuery = 10, + RenderBin_SunGlare = 11 + }; + +} + +#endif diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 3d2b35c37..8588d2158 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -41,6 +41,7 @@ #include "../mwworld/fallback.hpp" #include "vismask.hpp" +#include "renderbin.hpp" namespace { @@ -376,7 +377,7 @@ public: osg::ref_ptr queryTransform (new osg::PositionAttitudeTransform); queryTransform->setScale(osg::Vec3f(0.5f, 0.5f, 0.5f)); // Need to render after the world geometry so we can correctly test for occlusions - queryTransform->getOrCreateStateSet()->setRenderBinDetails(10, "RenderBin"); + queryTransform->getOrCreateStateSet()->setRenderBinDetails(RenderBin_OcclusionQuery, "RenderBin"); queryTransform->getOrCreateStateSet()->setNestRenderBins(false); mTransform->addChild(queryTransform); @@ -680,7 +681,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana mRootNode = skyroot; // By default render before the world is rendered - mRootNode->getOrCreateStateSet()->setRenderBinDetails(-1, "RenderBin"); + mRootNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Sky, "RenderBin"); } void SkyManager::create() diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index b5f141963..03ab58e6b 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -21,6 +21,7 @@ #include "vismask.hpp" #include "ripplesimulation.hpp" +#include "renderbin.hpp" namespace { @@ -86,7 +87,7 @@ namespace depth->setWriteMask(false); stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); - stateset->setRenderBinDetails(9, "RenderBin"); + stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); std::vector > textures; for (int i=0; i<32; ++i) From ac5d0bf40502f355a2bd46cdf57c12b3723d59b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Sep 2015 18:22:16 +0200 Subject: [PATCH 408/419] Render the sun flash (not adjusted based on occlusion yet) --- apps/openmw/mwrender/sky.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 8588d2158..17b4f2f6a 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -364,6 +364,7 @@ public: Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) : CelestialBody(parentNode, 1.0f, 1) , mUpdater(new Updater) + , mInitialFlashScale(2.6f) { mTransform->addUpdateCallback(mUpdater); @@ -384,6 +385,8 @@ public: mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryTransform, true); mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryTransform, false); + + createSunFlash(textureManager); } ~Sun() @@ -447,6 +450,34 @@ private: return oqn; } + void createSunFlash(Resource::TextureManager& textureManager) + { + osg::ref_ptr tex = textureManager.getTexture2D("textures/tx_sun_flash_grey_05.dds", + osg::Texture::CLAMP, + osg::Texture::CLAMP); + + osg::ref_ptr transform (new osg::PositionAttitudeTransform); + transform->setScale(osg::Vec3f(mInitialFlashScale, mInitialFlashScale, mInitialFlashScale)); + + mTransform->addChild(transform); + + osg::ref_ptr geode (new osg::Geode); + transform->addChild(geode); + + geode->addDrawable(createTexturedQuad()); + + osg::StateSet* stateset = geode->getOrCreateStateSet(); + + stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); + stateset->setAttributeAndModes(createUnlitMaterial(), + osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + stateset->setRenderBinDetails(RenderBin_SunGlare, "RenderBin"); + stateset->setNestRenderBins(false); + + // TODO: change size depending on occlusion + } + struct Updater : public SceneUtil::StateSetUpdater { osg::Vec4f mColor; @@ -472,6 +503,7 @@ private: osg::ref_ptr mUpdater; osg::ref_ptr mOcclusionQueryVisiblePixels; osg::ref_ptr mOcclusionQueryTotalPixels; + float mInitialFlashScale; }; class Moon : public CelestialBody From a2a4532e71317332068e6617a29a2bfc5aa20544 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 16:03:30 +0200 Subject: [PATCH 409/419] Add the full-screen sun glare effect --- apps/openmw/mwrender/sky.cpp | 262 +++++++++++++++++++++++++++++--- apps/openmw/mwrender/sky.hpp | 3 +- apps/openmw/mwworld/weather.cpp | 8 + 3 files changed, 254 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 17b4f2f6a..69041a724 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -376,7 +377,7 @@ public: // Slightly downscale the query geometry since the sun quad has a transparent texture that doesn't cover the whole area osg::ref_ptr queryTransform (new osg::PositionAttitudeTransform); - queryTransform->setScale(osg::Vec3f(0.5f, 0.5f, 0.5f)); + queryTransform->setScale(osg::Vec3f(0.4f, 0.4f, 0.4f)); // Need to render after the world geometry so we can correctly test for occlusions queryTransform->getOrCreateStateSet()->setRenderBinDetails(RenderBin_OcclusionQuery, "RenderBin"); queryTransform->getOrCreateStateSet()->setNestRenderBins(false); @@ -386,17 +387,26 @@ public: mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryTransform, true); mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryTransform, false); - createSunFlash(textureManager); + osg::PositionAttitudeTransform* sunFlashNode = createSunFlash(textureManager); + + mSunFlashCallback = new SunFlashCallback(mOcclusionQueryVisiblePixels, mOcclusionQueryTotalPixels, sunFlashNode, mTransform); + mTransform->addCullCallback(mSunFlashCallback); + + createSunGlare(); } ~Sun() { mTransform->removeUpdateCallback(mUpdater); + destroySunFlash(); + destroySunGlare(); } virtual void adjustTransparency(const float ratio) { mUpdater->mColor.a() = ratio; + if (mSunGlareCallback) + mSunGlareCallback->setGlareView(ratio); } void setDirection(const osg::Vec3f& direction) @@ -409,6 +419,12 @@ public: mTransform->setAttitude(quat); } + void setGlareTimeOfDayFade(float val) + { + if (mSunGlareCallback) + mSunGlareCallback->setTimeOfDayFade(val); + } + private: /// @param queryVisible If true, queries the amount of visible pixels. If false, queries the total amount of pixels. osg::ref_ptr createOcclusionQueryNode(osg::Group* parent, bool queryVisible) @@ -450,7 +466,7 @@ private: return oqn; } - void createSunFlash(Resource::TextureManager& textureManager) + osg::PositionAttitudeTransform* createSunFlash(Resource::TextureManager& textureManager) { osg::ref_ptr tex = textureManager.getTexture2D("textures/tx_sun_flash_grey_05.dds", osg::Texture::CLAMP, @@ -474,12 +490,58 @@ private: stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); stateset->setRenderBinDetails(RenderBin_SunGlare, "RenderBin"); stateset->setNestRenderBins(false); - - // TODO: change size depending on occlusion + return transform; + } + void destroySunFlash() + { + mTransform->removeCullCallback(mSunFlashCallback); + mSunFlashCallback = NULL; } - struct Updater : public SceneUtil::StateSetUpdater + void createSunGlare() { + osg::ref_ptr camera (new osg::Camera); + camera->setProjectionMatrix(osg::Matrix::identity()); + camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); // add to skyRoot instead? + camera->setViewMatrix(osg::Matrix::identity()); + camera->setClearMask(0); + camera->setRenderOrder(osg::Camera::NESTED_RENDER); + camera->setAllowEventFocus(false); + + osg::ref_ptr geode (new osg::Geode); + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3f(-1,-1,0), osg::Vec3f(2,0,0), osg::Vec3f(0,2,0)); + geode->addDrawable(geom); + + camera->addChild(geode); + + osg::StateSet* stateset = geom->getOrCreateStateSet(); + + stateset->setRenderBinDetails(RenderBin_SunGlare, "RenderBin"); + stateset->setNestRenderBins(false); + stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + + // set up additive blending + osg::ref_ptr blendFunc (new osg::BlendFunc); + blendFunc->setSource(osg::BlendFunc::SRC_ALPHA); + blendFunc->setDestination(osg::BlendFunc::ONE); + stateset->setAttributeAndModes(blendFunc, osg::StateAttribute::ON); + + mSunGlareCallback = new SunGlareCallback(mOcclusionQueryVisiblePixels, mOcclusionQueryTotalPixels, mTransform); + mSunGlareNode = camera; + + mSunGlareNode->addCullCallback(mSunGlareCallback); + + mTransform->addChild(camera); + } + void destroySunGlare() + { + mSunGlareNode->removeCullCallback(mSunGlareCallback); + mSunGlareCallback = NULL; + } + + class Updater : public SceneUtil::StateSetUpdater + { + public: osg::Vec4f mColor; Updater() @@ -489,8 +551,7 @@ private: virtual void setDefaults(osg::StateSet* stateset) { - stateset->setAttributeAndModes(createUnlitMaterial(), - osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); } virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) @@ -500,7 +561,181 @@ private: } }; + class OcclusionCallback : public osg::NodeCallback + { + public: + OcclusionCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal) + : mOcclusionQueryVisiblePixels(oqnVisible) + , mOcclusionQueryTotalPixels(oqnTotal) + { + } + + protected: + float getVisibleRatio (osg::Camera* camera) + { + int visible = mOcclusionQueryVisiblePixels->getQueryGeometry()->getNumPixels(camera); + int total = mOcclusionQueryTotalPixels->getQueryGeometry()->getNumPixels(camera); + + float visibleRatio = 0.f; + if (total > 0) + visibleRatio = static_cast(visible) / static_cast(total); + + float dt = MWBase::Environment::get().getFrameDuration(); + + float lastRatio = mLastRatio[osg::observer_ptr(camera)]; + + float change = dt*10; + + if (visibleRatio > lastRatio) + visibleRatio = std::min(visibleRatio, lastRatio + change); + else + visibleRatio = std::max(visibleRatio, lastRatio - change); + + mLastRatio[osg::observer_ptr(camera)] = visibleRatio; + + return visibleRatio; + } + + private: + osg::ref_ptr mOcclusionQueryVisiblePixels; + osg::ref_ptr mOcclusionQueryTotalPixels; + + std::map, float> mLastRatio; + }; + + /// SunFlashCallback handles fading/scaling of the sun flash depending on occlusion query result. Must be attached as a cull callback. + class SunFlashCallback : public OcclusionCallback + { + public: + SunFlashCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal, + osg::ref_ptr flashNode, + osg::ref_ptr sunTransform) + : OcclusionCallback(oqnVisible, oqnTotal) + , mFlashNode(flashNode) + { + mInitialScale = mFlashNode->getScale().x(); + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + float visibleRatio = getVisibleRatio(cv->getCurrentCamera()); + + handleOcclusionResult (visibleRatio, cv); + + traverse(node, nv); + } + + void handleOcclusionResult(float visibleRatio, osgUtil::CullVisitor* cv) + { + // TODO + } + + private: + float mInitialScale; + osg::ref_ptr mFlashNode; + }; + + + /// SunGlareCallback controls a full-screen glare effect depending on occlusion query result and the angle between sun and camera. + /// Must be attached as a cull callback to the node above the glare node. + class SunGlareCallback : public OcclusionCallback + { + public: + SunGlareCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal, + osg::ref_ptr sunTransform) + : OcclusionCallback(oqnVisible, oqnTotal) + , mSunTransform(sunTransform) + , mTimeOfDayFade(1.f) + , mGlareView(1.f) + { + + } + + virtual void operator ()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + float angleRadians = getAngleToSunInRadians(cv->getCurrentCamera()); + float visibleRatio = getVisibleRatio(cv->getCurrentCamera()); + + const float angleMaxRadians = osg::DegreesToRadians(30.f); // Sun Glare Fader Angle Max + + float value = 1.f - std::min(1.f, angleRadians / angleMaxRadians); + + const float sunGlareFaderMax = 0.5f; + float fade = value * sunGlareFaderMax; + + fade *= mTimeOfDayFade * mGlareView * visibleRatio; + + if (fade == 0.f) + { + // no traverse + return; + } + else + { + osg::ref_ptr stateset (new osg::StateSet); + + osg::ref_ptr mat (createUnlitMaterial()); + + osg::Vec4f sunGlareFaderColor (222/255.f, 95/255.f, 39/255.f, 1); + + // Replicating a design flaw in MW. The color was being set on both ambient and emissive properties, which multiplies the result by two, + // then finally gets clamped by the fixed function pipeline. With the default INI settings, only the red component gets clamped, + // so the resulting color looks more orange than red. + sunGlareFaderColor *= 2; + for (int i=0; i<3; ++i) + sunGlareFaderColor[i] = std::min(1.f, sunGlareFaderColor[i]); + + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,1)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,fade)); + mat->setEmission(osg::Material::FRONT_AND_BACK, sunGlareFaderColor); + mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,0)); + + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); + + cv->pushStateSet(stateset); + traverse(node, nv); + cv->popStateSet(); + } + } + + void setTimeOfDayFade(float val) + { + mTimeOfDayFade = val; + } + + void setGlareView(float glareView) + { + mGlareView = glareView; + } + + private: + float getAngleToSunInRadians(osg::Camera* camera) const + { + osg::Vec3d eye, center, up; + camera->getViewMatrixAsLookAt(eye, center, up); + + osg::Vec3d forward = center - eye; + osg::Vec3d sun = mSunTransform->getPosition(); + + forward.normalize(); + sun.normalize(); + float angleRadians = std::acos(forward * sun); + return angleRadians; + } + + osg::ref_ptr mSunTransform; + float mTimeOfDayFade; + float mGlareView; + }; + osg::ref_ptr mUpdater; + osg::ref_ptr mSunFlashCallback; + osg::ref_ptr mSunGlareCallback; + osg::ref_ptr mSunGlareNode; osg::ref_ptr mOcclusionQueryVisiblePixels; osg::ref_ptr mOcclusionQueryTotalPixels; float mInitialFlashScale; @@ -1223,11 +1458,6 @@ void SkyManager::setWeather(const WeatherResult& weather) mParticleFader->setAlpha(weather.mEffectFade); } -void SkyManager::setGlare(const float glare) -{ - mGlare = glare; -} - void SkyManager::sunEnable() { if (!mCreated) return; @@ -1276,11 +1506,9 @@ void SkyManager::setDate(int day, int month) mMonth = month; } -void SkyManager::setGlareEnabled (bool enabled) +void SkyManager::setGlareTimeOfDayFade(float val) { - if (!mCreated || !mEnabled) - return; - //mSunGlare->setVisible (mSunEnabled && enabled); + mSun->setGlareTimeOfDayFade(val); } } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index de27cf447..b9b27b3d0 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -140,8 +140,7 @@ namespace MWRender void setMasserState(const MoonState& state); void setSecundaState(const MoonState& state); - void setGlare(const float glare); - void setGlareEnabled(bool enabled); + void setGlareTimeOfDayFade(float val); private: void create(); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index b0e617f2b..050b6652c 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -624,6 +624,14 @@ void WeatherManager::update(float duration, bool paused) mRendering.setSunDirection( final * -1 ); } + float peakHour = mSunriseTime + (mSunsetTime - mSunriseTime) / 2; + if (time.getHour() < mSunriseTime || time.getHour() > mSunsetTime) + mRendering.getSkyManager()->setGlareTimeOfDayFade(0); + else if (time.getHour() < peakHour) + mRendering.getSkyManager()->setGlareTimeOfDayFade(1 - (peakHour - time.getHour()) / (peakHour - mSunriseTime)); + else + mRendering.getSkyManager()->setGlareTimeOfDayFade(1 - (time.getHour() - peakHour) / (mSunsetTime - peakHour)); + mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time)); mRendering.getSkyManager()->setSecundaState(mSecunda.calculateState(time)); From 96b31d3bba084e2a95ae63c3f245b427dc1f3977 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 16:34:30 +0200 Subject: [PATCH 410/419] Scale the sun flash texture depending on occlusion query --- apps/openmw/mwrender/sky.cpp | 73 ++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 69041a724..78b1aba70 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -387,11 +387,7 @@ public: mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryTransform, true); mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryTransform, false); - osg::PositionAttitudeTransform* sunFlashNode = createSunFlash(textureManager); - - mSunFlashCallback = new SunFlashCallback(mOcclusionQueryVisiblePixels, mOcclusionQueryTotalPixels, sunFlashNode, mTransform); - mTransform->addCullCallback(mSunFlashCallback); - + createSunFlash(textureManager); createSunGlare(); } @@ -466,7 +462,7 @@ private: return oqn; } - osg::PositionAttitudeTransform* createSunFlash(Resource::TextureManager& textureManager) + void createSunFlash(Resource::TextureManager& textureManager) { osg::ref_ptr tex = textureManager.getTexture2D("textures/tx_sun_flash_grey_05.dds", osg::Texture::CLAMP, @@ -490,12 +486,19 @@ private: stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); stateset->setRenderBinDetails(RenderBin_SunGlare, "RenderBin"); stateset->setNestRenderBins(false); - return transform; + + mSunFlashNode = transform; + + mSunFlashCallback = new SunFlashCallback(mOcclusionQueryVisiblePixels, mOcclusionQueryTotalPixels); + mSunFlashNode->addCullCallback(mSunFlashCallback); } void destroySunFlash() { - mTransform->removeCullCallback(mSunFlashCallback); - mSunFlashCallback = NULL; + if (mSunFlashNode) + { + mSunFlashNode->removeCullCallback(mSunFlashCallback); + mSunFlashCallback = NULL; + } } void createSunGlare() @@ -535,8 +538,11 @@ private: } void destroySunGlare() { - mSunGlareNode->removeCullCallback(mSunGlareCallback); - mSunGlareCallback = NULL; + if (mSunGlareNode) + { + mSunGlareNode->removeCullCallback(mSunGlareCallback); + mSunGlareCallback = NULL; + } } class Updater : public SceneUtil::StateSetUpdater @@ -603,17 +609,13 @@ private: std::map, float> mLastRatio; }; - /// SunFlashCallback handles fading/scaling of the sun flash depending on occlusion query result. Must be attached as a cull callback. + /// SunFlashCallback handles fading/scaling of a node depending on occlusion query result. Must be attached as a cull callback. class SunFlashCallback : public OcclusionCallback { public: - SunFlashCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal, - osg::ref_ptr flashNode, - osg::ref_ptr sunTransform) + SunFlashCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal) : OcclusionCallback(oqnVisible, oqnTotal) - , mFlashNode(flashNode) { - mInitialScale = mFlashNode->getScale().x(); } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) @@ -622,19 +624,33 @@ private: float visibleRatio = getVisibleRatio(cv->getCurrentCamera()); - handleOcclusionResult (visibleRatio, cv); + if (visibleRatio > 0.f) + { + // rescale into [0.35, 1.0] range + const float threshold = 0.35; + visibleRatio = visibleRatio * (1.f - threshold) + threshold; + } - traverse(node, nv); + float scale = visibleRatio; + + if (scale == 0.f) + { + // no traverse + return; + } + else + { + osg::Matrix modelView = *cv->getModelViewMatrix(); + + modelView.preMultScale(osg::Vec3f(visibleRatio, visibleRatio, visibleRatio)); + + cv->pushModelViewMatrix(new osg::RefMatrix(modelView), osg::Transform::RELATIVE_RF); + + traverse(node, nv); + + cv->popModelViewMatrix(); + } } - - void handleOcclusionResult(float visibleRatio, osgUtil::CullVisitor* cv) - { - // TODO - } - - private: - float mInitialScale; - osg::ref_ptr mFlashNode; }; @@ -734,6 +750,7 @@ private: osg::ref_ptr mUpdater; osg::ref_ptr mSunFlashCallback; + osg::ref_ptr mSunFlashNode; osg::ref_ptr mSunGlareCallback; osg::ref_ptr mSunGlareNode; osg::ref_ptr mOcclusionQueryVisiblePixels; From 9bb6c3f288c001ba11a2c08bf260ad927410f253 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 17:09:24 +0200 Subject: [PATCH 411/419] Improve accuracy of sun occlusion query (use circular shape) --- apps/openmw/mwrender/sky.cpp | 43 +++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 78b1aba70..63a041579 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -375,17 +376,20 @@ public: mGeode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); - // Slightly downscale the query geometry since the sun quad has a transparent texture that doesn't cover the whole area - osg::ref_ptr queryTransform (new osg::PositionAttitudeTransform); - queryTransform->setScale(osg::Vec3f(0.4f, 0.4f, 0.4f)); + osg::ref_ptr queryNode (new osg::Group); // Need to render after the world geometry so we can correctly test for occlusions - queryTransform->getOrCreateStateSet()->setRenderBinDetails(RenderBin_OcclusionQuery, "RenderBin"); - queryTransform->getOrCreateStateSet()->setNestRenderBins(false); + queryNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_OcclusionQuery, "RenderBin"); + queryNode->getOrCreateStateSet()->setNestRenderBins(false); + // Set up alpha testing on the occlusion testing subgraph, that way we can get the occlusion tested fragments to match the circular shape of the sun + osg::ref_ptr alphaFunc (new osg::AlphaFunc); + alphaFunc->setFunction(osg::AlphaFunc::GREATER, 0.8); + queryNode->getOrCreateStateSet()->setAttributeAndModes(alphaFunc, osg::StateAttribute::ON); + queryNode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); - mTransform->addChild(queryTransform); + mTransform->addChild(queryNode); - mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryTransform, true); - mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryTransform, false); + mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryNode, true); + mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryNode, false); createSunFlash(textureManager); createSunGlare(); @@ -441,6 +445,26 @@ private: oqn->addChild(queryGeode); + // Remove the default OFF|PROTECTED setting for texturing. We *want* to enable texturing for alpha testing purposes + oqn->getQueryStateSet()->removeTextureMode(0, GL_TEXTURE_2D); + + // Need to add texture coordinates so that texturing works. A bit ugly, relies on the vertex ordering + // used within OcclusionQueryNode. + osg::ref_ptr texCoordArray (new osg::Vec2Array); + for (int i=0; i<8; ++i) + { + texCoordArray->push_back(osg::Vec2(0,0)); + texCoordArray->push_back(osg::Vec2(1,0)); + texCoordArray->push_back(osg::Vec2(0,0)); + texCoordArray->push_back(osg::Vec2(1,0)); + texCoordArray->push_back(osg::Vec2(1,1)); + texCoordArray->push_back(osg::Vec2(0,1)); + texCoordArray->push_back(osg::Vec2(0,1)); + texCoordArray->push_back(osg::Vec2(1,1)); + } + + oqn->getQueryGeometry()->setTexCoordArray(0, texCoordArray, osg::Array::BIND_PER_VERTEX); + if (queryVisible) { osg::ref_ptr depth (new osg::Depth); @@ -626,8 +650,7 @@ private: if (visibleRatio > 0.f) { - // rescale into [0.35, 1.0] range - const float threshold = 0.35; + const float threshold = 0.6; visibleRatio = visibleRatio * (1.f - threshold) + threshold; } From 854fd9fe051c17395ec49a4e8321497b1c9e721e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 17:18:27 +0200 Subject: [PATCH 412/419] Remove dead code --- apps/openmw/mwrender/sky.cpp | 53 ++++++------------------------------ apps/openmw/mwrender/sky.hpp | 3 -- 2 files changed, 9 insertions(+), 47 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 63a041579..86a9a1765 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -972,8 +972,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mCloudSpeed(0.0f) , mStarsOpacity(0.0f) , mRemainingTransitionTime(0.0f) - , mGlare(0.0f) - , mGlareFade(0.0f) , mRainEnabled(false) , mRainSpeed(0) , mRainFrequency(1) @@ -1290,32 +1288,6 @@ void SkyManager::update(float duration) mCloudUpdater->setAnimationTimer(mCloudAnimationTimer); mCloudUpdater2->setAnimationTimer(mCloudAnimationTimer); - if (mSunEnabled) - { - // take 1/10 sec for fading the glare effect from invisible to full - if (mGlareFade > mGlare) - { - mGlareFade -= duration*10; - if (mGlareFade < mGlare) mGlareFade = mGlare; - } - else if (mGlareFade < mGlare) - { - mGlareFade += duration*10; - if (mGlareFade > mGlare) mGlareFade = mGlare; - } - - // increase the strength of the sun glare effect depending - // on how directly the player is looking at the sun - /* - Vector3 sun = mSunGlare->getPosition(); - Vector3 cam = mCamera->getRealDirection(); - const Degree angle = sun.angleBetween( cam ); - float val = 1- (angle.valueDegrees() / 180.f); - val = (val*val*val*val)*6; - mSunGlare->setSize(val * mGlareFade); - */ - } - // rotate the stars by 360 degrees every 4 days mAtmosphereNightRoll += MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*osg::DegreesToRadians(360.f) / (3600*96.f); if (mAtmosphereNightNode->getNodeMask() != 0) @@ -1466,6 +1438,15 @@ void SkyManager::setWeather(const WeatherResult& weather) mMasser->adjustTransparency(weather.mGlareView); mSecunda->adjustTransparency(weather.mGlareView); + + /* + float timeofday_angle = std::abs(mSun->getPosition().z/mSunGlare->getPosition().length()); + float strength; + if (timeofday_angle <= 0.44) + strength = timeofday_angle/0.44f; + else + strength = 1.f; + */ mSun->adjustTransparency(weather.mGlareView); float nextStarsOpacity = weather.mNightFade * weather.mGlareView; @@ -1478,20 +1459,6 @@ void SkyManager::setWeather(const WeatherResult& weather) mAtmosphereNightNode->setNodeMask(weather.mNight ? ~0 : 0); - - /* - float strength; - float timeofday_angle = std::abs(mSunGlare->getPosition().z/mSunGlare->getPosition().length()); - if (timeofday_angle <= 0.44) - strength = timeofday_angle/0.44f; - else - strength = 1.f; - - mSunGlare->setVisibility(weather.mGlareView * mGlareFade * strength); - - mSun->setVisibility(weather.mGlareView * strength); - */ - if (mRainFader) mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold? if (mParticleFader) @@ -1522,8 +1489,6 @@ void SkyManager::setSunDirection(const osg::Vec3f& direction) if (!mCreated) return; mSun->setDirection(direction); - - //mSunGlare->setPosition(direction); } void SkyManager::setMasserState(const MoonState& state) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index b9b27b3d0..0cef46346 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -209,9 +209,6 @@ namespace MWRender float mRemainingTransitionTime; - float mGlare; // target - float mGlareFade; // actual - bool mRainEnabled; std::string mRainEffect; float mRainSpeed; From d812434feeb8b32aa1edada2e240994e5715cd43 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 17:32:57 +0200 Subject: [PATCH 413/419] Add a subtle fading effect to the sun flash texture --- apps/openmw/mwrender/sky.cpp | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 86a9a1765..7f5666b17 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -385,6 +385,7 @@ public: alphaFunc->setFunction(osg::AlphaFunc::GREATER, 0.8); queryNode->getOrCreateStateSet()->setAttributeAndModes(alphaFunc, osg::StateAttribute::ON); queryNode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); + queryNode->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); mTransform->addChild(queryNode); @@ -407,6 +408,8 @@ public: mUpdater->mColor.a() = ratio; if (mSunGlareCallback) mSunGlareCallback->setGlareView(ratio); + if (mSunFlashCallback) + mSunFlashCallback->setGlareView(ratio); } void setDirection(const osg::Vec3f& direction) @@ -505,8 +508,6 @@ private: osg::StateSet* stateset = geode->getOrCreateStateSet(); stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); - stateset->setAttributeAndModes(createUnlitMaterial(), - osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); stateset->setRenderBinDetails(RenderBin_SunGlare, "RenderBin"); stateset->setNestRenderBins(false); @@ -639,6 +640,7 @@ private: public: SunFlashCallback(osg::ref_ptr oqnVisible, osg::ref_ptr oqnTotal) : OcclusionCallback(oqnVisible, oqnTotal) + , mGlareView(1.f) { } @@ -648,8 +650,20 @@ private: float visibleRatio = getVisibleRatio(cv->getCurrentCamera()); + osg::ref_ptr stateset; + if (visibleRatio > 0.f) { + const float fadeThreshold = 0.1; + if (visibleRatio < fadeThreshold) + { + float fade = 1.f - (fadeThreshold - visibleRatio) / fadeThreshold; + osg::ref_ptr mat (createUnlitMaterial()); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,fade*mGlareView)); + stateset = new osg::StateSet; + stateset->setAttributeAndModes(mat, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + const float threshold = 0.6; visibleRatio = visibleRatio * (1.f - threshold) + threshold; } @@ -667,13 +681,27 @@ private: modelView.preMultScale(osg::Vec3f(visibleRatio, visibleRatio, visibleRatio)); + if (stateset) + cv->pushStateSet(stateset); + cv->pushModelViewMatrix(new osg::RefMatrix(modelView), osg::Transform::RELATIVE_RF); traverse(node, nv); cv->popModelViewMatrix(); + + if (stateset) + cv->popStateSet(); } } + + void setGlareView(float value) + { + mGlareView = value; + } + + private: + float mGlareView; }; @@ -728,10 +756,8 @@ private: for (int i=0; i<3; ++i) sunGlareFaderColor[i] = std::min(1.f, sunGlareFaderColor[i]); - mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,1)); mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,fade)); mat->setEmission(osg::Material::FRONT_AND_BACK, sunGlareFaderColor); - mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,0)); stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); From 1a1f1fae87097885d11773f0137aed5ba0f03b51 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 17:50:36 +0200 Subject: [PATCH 414/419] Minor cleanup --- apps/openmw/mwrender/sky.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 7f5666b17..754e00909 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -366,7 +366,6 @@ public: Sun(osg::Group* parentNode, Resource::TextureManager& textureManager) : CelestialBody(parentNode, 1.0f, 1) , mUpdater(new Updater) - , mInitialFlashScale(2.6f) { mTransform->addUpdateCallback(mUpdater); @@ -496,7 +495,8 @@ private: osg::Texture::CLAMP); osg::ref_ptr transform (new osg::PositionAttitudeTransform); - transform->setScale(osg::Vec3f(mInitialFlashScale, mInitialFlashScale, mInitialFlashScale)); + const float scale = 2.6f; + transform->setScale(osg::Vec3f(scale,scale,scale)); mTransform->addChild(transform); @@ -804,7 +804,6 @@ private: osg::ref_ptr mSunGlareNode; osg::ref_ptr mOcclusionQueryVisiblePixels; osg::ref_ptr mOcclusionQueryTotalPixels; - float mInitialFlashScale; }; class Moon : public CelestialBody From f7e5a40143d0db37e349ee5e3541c3e2e2ace1b7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 17:58:57 +0200 Subject: [PATCH 415/419] Fix typo --- components/sceneutil/statesetupdater.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/statesetupdater.hpp b/components/sceneutil/statesetupdater.hpp index a4fcd7866..37d08e025 100644 --- a/components/sceneutil/statesetupdater.hpp +++ b/components/sceneutil/statesetupdater.hpp @@ -6,7 +6,7 @@ namespace SceneUtil { - /// @brief Implements efficient pre-frame updating of StateSets. + /// @brief Implements efficient per-frame updating of StateSets. /// @par With a naive update there would be race conditions when the OSG draw thread of the last frame /// queues up a StateSet that we want to modify for the next frame. To solve this we could set the StateSet to /// DYNAMIC data variance but that would undo all the benefits of the threading model - having the cull and draw From 385f4f729c967c02fbcc6fac062af9c0d27a82b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 21 Sep 2015 19:43:48 +0200 Subject: [PATCH 416/419] Implement SunDiscSunsetColor, fade the sun during sunrise & sunset --- apps/openmw/mwrender/sky.cpp | 23 ++++++++++++----------- apps/openmw/mwrender/sky.hpp | 2 ++ apps/openmw/mwworld/weather.cpp | 33 ++++++++++++++++++++++++++++++++- apps/openmw/mwworld/weather.hpp | 9 ++------- 4 files changed, 48 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 754e00909..317f2229d 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -402,6 +402,13 @@ public: destroySunGlare(); } + void setColor(const osg::Vec4f& color) + { + mUpdater->mColor.r() = color.r(); + mUpdater->mColor.g() = color.g(); + mUpdater->mColor.b() = color.b(); + } + virtual void adjustTransparency(const float ratio) { mUpdater->mColor.a() = ratio; @@ -576,7 +583,7 @@ private: osg::Vec4f mColor; Updater() - : mColor(1.f, 1.f, 1.f, 1.0f) + : mColor(1.f, 1.f, 1.f, 1.f) { } @@ -588,7 +595,8 @@ private: virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) { osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, mColor); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mColor.a())); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(mColor.r(), mColor.g(), mColor.b(), 1)); } }; @@ -1464,15 +1472,8 @@ void SkyManager::setWeather(const WeatherResult& weather) mMasser->adjustTransparency(weather.mGlareView); mSecunda->adjustTransparency(weather.mGlareView); - /* - float timeofday_angle = std::abs(mSun->getPosition().z/mSunGlare->getPosition().length()); - float strength; - if (timeofday_angle <= 0.44) - strength = timeofday_angle/0.44f; - else - strength = 1.f; - */ - mSun->adjustTransparency(weather.mGlareView); + mSun->setColor(weather.mSunDiscColor); + mSun->adjustTransparency(weather.mGlareView * weather.mSunDiscColor.a()); float nextStarsOpacity = weather.mNightFade * weather.mGlareView; if(weather.mNight && mStarsOpacity != nextStarsOpacity) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 0cef46346..072083d27 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -48,8 +48,10 @@ namespace MWRender osg::Vec4f mSkyColor; + // sun light color osg::Vec4f mSunColor; + // alpha is the sun transparency osg::Vec4f mSunDiscColor; float mFogDepth; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 050b6652c..78ae6fa0b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -432,6 +432,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mSunsetTime(fallback.getFallbackFloat("Weather_Sunset_Time")) , mSunriseDuration(fallback.getFallbackFloat("Weather_Sunrise_Duration")) , mSunsetDuration(fallback.getFallbackFloat("Weather_Sunset_Duration")) + , mSunPreSunsetTime(fallback.getFallbackFloat("Weather_Sun_Pre-Sunset_Time")) , mNightStart(mSunsetTime + mSunsetDuration) , mNightEnd(mSunriseTime - 0.5f) , mDayStart(mSunriseTime + mSunriseDuration) @@ -966,7 +967,6 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; mResult.mAmbientSoundVolume = 1.f; mResult.mEffectFade = 1.f; - mResult.mSunColor = current.mSunDiscSunsetColor; mResult.mIsStorm = current.mIsStorm; @@ -980,6 +980,7 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; + // TODO: use pre/post sunset/sunrise time values in [Weather] section // night if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) { @@ -1050,6 +1051,36 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mNightFade = factor; } } + + if (gameHour >= mSunsetTime - mSunPreSunsetTime) + { + float factor = (gameHour - (mSunsetTime - mSunPreSunsetTime)) / mSunPreSunsetTime; + factor = std::min(1.f, factor); + mResult.mSunDiscColor = lerp(osg::Vec4f(1,1,1,1), current.mSunDiscSunsetColor, factor); + // The SunDiscSunsetColor in the INI isn't exactly the resulting color on screen, most likely because + // MW applied the color to the ambient term as well. After the ambient and emissive terms are added together, the fixed pipeline + // would then clamp the total lighting to (1,1,1). A noticable change in color tone can be observed when only one of the color components gets clamped. + // Unfortunately that means we can't use the INI color as is, have to replicate the above nonsense. + mResult.mSunDiscColor = mResult.mSunDiscColor + osg::componentMultiply(mResult.mSunDiscColor, mResult.mAmbientColor); + for (int i=0; i<3; ++i) + mResult.mSunDiscColor[i] = std::min(1.f, mResult.mSunDiscColor[i]); + } + else + mResult.mSunDiscColor = osg::Vec4f(1,1,1,1); + + if (gameHour >= mSunsetTime) + { + float fade = std::min(1.f, (gameHour - mSunsetTime) / 2.f); + fade = fade*fade; + mResult.mSunDiscColor.a() = 1.f - fade; + } + else if (gameHour >= mSunriseTime && gameHour <= mSunriseTime + 1) + { + mResult.mSunDiscColor.a() = gameHour - mSunriseTime; + } + else + mResult.mSunDiscColor.a() = 1; + } inline void WeatherManager::calculateTransitionResult(const float factor, const float gameHour) diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index a0c93a460..7ce7c1bf8 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -75,7 +75,7 @@ namespace MWWorld float mLandFogDayDepth; float mLandFogNightDepth; - // Color modulation for the sun itself during sunset (not completely sure) + // Color modulation for the sun itself during sunset osg::Vec4f mSunDiscSunsetColor; // Used by scripts to animate signs, etc based on the wind (GetWindSpeed) @@ -242,12 +242,7 @@ namespace MWWorld float mSunsetTime; float mSunriseDuration; float mSunsetDuration; - // Some useful values - /* TODO: Use pre-sunrise_time, pre-sunset_time, - * post-sunrise_time, and post-sunset_time to better - * describe sunrise/sunset time. - * These values are fallbacks attached to weather. - */ + float mSunPreSunsetTime; float mNightStart; float mNightEnd; float mDayStart; From 7bef97bf3331dbdf9544c2caad17ecf68b3be96b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 22 Sep 2015 15:36:00 +0200 Subject: [PATCH 417/419] fixed local variable caching issue in automatic error checking (Fixes #2927) --- apps/opencs/model/world/scriptcontext.cpp | 17 +++++++++++-- apps/opencs/model/world/scriptcontext.hpp | 3 +++ apps/opencs/view/world/scripterrortable.cpp | 5 ++++ apps/opencs/view/world/scripterrortable.hpp | 5 ++++ apps/opencs/view/world/scriptsubview.cpp | 27 ++++++++++++++++++++- apps/opencs/view/world/scriptsubview.hpp | 1 + 6 files changed, 55 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index bcbca4b28..f644ad37a 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -39,8 +39,6 @@ char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const std::pair CSMWorld::ScriptContext::getMemberType (const std::string& name, const std::string& id) const { - /// \todo invalidate locals cache on change to scripts - std::string id2 = Misc::StringUtils::lowerCase (id); int index = mData.getScripts().searchId (id2); @@ -120,3 +118,18 @@ void CSMWorld::ScriptContext::clear() mIdsUpdated = false; mLocals.clear(); } + +bool CSMWorld::ScriptContext::clearLocals (const std::string& script) +{ + std::map::iterator iter = + mLocals.find (Misc::StringUtils::lowerCase (script)); + + if (iter!=mLocals.end()) + { + mLocals.erase (iter); + mIdsUpdated = false; + return true; + } + + return false; +} diff --git a/apps/opencs/model/world/scriptcontext.hpp b/apps/opencs/model/world/scriptcontext.hpp index 29ee42645..2cd59f070 100644 --- a/apps/opencs/model/world/scriptcontext.hpp +++ b/apps/opencs/model/world/scriptcontext.hpp @@ -46,6 +46,9 @@ namespace CSMWorld void clear(); ///< Remove all cached data. + + /// \return Were there any locals that needed clearing? + bool clearLocals (const std::string& script); }; } diff --git a/apps/opencs/view/world/scripterrortable.cpp b/apps/opencs/view/world/scripterrortable.cpp index b44e1c0bd..a9e315c73 100644 --- a/apps/opencs/view/world/scripterrortable.cpp +++ b/apps/opencs/view/world/scripterrortable.cpp @@ -131,6 +131,11 @@ void CSVWorld::ScriptErrorTable::clear() setRowCount (0); } +bool CSVWorld::ScriptErrorTable::clearLocals (const std::string& script) +{ + return mContext.clearLocals (script); +} + void CSVWorld::ScriptErrorTable::cellClicked (int row, int column) { if (item (row, 1)) diff --git a/apps/opencs/view/world/scripterrortable.hpp b/apps/opencs/view/world/scripterrortable.hpp index 98db425cf..33af7c864 100644 --- a/apps/opencs/view/world/scripterrortable.hpp +++ b/apps/opencs/view/world/scripterrortable.hpp @@ -44,6 +44,11 @@ namespace CSVWorld void clear(); + /// Clear local variable cache for \a script. + /// + /// \return Were there any locals that needed clearing? + bool clearLocals (const std::string& script); + private slots: void cellClicked (int row, int column); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index d405d1765..d99f789b3 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -89,6 +89,7 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: *document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts)); mColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_ScriptText); + mIdColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id); mStateColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification); QString source = mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString(); @@ -241,6 +242,15 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo ScriptEdit::ChangeLock lock (*mEditor); + bool updateRequired = false; + + for (int i=topLeft.row(); i<=bottomRight.row(); ++i) + { + std::string id = mModel->data (mModel->index (i, mIdColumn)).toString().toUtf8().constData(); + if (mErrors->clearLocals (id)) + updateRequired = true; + } + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); if (index.row()>=topLeft.row() && index.row()<=bottomRight.row()) @@ -256,13 +266,28 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo mEditor->setPlainText (source); mEditor->setTextCursor (cursor); - recompile(); + updateRequired = true; } } + + if (updateRequired) + recompile(); } void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end) { + bool updateRequired = false; + + for (int i=start; i<=end; ++i) + { + std::string id = mModel->data (mModel->index (i, mIdColumn)).toString().toUtf8().constData(); + if (mErrors->clearLocals (id)) + updateRequired = true; + } + + if (updateRequired) + recompile(); + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); if (!parent.isValid() && index.row()>=start && index.row()<=end) diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 6125dd259..907dc7958 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -38,6 +38,7 @@ namespace CSVWorld CSMDoc::Document& mDocument; CSMWorld::IdTable *mModel; int mColumn; + int mIdColumn; int mStateColumn; TableBottomBox *mBottom; RecordButtonBar *mButtons; From 12b8fcf0bfb4cd5950a1f1dd7e7be460d5f3a75a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 23 Sep 2015 23:37:09 +0200 Subject: [PATCH 418/419] OpenCS: Fix camera position retrieval in WorldspaceWidget --- apps/opencs/view/render/pagedworldspacewidget.cpp | 5 ++++- apps/opencs/view/render/unpagedworldspacewidget.cpp | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 274c77620..b0c1e74a9 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -170,7 +170,10 @@ void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() { - osg::Vec3d position = mView->getCamera()->getViewMatrix().getTrans(); + osg::Vec3d eye, center, up; + mView->getCamera()->getViewMatrixAsLookAt(eye, center, up); + osg::Vec3d position = eye; + std::ostringstream stream; stream diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index a5733ad10..3e1733c81 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -166,7 +166,9 @@ void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons ( std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction() { - osg::Vec3d position = mView->getCamera()->getViewMatrix().getTrans(); + osg::Vec3d eye, center, up; + mView->getCamera()->getViewMatrixAsLookAt(eye, center, up); + osg::Vec3d position = eye; std::ostringstream stream; From 7d4125d97ff1e79ad19f9d11f43410c50de9354c Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 24 Sep 2015 15:21:42 +0200 Subject: [PATCH 419/419] Fixes for building with unity build --- apps/openmw/CMakeLists.txt | 3 ++- apps/openmw/mwgui/dialogue.cpp | 28 ++++++++++---------- apps/openmw/mwmechanics/steering.hpp | 1 + apps/openmw/mwrender/camera.cpp | 6 ++--- apps/openmw/mwrender/globalmap.cpp | 6 ++--- apps/openmw/mwrender/localmap.cpp | 6 ++--- apps/openmw/mwrender/sky.cpp | 1 - apps/openmw/mwscript/containerextensions.cpp | 24 ++++++++--------- apps/openmw/mwscript/statsextensions.cpp | 2 +- apps/openmw/mwworld/store.cpp | 6 ++--- apps/openmw/mwworld/weather.cpp | 5 ++-- components/CMakeLists.txt | 2 +- components/files/windowspath.cpp | 2 +- components/vfs/bsaarchive.hpp | 5 ++++ 14 files changed, 50 insertions(+), 47 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 5a9b52cb2..fa05576f5 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -65,7 +65,7 @@ add_openmw_dir (mwworld containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat - esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor + store esmstore recordcmp fallback actionrepair actionsoulgem livecellref actiondoor contentloader esmloader actiontrap cellreflist cellref physicssystem weather projectilemanager ) @@ -179,4 +179,5 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) + add_definitions("-D_USE_MATH_DEFINES") endif (MSVC) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index a6000a739..d32588631 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -31,7 +31,7 @@ namespace { - MyGUI::Colour getTextColour (const std::string& type) + MyGUI::Colour getDialogueTextColour (const std::string& type) { return MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=" + type + "}")); } @@ -115,7 +115,7 @@ namespace MWGui void Response::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map& topicLinks) const { - BookTypesetter::Style* title = typesetter->createStyle("", getTextColour("header")); + BookTypesetter::Style* title = typesetter->createStyle("", getDialogueTextColour("header")); typesetter->sectionBreak(9); if (mTitle != "") typesetter->write(title, to_utf8_span(mTitle.c_str())); @@ -159,14 +159,14 @@ namespace MWGui if (hyperLinks.size() && MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation()) { - BookTypesetter::Style* style = typesetter->createStyle("", getTextColour("normal")); + BookTypesetter::Style* style = typesetter->createStyle("", getDialogueTextColour("normal")); size_t formatted = 0; // points to the first character that is not laid out yet for (std::map::iterator it = hyperLinks.begin(); it != hyperLinks.end(); ++it) { intptr_t topicId = it->second; - const MyGUI::Colour linkHot (getTextColour("link_over")); - const MyGUI::Colour linkNormal (getTextColour("link")); - const MyGUI::Colour linkActive (getTextColour("link_pressed")); + const MyGUI::Colour linkHot(getDialogueTextColour("link_over")); + const MyGUI::Colour linkNormal(getDialogueTextColour("link")); + const MyGUI::Colour linkActive(getDialogueTextColour("link_pressed")); BookTypesetter::Style* hotStyle = typesetter->createHotStyle (style, linkNormal, linkHot, linkActive, topicId); if (formatted < it->first.first) typesetter->write(style, formatted, it->first.first); @@ -199,11 +199,11 @@ namespace MWGui void Response::addTopicLink(BookTypesetter::Ptr typesetter, intptr_t topicId, size_t begin, size_t end) const { - BookTypesetter::Style* style = typesetter->createStyle("", getTextColour("normal")); + BookTypesetter::Style* style = typesetter->createStyle("", getDialogueTextColour("normal")); - const MyGUI::Colour linkHot (getTextColour("link_over")); - const MyGUI::Colour linkNormal (getTextColour("link")); - const MyGUI::Colour linkActive (getTextColour("link_pressed")); + const MyGUI::Colour linkHot(getDialogueTextColour("link_over")); + const MyGUI::Colour linkNormal(getDialogueTextColour("link")); + const MyGUI::Colour linkActive(getDialogueTextColour("link_pressed")); if (topicId) style = typesetter->createHotStyle (style, linkNormal, linkHot, linkActive, topicId); @@ -217,7 +217,7 @@ namespace MWGui void Message::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map& topicLinks) const { - BookTypesetter::Style* title = typesetter->createStyle("", getTextColour("notify")); + BookTypesetter::Style* title = typesetter->createStyle("", getDialogueTextColour("notify")); typesetter->sectionBreak(9); typesetter->write(title, to_utf8_span(mText.c_str())); } @@ -486,9 +486,9 @@ namespace MWGui typesetter->sectionBreak(9); // choices - const MyGUI::Colour linkHot (getTextColour("answer_over")); - const MyGUI::Colour linkNormal (getTextColour("answer")); - const MyGUI::Colour linkActive (getTextColour("answer_pressed")); + const MyGUI::Colour linkHot(getDialogueTextColour("answer_over")); + const MyGUI::Colour linkNormal(getDialogueTextColour("answer")); + const MyGUI::Colour linkActive(getDialogueTextColour("answer_pressed")); for (std::vector >::iterator it = mChoices.begin(); it != mChoices.end(); ++it) { Choice* link = new Choice(it->second); diff --git a/apps/openmw/mwmechanics/steering.hpp b/apps/openmw/mwmechanics/steering.hpp index 4b29dc1d9..632ab3611 100644 --- a/apps/openmw/mwmechanics/steering.hpp +++ b/apps/openmw/mwmechanics/steering.hpp @@ -1,4 +1,5 @@ #ifndef OPENMW_MECHANICS_STEERING_H +#define OPENMW_MECHANICS_STEERING_H #include diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 316c9308b..fb6573d65 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -14,10 +14,10 @@ namespace { -class UpdateCameraCallback : public osg::NodeCallback +class UpdateRenderCameraCallback : public osg::NodeCallback { public: - UpdateCameraCallback(MWRender::Camera* cam) + UpdateRenderCameraCallback(MWRender::Camera* cam) : mCamera(cam) { } @@ -67,7 +67,7 @@ namespace MWRender mMainCam.yaw = 0.f; mMainCam.offset = 400.f; - mUpdateCallback = new UpdateCameraCallback(this); + mUpdateCallback = new UpdateRenderCameraCallback(this); mCamera->addUpdateCallback(mUpdateCallback); } diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 7acda92a3..3445e4189 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -59,10 +59,10 @@ namespace } - class CameraUpdateCallback : public osg::NodeCallback + class CameraUpdateGlobalCallback : public osg::NodeCallback { public: - CameraUpdateCallback(osg::Camera* cam, MWRender::GlobalMap* parent) + CameraUpdateGlobalCallback(osg::Camera* cam, MWRender::GlobalMap* parent) : mRendered(false) , mCamera(cam) , mParent(parent) @@ -263,7 +263,7 @@ namespace MWRender else camera->setClearMask(GL_NONE); - camera->setUpdateCallback(new CameraUpdateCallback(camera, this)); + camera->setUpdateCallback(new CameraUpdateGlobalCallback(camera, this)); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); camera->attach(osg::Camera::COLOR_BUFFER, mOverlayTexture); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 02ca0cb4c..fe685f97c 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -27,10 +27,10 @@ namespace { - class CameraUpdateCallback : public osg::NodeCallback + class CameraLocalUpdateCallback : public osg::NodeCallback { public: - CameraUpdateCallback(osg::Camera* cam, MWRender::LocalMap* parent) + CameraLocalUpdateCallback(osg::Camera* cam, MWRender::LocalMap* parent) : mRendered(false) , mCamera(cam) , mParent(parent) @@ -205,7 +205,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setStateSet(stateset); camera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); camera->setViewport(0, 0, mMapResolution, mMapResolution); - camera->setUpdateCallback(new CameraUpdateCallback(camera, this)); + camera->setUpdateCallback(new CameraLocalUpdateCallback(camera, this)); return camera; } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 317f2229d..6f1b26733 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1,6 +1,5 @@ #include "sky.hpp" -#define _USE_MATH_DEFINES #include #include diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index e33c7580f..4e3e010f7 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -56,10 +56,10 @@ namespace MWScript if (count == 0) return; - if(Misc::StringUtils::ciEqual(item, "gold_005") - || Misc::StringUtils::ciEqual(item, "gold_010") - || Misc::StringUtils::ciEqual(item, "gold_025") - || Misc::StringUtils::ciEqual(item, "gold_100")) + if(::Misc::StringUtils::ciEqual(item, "gold_005") + || ::Misc::StringUtils::ciEqual(item, "gold_010") + || ::Misc::StringUtils::ciEqual(item, "gold_025") + || ::Misc::StringUtils::ciEqual(item, "gold_100")) item = "gold_001"; MWWorld::Ptr itemPtr = *ptr.getClass().getContainerStore (ptr).add (item, count, ptr); @@ -97,10 +97,10 @@ namespace MWScript std::string item = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - if(Misc::StringUtils::ciEqual(item, "gold_005") - || Misc::StringUtils::ciEqual(item, "gold_010") - || Misc::StringUtils::ciEqual(item, "gold_025") - || Misc::StringUtils::ciEqual(item, "gold_100")) + if(::Misc::StringUtils::ciEqual(item, "gold_005") + || ::Misc::StringUtils::ciEqual(item, "gold_010") + || ::Misc::StringUtils::ciEqual(item, "gold_025") + || ::Misc::StringUtils::ciEqual(item, "gold_100")) item = "gold_001"; MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); @@ -131,10 +131,10 @@ namespace MWScript if (count == 0) return; - if(Misc::StringUtils::ciEqual(item, "gold_005") - || Misc::StringUtils::ciEqual(item, "gold_010") - || Misc::StringUtils::ciEqual(item, "gold_025") - || Misc::StringUtils::ciEqual(item, "gold_100")) + if(::Misc::StringUtils::ciEqual(item, "gold_005") + || ::Misc::StringUtils::ciEqual(item, "gold_010") + || ::Misc::StringUtils::ciEqual(item, "gold_025") + || ::Misc::StringUtils::ciEqual(item, "gold_100")) item = "gold_001"; MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 4debb24fe..e4ad71875 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -228,7 +228,7 @@ namespace MWScript // workaround broken endgame scripts that kill dagoth ur if (!R::implicit && - Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "dagoth_ur_1")) + ::Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), "dagoth_ur_1")) { runtime.push (peek); diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 29187f950..b647a6c88 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -994,7 +994,7 @@ namespace MWWorld template<> - inline void Store::setUp() + void Store::setUp() { // DialInfos marked as deleted are kept during the loading phase, so that the linked list // structure is kept intact for inserting further INFOs. Delete them now that loading is done. @@ -1013,7 +1013,7 @@ namespace MWWorld } template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { + void Store::load(ESM::ESMReader &esm, const std::string &id) { std::string idLower = Misc::StringUtils::lowerCase(id); std::map::iterator it = mStatic.find(idLower); @@ -1029,7 +1029,6 @@ namespace MWWorld // Script //========================================================================= - template <> inline void Store::load(ESM::ESMReader &esm, const std::string &id) { ESM::Script scpt; scpt.load(esm); @@ -1046,7 +1045,6 @@ namespace MWWorld // StartScript //========================================================================= - template <> inline void Store::load(ESM::ESMReader &esm, const std::string &id) { ESM::StartScript s; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 78ae6fa0b..5008d8fbf 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -1,6 +1,3 @@ -#define _USE_MATH_DEFINES -#include - #include "weather.hpp" #include @@ -26,6 +23,8 @@ #include "fallback.hpp" #include "cellstore.hpp" +#include + using namespace MWWorld; namespace diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 946c3af16..00eac6ca5 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -47,7 +47,7 @@ add_component_dir (sceneutil ) add_component_dir (nif - controlled effect niftypes record controller extra node record_ptr data niffile property nifkey data node base nifstream + controlled effect niftypes record controller extra node record_ptr data niffile property nifkey base nifstream ) add_component_dir (nifosg diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index ece4049a8..4b7c6c50a 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -4,9 +4,9 @@ #include -#include #include #include +#include #include namespace bconv = boost::locale::conv; diff --git a/components/vfs/bsaarchive.hpp b/components/vfs/bsaarchive.hpp index 961746947..25ad60e0a 100644 --- a/components/vfs/bsaarchive.hpp +++ b/components/vfs/bsaarchive.hpp @@ -1,3 +1,6 @@ +#ifndef VFS_BSAARCHIVE_HPP_ +#define VFS_BSAARCHIVE_HPP_ + #include "archive.hpp" #include @@ -30,3 +33,5 @@ namespace VFS }; } + +#endif \ No newline at end of file