From 33ce03dfc597dd4d2f08356bfb0f3fbf1364eb0c Mon Sep 17 00:00:00 2001 From: Nathan Aclander Date: Sat, 24 Jan 2015 17:17:05 -0800 Subject: [PATCH 001/214] Should be compared against uint only --- components/esm/esmcommon.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index 1bdadead2f..80706793a5 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -40,8 +40,8 @@ union NAME_T } bool operator!=(const std::string &str) const { return !((*this)==str); } - bool operator==(int v) const { return v == val; } - bool operator!=(int v) const { return v != val; } + bool operator==(uint32_t v) const { return v == val; } + bool operator!=(uint32_t v) const { return v != val; } std::string toString() const { return std::string(name, strnlen(name, LEN)); } From f7f593b1436d59b41a52e6e0dbec934b9d8e92af Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 25 Jan 2015 18:30:33 +0100 Subject: [PATCH 002/214] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index d2c5cdc044..f261ea4233 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -75,6 +75,7 @@ Programmers Michał Bień (Glorf) Miroslav Puda (pakanek) MiroslavR + naclander Narmo Nathan Jeffords (blunted2night) Nikolay Kasyanov (corristo) From b0b275a936a815de94eed2ee1391df2a6062137b Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 12:53:01 +1300 Subject: [PATCH 003/214] Fix for MSVC 2013 compiler issues. Fixes: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\utility(199): error C2079: 'std::pair::second' uses undefined class 'boost::shared_ptr' Which cascades to 36 more errors. --- apps/essimporter/importer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 73a12769ab..10fad37b0e 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -1,4 +1,5 @@ #include "importer.hpp" +#include #include From e02bab67ba67dffc133f0583cc0f593709af90c5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 13:17:16 +1300 Subject: [PATCH 004/214] Fixed MSVC warnings. warning C4099: 'ESM::ESMReader' : type name first seen using 'class' now seen using 'struct' warning C4099: 'ESM::CellId' : type name first seen using 'struct' now seen using 'class' --- apps/essimporter/importacdt.hpp | 2 +- apps/essimporter/importdial.hpp | 2 +- apps/essimporter/importinfo.hpp | 2 +- apps/essimporter/importjour.hpp | 2 +- apps/essimporter/importklst.hpp | 2 +- apps/essimporter/importques.hpp | 2 +- components/esm/loadcell.hpp | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 4eb5edb73e..53783a3644 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -9,7 +9,7 @@ namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/apps/essimporter/importdial.hpp b/apps/essimporter/importdial.hpp index fe4b0c5b4c..9a1e882332 100644 --- a/apps/essimporter/importdial.hpp +++ b/apps/essimporter/importdial.hpp @@ -2,7 +2,7 @@ #define OPENMW_ESSIMPORT_IMPORTDIAL_H namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/apps/essimporter/importinfo.hpp b/apps/essimporter/importinfo.hpp index 08f588f8d8..f4d616786f 100644 --- a/apps/essimporter/importinfo.hpp +++ b/apps/essimporter/importinfo.hpp @@ -5,7 +5,7 @@ namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/apps/essimporter/importjour.hpp b/apps/essimporter/importjour.hpp index fe8775a93b..1b2d094f63 100644 --- a/apps/essimporter/importjour.hpp +++ b/apps/essimporter/importjour.hpp @@ -5,7 +5,7 @@ namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/apps/essimporter/importklst.hpp b/apps/essimporter/importklst.hpp index e333e71509..d07332600f 100644 --- a/apps/essimporter/importklst.hpp +++ b/apps/essimporter/importklst.hpp @@ -6,7 +6,7 @@ namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/apps/essimporter/importques.hpp b/apps/essimporter/importques.hpp index d7e718b928..51fe22434c 100644 --- a/apps/essimporter/importques.hpp +++ b/apps/essimporter/importques.hpp @@ -6,7 +6,7 @@ namespace ESM { - struct ESMReader; + class ESMReader; } namespace ESSImport diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index e1a6eee1ab..4c2ac68dcc 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -18,7 +18,7 @@ namespace ESM { class ESMReader; class ESMWriter; - class CellId; +struct CellId; /* Moved cell reference tracking object. This mainly stores the target cell of the reference, so we can easily know where it has been moved when another From f95743ccc3646aa22f36f250a75daeac14f0a6a6 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 13:18:21 +1300 Subject: [PATCH 005/214] Fixed MSVC warning. warning C4305: 'return' : truncation from 'double' to 'float' --- components/esm/esmreader.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index e7721bb8f5..ebbc935f6f 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -32,7 +32,7 @@ public: int getVer() const { return mHeader.mData.version; } int getRecordCount() const { return mHeader.mData.records; } - float getFVer() const { if(mHeader.mData.version == VER_12) return 1.2; else return 1.3; } + float getFVer() const { return (mHeader.mData.version == VER_12) ? 1.2f : 1.3f; } const std::string getAuthor() const { return mHeader.mData.author.toString(); } const std::string getDesc() const { return mHeader.mData.desc.toString(); } const std::vector &getGameFiles() const { return mHeader.mMaster; } From 946dd16696761a8e87565ed1bd93826b05b0e6b8 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 13:57:22 +1300 Subject: [PATCH 006/214] Fixed Windows warning. warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning) --- apps/essimporter/converter.hpp | 2 +- components/esm/loadcell.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 6f85b01cff..90b75fee1f 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -263,7 +263,7 @@ public: for (std::vector::const_iterator it = pcdt.mFactions.begin(); it != pcdt.mFactions.end(); ++it) { ESM::NpcStats::Faction faction; - faction.mExpelled = it->mFlags & 0x2; + faction.mExpelled = (it->mFlags & 0x2) != 0; faction.mRank = it->mRank; faction.mReputation = it->mReputation; mContext->mPlayer.mObject.mNpcStats.mFactions[it->mFactionName.toString()] = faction; diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 4c2ac68dcc..d982bbfd40 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -137,7 +137,7 @@ struct Cell bool hasWater() const { - return (mData.mFlags&HasWater); + return (mData.mFlags&HasWater) != 0; } // Restore the given reader to the stored position. Will try to open From 70e4f821ba394840554199f1f84066a8711e454a Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 13:58:13 +1300 Subject: [PATCH 007/214] Fix Windows warning warning C4244: 'initializing' : conversion from 'float' to 'int', possible loss of data --- 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 10fad37b0e..8f6563dee6 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -342,8 +342,8 @@ namespace ESSImport { // exterior cell -> determine cell coordinates based on position const int cellSize = 8192; - int cellX = std::floor(context.mPlayer.mObject.mPosition.pos[0]/cellSize); - int cellY = std::floor(context.mPlayer.mObject.mPosition.pos[1]/cellSize); + int cellX = static_cast(std::floor(context.mPlayer.mObject.mPosition.pos[0]/cellSize)); + int cellY = static_cast(std::floor(context.mPlayer.mObject.mPosition.pos[1] / cellSize)); context.mPlayer.mCellId.mIndex.mX = cellX; context.mPlayer.mCellId.mIndex.mY = cellY; } From 1410819e20308b09bdab02c04308ea12c1fdfcb6 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sun, 25 Jan 2015 22:23:38 -0600 Subject: [PATCH 008/214] Dialog fix for line breaks in the middle of words. Issue 1049 Adjust the TypesetBookImpl::Typesetter to not assume a word break at the end of write() calls. A word break is assumed if any of the other content insertion methods are used (section break, add/select content, etc). --- apps/openmw/mwgui/bookpage.cpp | 88 ++++++++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 3b1d40fc39..c9cfc8c2c1 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -195,8 +195,20 @@ struct TypesetBookImpl : TypesetBook struct TypesetBookImpl::Typesetter : BookTypesetter { + struct PartialText { + StyleImpl *mStyle; + Utf8Stream::Point mBegin; + Utf8Stream::Point mEnd; + int mWidth; + + PartialText( StyleImpl *style, Utf8Stream::Point begin, Utf8Stream::Point end, int width) : + mStyle(style), mBegin(begin), mEnd(end), mWidth(width) + {} + }; + typedef TypesetBookImpl Book; typedef boost::shared_ptr BookPtr; + typedef std::vector::const_iterator PartialTextConstIterator; int mPageWidth; int mPageHeight; @@ -207,6 +219,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter Run * mRun; std::vector mSectionAlignment; + std::vector mPartialWhitespace; + std::vector mPartialWord; Book::Content const * mCurrentContent; Alignment mCurrentAlignment; @@ -273,6 +287,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter intptr_t addContent (Utf8Span text, bool select) { + add_partial_text(); + Contents::iterator i = mBook->mContents.insert (mBook->mContents.end (), Content (text.first, text.second)); if (select) @@ -283,6 +299,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter void selectContent (intptr_t contentHandle) { + add_partial_text(); + mCurrentContent = reinterpret_cast (contentHandle); } @@ -302,12 +320,16 @@ struct TypesetBookImpl::Typesetter : BookTypesetter { assert (margin == 0); //TODO: figure out proper behavior here... + add_partial_text(); + mRun = NULL; mLine = NULL; } void sectionBreak (float margin) { + add_partial_text(); + if (mBook->mSections.size () > 0) { mRun = NULL; @@ -321,6 +343,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter void setSectionAlignment (Alignment sectionAlignment) { + add_partial_text(); + if (mSection != NULL) mSectionAlignment.back () = sectionAlignment; mCurrentAlignment = sectionAlignment; @@ -331,6 +355,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter int curPageStart = 0; int curPageStop = 0; + add_partial_text(); + std::vector ::iterator sa = mSectionAlignment.begin (); for (Sections::iterator i = mBook->mSections.begin (); i != mBook->mSections.end (); ++i, ++sa) { @@ -415,23 +441,23 @@ struct TypesetBookImpl::Typesetter : BookTypesetter void writeImpl (StyleImpl * style, Utf8Stream::Point _begin, Utf8Stream::Point _end) { - int line_height = style->mFont->getDefaultHeight (); - Utf8Stream stream (_begin, _end); while (!stream.eof ()) { if (ucsLineBreak (stream.peek ())) { + add_partial_text(); stream.consume (); mLine = NULL, mRun = NULL; continue; } + if (ucsBreakingSpace (stream.peek ()) && !mPartialWord.empty()) + add_partial_text(); + int word_width = 0; - int word_height = 0; int space_width = 0; - int character_count = 0; Utf8Stream::Point lead = stream.current (); @@ -450,8 +476,6 @@ struct TypesetBookImpl::Typesetter : BookTypesetter MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ()); if (gi) word_width += gi->advance + gi->bearingX; - word_height = line_height; - ++character_count; stream.consume (); } @@ -460,21 +484,57 @@ struct TypesetBookImpl::Typesetter : BookTypesetter if (lead == extent) break; - int left = mLine ? mLine->mRect.right : 0; + if ( lead != origin ) + mPartialWhitespace.push_back (PartialText (style, lead, origin, space_width)); + if ( origin != extent ) + mPartialWord.push_back (PartialText (style, origin, extent, word_width)); + } + } - if (left + space_width + word_width > mPageWidth) - { - mLine = NULL, mRun = NULL; + void add_partial_text () + { + if (mPartialWhitespace.empty() && mPartialWord.empty()) + return; - append_run (style, origin, extent, extent - origin, word_width, mBook->mRect.bottom + word_height); - } - else + int space_width = 0; + int word_width = 0; + + for (PartialTextConstIterator i = mPartialWhitespace.begin (); i != mPartialWhitespace.end (); ++i) + space_width += i->mWidth; + for (PartialTextConstIterator i = mPartialWord.begin (); i != mPartialWord.end (); ++i) + word_width += i->mWidth; + + int left = mLine ? mLine->mRect.right : 0; + + if (left + space_width + word_width > mPageWidth) + { + mLine = NULL, mRun = NULL, left = 0; + } + else + { + for (PartialTextConstIterator i = mPartialWhitespace.begin (); i != mPartialWhitespace.end (); ++i) { int top = mLine ? mLine->mRect.top : mBook->mRect.bottom; + int line_height = i->mStyle->mFont->getDefaultHeight (); - append_run (style, lead, extent, extent - origin, left + space_width + word_width, top + word_height); + append_run ( i->mStyle, i->mBegin, i->mEnd, 0, left + i->mWidth, top + line_height); + + left = mLine->mRect.right; } } + + for (PartialTextConstIterator i = mPartialWord.begin (); i != mPartialWord.end (); ++i) + { + int top = mLine ? mLine->mRect.top : mBook->mRect.bottom; + int line_height = i->mStyle->mFont->getDefaultHeight (); + + append_run (i->mStyle, i->mBegin, i->mEnd, i->mEnd - i->mBegin, left + i->mWidth, top + line_height); + + left = mLine->mRect.right; + } + + mPartialWhitespace.clear(); + mPartialWord.clear(); } void append_run (StyleImpl * style, Utf8Stream::Point begin, Utf8Stream::Point end, int pc, int right, int bottom) From e298589e7fc3641abd5a20b2da3fd6400d272d5c Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 26 Jan 2015 18:46:18 +1300 Subject: [PATCH 009/214] Reorganised DataFilesPage.cpp code. Removed some recursive calling of saveSettings() and loadSettings(). --- apps/launcher/datafilespage.cpp | 48 +++++++++++++++------------------ apps/launcher/datafilespage.hpp | 1 + 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 2456654213..ff1364b08c 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -69,19 +69,6 @@ void Launcher::DataFilesPage::buildView() bool Launcher::DataFilesPage::loadSettings() { - QStringList paths = mGameSettings.getDataDirs(); - - foreach (const QString &path, paths) - mSelector->addFiles(path); - - mDataLocal = mGameSettings.getDataLocal(); - - if (!mDataLocal.isEmpty()) - mSelector->addFiles(mDataLocal); - - paths.insert (0, mDataLocal); - PathIterator pathIterator (paths); - QStringList profiles = mLauncherSettings.getContentLists(); QString currentProfile = mLauncherSettings.getCurrentContentListName(); @@ -94,11 +81,27 @@ bool Launcher::DataFilesPage::loadSettings() if (!currentProfile.isEmpty()) addProfile(currentProfile, true); - mSelector->setProfileContent(filesInProfile(currentProfile, pathIterator)); - return true; } +void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName) +{ + QStringList paths = mGameSettings.getDataDirs(); + + foreach(const QString &path, paths) + mSelector->addFiles(path); + + mDataLocal = mGameSettings.getDataLocal(); + + if (!mDataLocal.isEmpty()) + mSelector->addFiles(mDataLocal); + + paths.insert(0, mDataLocal); + PathIterator pathIterator(paths); + + mSelector->setProfileContent(filesInProfile(contentModelName, pathIterator)); +} + QStringList Launcher::DataFilesPage::filesInProfile(const QString& profileName, PathIterator& pathIterator) { QStringList files = mLauncherSettings.getContentListFiles(profileName); @@ -175,7 +178,7 @@ void Launcher::DataFilesPage::setProfile (const QString &previous, const QString ui.profilesComboBox->setCurrentProfile (ui.profilesComboBox->findText (current)); - loadSettings(); + populateFileViews(current); checkForDefaultProfile(); } @@ -229,13 +232,6 @@ void Launcher::DataFilesPage::on_newProfileAction_triggered() mLauncherSettings.setCurrentContentListName(profile); addProfile(profile, true); - mSelector->clearCheckStates(); - - mSelector->setGameFile(); - - saveSettings(); - - emit signalProfileChanged (ui.profilesComboBox->findText(profile)); } void Launcher::DataFilesPage::addProfile (const QString &profile, bool setAsCurrent) @@ -262,15 +258,13 @@ void Launcher::DataFilesPage::on_deleteProfileAction_triggered() // this should work since the Default profile can't be deleted and is always index 0 int next = ui.profilesComboBox->currentIndex()-1; + + // changing the profile forces a reload of plugin file views. ui.profilesComboBox->setCurrentIndex(next); removeProfile(profile); ui.profilesComboBox->removeItem(ui.profilesComboBox->findText(profile)); - saveSettings(); - - loadSettings(); - checkForDefaultProfile(); } diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index c2fc224614..73b840c5c8 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -82,6 +82,7 @@ namespace Launcher bool showDeleteMessageBox (const QString &text); void addProfile (const QString &profile, bool setAsCurrent); void checkForDefaultProfile(); + void populateFileViews(const QString& contentModelName); class PathIterator { From 697ab16ec5b3ed0502e47b71ea7aa7a883320bd8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 27 Jan 2015 19:00:26 +0100 Subject: [PATCH 010/214] Fix for coverity defects --- apps/openmw/mwdialogue/keywordsearch.hpp | 2 +- apps/openmw/mwworld/esmstore.cpp | 2 +- apps/wizard/unshield/unshieldworker.cpp | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwdialogue/keywordsearch.hpp b/apps/openmw/mwdialogue/keywordsearch.hpp index 0bb3616d9f..c4e1d75538 100644 --- a/apps/openmw/mwdialogue/keywordsearch.hpp +++ b/apps/openmw/mwdialogue/keywordsearch.hpp @@ -161,7 +161,7 @@ public: while (matches.size()) { int longestKeywordSize = 0; - typename std::vector::iterator longestKeyword; + typename std::vector::iterator longestKeyword = matches.begin(); for (typename std::vector::iterator it = matches.begin(); it != matches.end(); ++it) { int size = it->mEnd - it->mBeg; diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index caa88d751c..12e02f9383 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -82,7 +82,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) } else if (n.val == ESM::REC_SKIL) { mSkills.load (esm); } - else if (n.val==ESM::REC_FILT || ESM::REC_DBGP) + else if (n.val==ESM::REC_FILT || n.val == ESM::REC_DBGP) { // ignore project file only records esm.skipRecord(); diff --git a/apps/wizard/unshield/unshieldworker.cpp b/apps/wizard/unshield/unshieldworker.cpp index 5fa0433476..11e090ed18 100644 --- a/apps/wizard/unshield/unshieldworker.cpp +++ b/apps/wizard/unshield/unshieldworker.cpp @@ -739,7 +739,8 @@ bool Wizard::UnshieldWorker::extractFile(Unshield *unshield, const QString &dest // Ensure the target path exists QDir dir; - dir.mkpath(path); + if (!dir.mkpath(path)) + return false; QString fileName(path); fileName.append(QString::fromUtf8(unshield_file_name(unshield, index))); From 62acb0373519d310799967ce7b0f556e27ddd1c4 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 27 Jan 2015 21:07:26 +0100 Subject: [PATCH 011/214] More Ogre + recent Boost build fixes --- apps/opencs/view/render/cell.hpp | 2 ++ apps/opencs/view/render/object.hpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 9f38b0d9f3..73d7949482 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -9,7 +9,9 @@ #include +#ifndef Q_MOC_RUN #include +#endif #include "object.hpp" diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 05a32fbeab..3ed4fa793f 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -3,7 +3,9 @@ #include +#ifndef Q_MOC_RUN #include +#endif class QModelIndex; From 9b3728d87856d1c515882c8ccd6bd08e6a96e5d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 17:15:25 +0100 Subject: [PATCH 012/214] ESSImport: convert weather state --- apps/essimporter/converter.hpp | 63 +++++++++++++++++++++++++++++++-- apps/essimporter/importgame.cpp | 3 ++ apps/essimporter/importgame.hpp | 2 +- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 90b75fee1f..28d904d3c9 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "importcrec.hpp" #include "importcntc.hpp" @@ -455,11 +456,69 @@ public: 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) { - GAME game; - game.load(esm); + mGame.load(esm); + mHasGame = true; } + + 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.015*24*3600); + weather.mHour = mContext->mHour; + weather.mWindSpeed = 0.f; + weather.mTimePassed = 0.0; + weather.mFirstUpdate = false; + weather.save(esm); + esm.endRecord(ESM::REC_WTHR); + } + +private: + bool mHasGame; + GAME mGame; }; /// Running global script diff --git a/apps/essimporter/importgame.cpp b/apps/essimporter/importgame.cpp index 0b3a4f1a7f..c9da71e0c3 100644 --- a/apps/essimporter/importgame.cpp +++ b/apps/essimporter/importgame.cpp @@ -8,6 +8,9 @@ namespace ESSImport void GAME::load(ESM::ESMReader &esm) { esm.getHNT(mGMDT, "GMDT"); + mGMDT.mWeatherTransition &= (0x000000ff); + mGMDT.mSecundaPhase &= (0x000000ff); + mGMDT.mMasserPhase &= (0x000000ff); } } diff --git a/apps/essimporter/importgame.hpp b/apps/essimporter/importgame.hpp index 7bb8143207..fca7d72a0a 100644 --- a/apps/essimporter/importgame.hpp +++ b/apps/essimporter/importgame.hpp @@ -20,7 +20,7 @@ namespace ESSImport int mCurrentWeather, mNextWeather; int mWeatherTransition; // 0-100 transition between weathers, top 3 bytes may be garbage float mTimeOfNextTransition; // weather changes when gamehour == timeOfNextTransition - int masserPhase, secundaPhase; // top 3 bytes may be garbage + int mMasserPhase, mSecundaPhase; // top 3 bytes may be garbage }; GMDT mGMDT; From 60f722b0a9bca552475e2d721c23287e5457994a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 17:28:05 +0100 Subject: [PATCH 013/214] Treat the first mouse motion event as non-relative This fixes incorrect starting camera orientation when using --skip-menu or --load-savegame. --- extern/sdl4ogre/sdlinputwrapper.cpp | 10 +++++++++- extern/sdl4ogre/sdlinputwrapper.hpp | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 0c29be9395..a6c7d3e5ca 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -30,7 +30,8 @@ namespace SFO mWantMouseVisible(false), mAllowGrab(grab), mWarpX(0), - mWarpY(0) + mWarpY(0), + mFirstMouseMove(true) { _setupOISKeys(); } @@ -316,6 +317,13 @@ namespace SFO pack_evt.y = mMouseY = evt.motion.y; pack_evt.xrel = evt.motion.xrel; pack_evt.yrel = evt.motion.yrel; + if (mFirstMouseMove) + { + // first event should be treated as non-relative, since there's no point of reference + // SDL then (incorrectly) uses (0,0) as point of reference, on Linux at least... + pack_evt.xrel = pack_evt.yrel = 0; + mFirstMouseMove = false; + } } else if(evt.type == SDL_MOUSEWHEEL) { diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index 339e99de14..af16ab68d8 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -71,6 +71,8 @@ namespace SFO bool mGrabPointer; bool mMouseRelative; + bool mFirstMouseMove; + Sint32 mMouseZ; Sint32 mMouseX; Sint32 mMouseY; From 4921c6ef9eb5b0ee52097cd6bca40b3a0634d391 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 24 Jan 2015 19:26:31 +0100 Subject: [PATCH 014/214] Split window caption bars so that the caption can be transparent (Fixes #531) Fix transparent window background not applying to the header bar (Fixes #2294) --- apps/openmw/mwgui/container.cpp | 2 - apps/openmw/mwgui/statswindow.cpp | 1 - apps/openmw/mwgui/tradewindow.cpp | 2 - components/CMakeLists.txt | 2 +- components/widgets/widgets.cpp | 2 + components/widgets/windowcaption.cpp | 58 ++++++++++++++++++++++++++++ components/widgets/windowcaption.hpp | 32 +++++++++++++++ files/mygui/openmw_hud_box.skin.xml | 16 ++++---- files/mygui/openmw_windows.skin.xml | 37 ++++++------------ libs/openengine/gui/layout.cpp | 22 ----------- libs/openengine/gui/layout.hpp | 4 -- 11 files changed, 112 insertions(+), 66 deletions(-) create mode 100644 components/widgets/windowcaption.cpp create mode 100644 components/widgets/windowcaption.hpp diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 49e641aedc..53b1e679a0 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -154,8 +154,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); - // Careful here. setTitle may cause size updates, causing itemview redraw, so make sure to do it last - // or we end up using a possibly invalid model. setTitle(container.getClass().getName(container)); } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 19f9c749c8..a407aedc72 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -108,7 +108,6 @@ namespace MWGui void StatsWindow::setPlayerName(const std::string& playerName) { mMainWidget->castType()->setCaption(playerName); - adjustWindowCaption(); } void StatsWindow::setValue (const std::string& id, const MWMechanics::AttributeValue& value) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index bafa89d5b1..fab7c63a6c 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -133,8 +133,6 @@ namespace MWGui updateLabels(); - // Careful here. setTitle may cause size updates, causing itemview redraw, so make sure to do it last - // or we end up using a possibly invalid model. setTitle(actor.getClass().getName(actor)); onFilterChanged(mFilterAll); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a0500127c9..2126c5ca54 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -113,7 +113,7 @@ add_component_dir (ogreinit ) add_component_dir (widgets - box imagebutton tags list numericeditbox sharedstatebutton widgets + box imagebutton tags list numericeditbox sharedstatebutton windowcaption widgets ) add_component_dir (fontloader diff --git a/components/widgets/widgets.cpp b/components/widgets/widgets.cpp index 82839c6c96..3b6361cf88 100644 --- a/components/widgets/widgets.cpp +++ b/components/widgets/widgets.cpp @@ -7,6 +7,7 @@ #include "box.hpp" #include "imagebutton.hpp" #include "sharedstatebutton.hpp" +#include "windowcaption.hpp" namespace Gui { @@ -22,6 +23,7 @@ namespace Gui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); } } diff --git a/components/widgets/windowcaption.cpp b/components/widgets/windowcaption.cpp new file mode 100644 index 0000000000..bcb0a7c125 --- /dev/null +++ b/components/widgets/windowcaption.cpp @@ -0,0 +1,58 @@ +#include "windowcaption.hpp" + +#include + +namespace Gui +{ + + WindowCaption::WindowCaption() + : mLeft(NULL) + , mRight(NULL) + { + } + + void WindowCaption::initialiseOverride() + { + Base::initialiseOverride(); + + assignWidget(mLeft, "Left"); + assignWidget(mRight, "Right"); + + assignWidget(mClient, "Client"); + if (!mClient) + throw std::runtime_error("WindowCaption needs an EditBox Client widget in its skin"); + } + + void WindowCaption::setCaption(const MyGUI::UString &_value) + { + EditBox::setCaption(_value); + align(); + } + + void WindowCaption::setSize(const MyGUI::IntSize& _value) + { + Base::setSize(_value); + align(); + } + + void WindowCaption::setCoord(const MyGUI::IntCoord& _value) + { + Base::setCoord(_value); + align(); + } + + void WindowCaption::align() + { + MyGUI::IntSize textSize = getTextSize(); + MyGUI::Widget* caption = mClient; + caption->setSize(textSize.width + 24, caption->getHeight()); + + int barwidth = (getWidth()-caption->getWidth())/2; + caption->setPosition(barwidth, caption->getTop()); + if (mLeft) + mLeft->setCoord(0, mLeft->getTop(), barwidth, mLeft->getHeight()); + if (mRight) + mRight->setCoord(barwidth + caption->getWidth(), mRight->getTop(), barwidth, mRight->getHeight()); + } + +} diff --git a/components/widgets/windowcaption.hpp b/components/widgets/windowcaption.hpp new file mode 100644 index 0000000000..bdd4c0a2e2 --- /dev/null +++ b/components/widgets/windowcaption.hpp @@ -0,0 +1,32 @@ +#ifndef OPENMW_WIDGETS_WINDOWCAPTION_H +#define OPENMW_WIDGETS_WINDOWCAPTION_H + +#include + +namespace Gui +{ + + /// Window caption that automatically adjusts "Left" and "Right" widgets in its skin + /// based on the text size of the caption in the middle + class WindowCaption : public MyGUI::EditBox + { + MYGUI_RTTI_DERIVED(WindowCaption) + public: + WindowCaption(); + + virtual void setCaption(const MyGUI::UString &_value); + virtual void initialiseOverride(); + + virtual void setSize(const MyGUI::IntSize& _value); + virtual void setCoord(const MyGUI::IntCoord& _value); + + private: + MyGUI::Widget* mLeft; + MyGUI::Widget* mRight; + + void align(); + }; + +} + +#endif diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index e7457e7d29..4e63497680 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -6,14 +6,14 @@ + + + + - - - - @@ -22,14 +22,14 @@ + + + + - - - - diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index d01bd8ef20..57d50fe744 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -395,17 +395,9 @@ - - - - - - - - - - - + + + @@ -538,12 +531,7 @@ - - - - - - + @@ -695,7 +684,8 @@ - + + @@ -814,12 +804,7 @@ - - - - - - + - + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index ebbc77bef6..2854401c89 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -804,7 +804,7 @@ - + + diff --git a/files/mygui/openmw_trainingwindow.layout b/files/mygui/openmw_trainingwindow.layout index c58bd0ab3a..d6cea8727b 100644 --- a/files/mygui/openmw_trainingwindow.layout +++ b/files/mygui/openmw_trainingwindow.layout @@ -1,26 +1,22 @@ - + + + + - - - - - + + - - - - - + - + diff --git a/files/mygui/openmw_travel_window.layout b/files/mygui/openmw_travel_window.layout index 30b470e08d..4b383ee7c4 100644 --- a/files/mygui/openmw_travel_window.layout +++ b/files/mygui/openmw_travel_window.layout @@ -1,31 +1,28 @@ - + + + - - - + + - - - - + - - - + + + - - - + + - + From 0557d45bd156844772a5be5cdc602cdf22781eb5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Feb 2015 13:18:03 +0100 Subject: [PATCH 080/214] renamed opencs into openmw-cs --- CMakeLists.txt | 14 +++++++------- apps/opencs/CMakeLists.txt | 14 +++++++------- apps/opencs/editor.cpp | 4 ++-- apps/opencs/main.cpp | 2 +- files/mac/{opencs.icns => openmw-cs.icns} | Bin files/opencs/{opencs.png => openmw-cs.png} | Bin files/opencs/resources.qrc | 2 +- files/{opencs.desktop => openmw-cs.desktop} | 6 +++--- files/windows/opencs.rc | 2 +- files/windows/{opencs.ico => openmw-cs.ico} | Bin 10 files changed, 22 insertions(+), 22 deletions(-) rename files/mac/{opencs.icns => openmw-cs.icns} (100%) rename files/opencs/{opencs.png => openmw-cs.png} (100%) rename files/{opencs.desktop => openmw-cs.desktop} (83%) rename files/windows/{opencs.ico => openmw-cs.ico} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index f316034606..019d53c4e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -373,8 +373,8 @@ if (NOT WIN32 AND NOT APPLE) "${OpenMW_BINARY_DIR}/openmw.desktop") configure_file(${OpenMW_SOURCE_DIR}/files/openmw-mimeinfo.xml "${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml") - configure_file(${OpenMW_SOURCE_DIR}/files/opencs.desktop - "${OpenMW_BINARY_DIR}/opencs.desktop") + configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.desktop + "${OpenMW_BINARY_DIR}/openmw-cs.desktop") endif() # Compiler settings @@ -423,7 +423,7 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-essimporter" DESTINATION "${BINDIR}" ) ENDIF(BUILD_ESSIMPORTER) IF(BUILD_OPENCS) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" ) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-cs" DESTINATION "${BINDIR}" ) ENDIF(BUILD_OPENCS) IF(BUILD_NIFTEST) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" ) @@ -444,8 +444,8 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml" DESTINATION "${DATAROOTDIR}/mime/packages" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") IF(BUILD_OPENCS) - INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") - INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/opencs.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") ENDIF(BUILD_OPENCS) # Install global configuration files @@ -485,7 +485,7 @@ if(WIN32) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-essimporter.exe" DESTINATION ".") ENDIF(BUILD_ESSIMPORTER) IF(BUILD_OPENCS) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/opencs.exe" DESTINATION ".") + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-cs.exe" DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION ".") ENDIF(BUILD_OPENCS) IF(BUILD_WIZARD) @@ -509,7 +509,7 @@ if(WIN32) SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-launcher;OpenMW Launcher") ENDIF(BUILD_LAUNCHER) IF(BUILD_OPENCS) - SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};opencs;OpenMW Construction Set") + SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-cs;OpenMW Construction Set") ENDIF(BUILD_OPENCS) IF(BUILD_WIZARD) SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-wizard;OpenMW Wizard") diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 468e172cd2..be30431dfa 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -146,7 +146,7 @@ set (OPENCS_UI ${CMAKE_SOURCE_DIR}/files/ui/filedialog.ui ) -source_group (opencs FILES ${OPENCS_SRC} ${OPENCS_HDR}) +source_group (openmw-cs FILES ${OPENCS_SRC} ${OPENCS_HDR}) if(WIN32) set(QT_USE_QTMAIN TRUE) @@ -169,12 +169,12 @@ qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) include_directories(${CMAKE_CURRENT_BINARY_DIR} ${BULLET_INCLUDE_DIRS}) if(APPLE) - set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/opencs.icns) + set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns) else() set (OPENCS_MAC_ICON "") endif(APPLE) -add_executable(opencs +add_executable(openmw-cs MACOSX_BUNDLE ${OENGINE_BULLET} ${OPENCS_SRC} @@ -187,8 +187,8 @@ add_executable(opencs if(APPLE) set_target_properties(opencs PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}" - OUTPUT_NAME "OpenCS" - MACOSX_BUNDLE_ICON_FILE "opencs.icns" + OUTPUT_NAME "OpenMW-CS" + MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns" MACOSX_BUNDLE_BUNDLE_NAME "OpenCS" MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs" MACOSX_BUNDLE_SHORT_VERSION_STRING ${OPENMW_VERSION} @@ -199,7 +199,7 @@ if(APPLE) MACOSX_PACKAGE_LOCATION Resources) endif(APPLE) -target_link_libraries(opencs +target_link_libraries(openmw-cs ${OGRE_LIBRARIES} ${OGRE_Overlay_LIBRARIES} ${OGRE_STATIC_PLUGINS} @@ -211,5 +211,5 @@ target_link_libraries(opencs ) if(APPLE) - INSTALL(TARGETS opencs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE) + INSTALL(TARGETS opencs BUNDLE DESTINATION OpenMW-CS COMPONENT BUNDLE) endif() diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 58614ec5f6..1d31c83969 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -96,7 +96,7 @@ void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs) std::pair > CS::Editor::readConfig() { boost::program_options::variables_map variables; - boost::program_options::options_description desc("Syntax: opencs \nAllowed options"); + boost::program_options::options_description desc("Syntax: openmw-cs \nAllowed options"); desc.add_options() ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()->composing()) @@ -249,7 +249,7 @@ bool CS::Editor::makeIPCServer() try { mPid = boost::filesystem::temp_directory_path(); - mPid /= "opencs.pid"; + mPid /= "openmw-cs.pid"; bool pidExists = boost::filesystem::exists(mPid); mPidFile.open(mPid); diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index 0b8da61efe..b11561c135 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -78,7 +78,7 @@ int main(int argc, char *argv[]) application.setLibraryPaths(libraryPaths); #endif - application.setWindowIcon (QIcon (":./opencs.png")); + application.setWindowIcon (QIcon (":./openmw-cs.png")); CS::Editor editor (ogreInit); diff --git a/files/mac/opencs.icns b/files/mac/openmw-cs.icns similarity index 100% rename from files/mac/opencs.icns rename to files/mac/openmw-cs.icns diff --git a/files/opencs/opencs.png b/files/opencs/openmw-cs.png similarity index 100% rename from files/opencs/opencs.png rename to files/opencs/openmw-cs.png diff --git a/files/opencs/resources.qrc b/files/opencs/resources.qrc index 0cc6996a8f..1bcd3ab4f2 100644 --- a/files/opencs/resources.qrc +++ b/files/opencs/resources.qrc @@ -1,6 +1,6 @@ - opencs.png + openmw-cs.png activator.png added.png apparatus.png diff --git a/files/opencs.desktop b/files/openmw-cs.desktop similarity index 83% rename from files/opencs.desktop rename to files/openmw-cs.desktop index 638de6ebf4..a5e3c27f2a 100644 --- a/files/opencs.desktop +++ b/files/openmw-cs.desktop @@ -4,7 +4,7 @@ Name=OpenMW Content Editor GenericName=Content Editor Comment=A replacement for the Morrowind Construction Set. Keywords=Morrowind;Construction Set;Creation Kit Editor;Set;Kit; -TryExec=opencs -Exec=opencs -Icon=opencs +TryExec=openmw-cs +Exec=openmw-cs +Icon=openmw-cs Categories=Game;RolePlaying; diff --git a/files/windows/opencs.rc b/files/windows/opencs.rc index 8839f18613..3ae18dddd8 100644 --- a/files/windows/opencs.rc +++ b/files/windows/opencs.rc @@ -1 +1 @@ -IDI_ICON1 ICON DISCARDABLE "opencs.ico" +IDI_ICON1 ICON DISCARDABLE "openmw-cs.ico" diff --git a/files/windows/opencs.ico b/files/windows/openmw-cs.ico similarity index 100% rename from files/windows/opencs.ico rename to files/windows/openmw-cs.ico From c02537c3b16c55fb889824595eb4bc9912f578f2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Feb 2015 13:42:47 +0100 Subject: [PATCH 081/214] incremented version number --- CMakeLists.txt | 2 +- README.md | 44 ++++++++++++++++++++++---------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 019d53c4e7..8fe213b49a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) -set(OPENMW_VERSION_MINOR 34) +set(OPENMW_VERSION_MINOR 35) set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_COMMITHASH "") diff --git a/README.md b/README.md index e177847521..1698a7ebc3 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.34.0 +* Version: 0.35.0 * License: GPL (see docs/license/GPL3.txt for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net @@ -39,26 +39,26 @@ Command line options --version print version information and quit --data arg (=data) set data directories (later directories have higher priority) - --data-local arg set local data directory (highest + --data-local arg set local data directory (highest priority) --fallback-archive arg (=fallback-archive) - set fallback BSA archives (later + set fallback BSA archives (later archives have higher priority) --resources arg (=resources) set resources directory --start arg set initial cell - --content arg content file(s): esm/esp, or + --content arg content file(s): esm/esp, or omwgame/omwaddon --no-sound [=arg(=1)] (=0) disable all sounds --script-verbose [=arg(=1)] (=0) verbose script output --script-all [=arg(=1)] (=0) compile all scripts (excluding dialogue scripts) at startup --script-all-dialogue [=arg(=1)] (=0) compile all dialogue scripts at startup - --script-console [=arg(=1)] (=0) enable console-only script + --script-console [=arg(=1)] (=0) enable console-only script functionality - --script-run arg select a file containing a list of - console commands that is executed on + --script-run arg select a file containing a list of + console commands that is executed on startup - --script-warn [=arg(=1)] (=1) handling of warnings when compiling + --script-warn [=arg(=1)] (=1) handling of warnings when compiling scripts 0 - ignore warning 1 - show warning but consider script as @@ -70,27 +70,27 @@ Command line options enable script blacklisting --load-savegame arg load a save game file on game startup --skip-menu [=arg(=1)] (=0) skip main menu on game startup - --new-game [=arg(=1)] (=0) run new game sequence (ignored if + --new-game [=arg(=1)] (=0) run new game sequence (ignored if skip-menu=0) - --fs-strict [=arg(=1)] (=0) strict file system handling (no case + --fs-strict [=arg(=1)] (=0) strict file system handling (no case folding) - --encoding arg (=win1252) Character encoding used in OpenMW game + --encoding arg (=win1252) Character encoding used in OpenMW game messages: - - win1250 - Central and Eastern European - such as Polish, Czech, Slovak, - Hungarian, Slovene, Bosnian, Croatian, - Serbian (Latin script), Romanian and + + win1250 - Central and Eastern European + such as Polish, Czech, Slovak, + Hungarian, Slovene, Bosnian, Croatian, + Serbian (Latin script), Romanian and Albanian languages - - win1251 - Cyrillic alphabet such as - Russian, Bulgarian, Serbian Cyrillic + + win1251 - Cyrillic alphabet such as + Russian, Bulgarian, Serbian Cyrillic and other languages - - win1252 - Western European (Latin) + + win1252 - Western European (Latin) alphabet, used by default --fallback arg fallback values --no-grab Don't grab mouse cursor - --export-fonts [=arg(=1)] (=0) Export Morrowind .fnt fonts to PNG + --export-fonts [=arg(=1)] (=0) Export Morrowind .fnt fonts to PNG image and XML file in current directory --activate-dist arg (=-1) activation distance override From 0b7b62744368a42a32f889ef6408dd1bdd283b04 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 13:57:40 +0100 Subject: [PATCH 082/214] CMake fix for opencs rename --- apps/opencs/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index be30431dfa..e713c65bc6 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -185,7 +185,7 @@ add_executable(openmw-cs ) if(APPLE) - set_target_properties(opencs PROPERTIES + set_target_properties(openmw-cs PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}" OUTPUT_NAME "OpenMW-CS" MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns" @@ -211,5 +211,5 @@ target_link_libraries(openmw-cs ) if(APPLE) - INSTALL(TARGETS opencs BUNDLE DESTINATION OpenMW-CS COMPONENT BUNDLE) + INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW-CS COMPONENT BUNDLE) endif() From 9cfaffc7cc6db0e68f90c606ea3b07caa002a1d8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 3 Feb 2015 14:12:30 +0100 Subject: [PATCH 083/214] updated changelog --- CHANGELOG.md | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 750cb5476f..c2aa03dc2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,127 @@ +0.35.0 +------ + + Bug #244: Clipping/static in relation to the ghostgate/fence sound. + Bug #531: Missing transparent menu items + Bug #811: Content Lists in openmw.cfg are overwritten + Bug #925: OpenCS doesn't launch because it thinks its already started + Bug #969: Water shader strange behaviour on AMD card + Bug #1049: Partially highlighted word in dialogue may cause incorrect line break + Bug #1069: omwlauncher.exe crashes due to file lock + Bug #1192: It is possible to jump on top of hostile creatures in combat + Bug #1342: Loud ambient sounds + Bug #1431: Creatures can climb the player + Bug #1605: Guard in CharGen doesn't turn around to face you when reaching stairs + Bug #1624: Moon edges don't transition properly + Bug #1634: Items dropped by PC have collision + Bug #1637: Weird NPC behaviour in Vivec, Hlaalu Ancestral Vaults? + Bug #1638: Cannot climb staircases + Bug #1648: Enchanted equipment badly handled at game reload + Bug #1663: Crash when casting spell at enemy near you + Bug #1683: Scale doesn't apply to animated collision nodes + Bug #1702: Active enchanted item forgotten + Bug #1730: Scripts names starting with digit(s) fail to compile + Bug #1743: Moons are transparent + Bug #1745: Shadows crash: Assertion `mEffects.empty()' failed. + Bug #1785: Can't equip two-handed weapon and shield + Bug #1809: Player falls too easily + Bug #1825: Sword of Perithia can´t run in OpenMW + Bug #1899: The launcher resets any alterations you´ve made in the mod list order, + Bug #1964: Idle voices/dialogs not triggered correctly + Bug #1980: Please, change default click behavior in OpenMW Launchers Data Files list + Bug #1984: Vampire corpses standing up when looting the first item + Bug #1985: Calm spell does nothing + Bug #1986: Spell name lights up on mouseover but spell cost does not + Bug #1989: Tooltip still shown when menu toggled off + Bug #2010: Raindrops Displayed While Underwater + Bug #2023: Walking into plants causes massive framedrop + Bug #2031: [MOD: Shrines - Restore Health and Cancel Options]: Restore health option doesn't work + Bug #2039: Lake Fjalding pillar of fire not rendered + Bug #2040: AI_follow should stop further from the target + Bug #2076: Slaughterfish AI + Bug #2077: Direction of long jump can be changed much more than it is possible in vanilla + Bug #2078: error during rendering: Object '' not found (const) + Bug #2105: Lockpicking causes screen sync glitch + Bug #2113: [MOD: Julan Ashlander Companion] Julan does not act correctly within the Ghostfence. + Bug #2123: Window glow mod: Collision issues + Bug #2133: Missing collision for bridges in Balmora when using Morrowind Rebirth 2.81 + Bug #2135: Casting a summon spell while the summon is active does not reset the summon. + Bug #2144: Changing equipment will unequip drawn arrows/bolts + Bug #2169: Yellow on faces when using opengl renderer and mods from overhaul on windows + Bug #2175: Pathgrid mods do not overwrite the existing pathgrid + Bug #2176: Morrowind -Russian localization end add-on ChaosHeart. Error in framelistener;object ;frenzying toush; not found + Bug #2181: Mod Morrowind crafting merchants die. + Bug #2182: mods changing skill progression double the bonus for class specialization + Bug #2183: Editor: Skills "use value" only allows integer between 0 and 99 + Bug #2184: Animated Morrowind Expanded produces an error on Open MW Launch + Bug #2185: Conditional Operator formats + Bug #2193: Quest: Gateway Ghost + Bug #2194: Cannot summon multiples of the same creature + Bug #2195: Pathgrid in the (0,0) exterior cell not loaded + Bug #2200: Outdoor NPCs can stray away and keep walking into a wall + Bug #2201: Creatures do not receive fall damage + Bug #2202: The enchantment the item can hold is calculated incorrectly + Bug #2203: Having the mod Living Cities of Vvardenfall running causes the game world to fail to load after leaving the prison ship + Bug #2204: Abot's Water Life - Book rendered incorrectly + Bug #2205: sound_waterfall script no longer compiles + Bug #2206: Dialogue script fails to compile (extra .) + Bug #2207: Script using – instead of - character does not compile + Bug #2208: Failing dialogue scripts in french Morrowind.esm + Bug #2214: LGNPC Vivec Redoran 1.62 and The King Rat (Size and inventory Issues) + Bug #2215: Beast races can use enchanted boots + Bug #2218: Incorrect names body parts in 3D models for open helmet with skinning + Bug #2219: Orcs in Ghorak Manor in Caldera don't attack if you pick their pockets. + Bug #2220: Chargen race preview head incorrect orientation + Bug #2223: Reseting rock falling animation + Bug #2224: Fortify Attribute effects do not stack when Spellmaking. + Bug #2226: OpenCS pseudo-crash + Bug #2230: segfaulting when entering Ald'ruhn with a specific mod: "fermeture la nuit" (closed by night) + Bug #2233: Area effect spells on touch do not have the area effect + Bug #2234: Dwarven Crossbow clips through the ground when dropped + Bug #2235: class SettingsBase<> reverses the order of entries with multiple keys. + Bug #2236: Weird two handed longsword + torch interaction + Bug #2237: Shooting arrows while sneaking do not agro + Bug #2238: Bipedal creatures not using weapons are not handled properly + Bug #2245: Incorrect topic highlighting in HT_SpyBaladas quest + Bug #2252: Tab completion incomplete for places using COC from the console. + Bug #2255: Camera reverts to first person on load + Bug #2259: enhancement: the save/load progress bar is not very progressive + Bug #2263: TogglePOV can not be bound to Alt key + Bug #2267: dialogue disabling via mod + Bug #2268: Highlighting Files with load order problems in Data Files tab of Launcher + Bug #2276: [Mod]ShotN issues with Karthwasten + Bug #2283: Count argument for PlaceAt functions not working + Bug #2284: Local map notes should be visible on door marker leading to the cell with the note + Bug #2293: There is a graphical glitch at the end of the spell's animation in 3rd Person (looking over the shoulder) view + Bug #2294: When using Skyrim UI Overhaul, the tops of pinnable menus are invisible + Bug #2302: Random leveled items repeat way too often in a single dungeon + Bug #2306: Enchanted arrows should not be retrievable from corpses + Bug #2308: No sound effect when drawing the next throwing knife + Bug #2309: Guards chase see the player character even if they're invisible + Bug #2319: Inverted controls and other issues after becoming a vampire + Bug #2324: Spells cast when crossing cell border are imprinted on the local map + Bug #2330: Actors with Drain Health effect retain health after dying + Bug #2331: tgm (god mode) won't allow the player to cast spells if the player doesn't have enough mana + Bug #2332: Error in framelistener: Need a skeleton to attach the arrow to + Feature #114: ess-Importer + Feature #504: Editor: Delete selected rows from result windows + Feature #1024: Addition of remaining equipping hotkeys + Feature #1067: Handle NIF interpolation type 4 (XYZ_ROTATION_KEY) + Feature #1125: AI fast-forward + Feature #1228: Drowning while knocked out + Feature #1325: Editor: Opening window and User Settings window cleanup + Feature #1537: Ability to change the grid size from 3x3 to 5x5 (or more with good pc) + Feature #1546: Leveled list script functions + Feature #1659: Test dialogue scripts in --script-all + Feature #1720: NPC lookAt controller + Feature #2178: Load initial particle system state from NIF files + Feature #2197: Editor: When clicking on a script error in the report window set cursor in script editor to the respective line/column + Feature #2261: Warn when loading save games with mod mismatch + Feature #2313: ess-Importer: convert global map exploration overlay + Feature #2318: Add commandline option to load a save game + Task #810: Rename "profile" to "content list" + Task #2196: Label local/global openmw.cfg files via comments + 0.34.0 ------ From 42363191a41a30833247fbfe9eba634e8f035a3a Mon Sep 17 00:00:00 2001 From: Lazaroth Date: Tue, 3 Feb 2015 15:25:36 +0100 Subject: [PATCH 084/214] Layout tweaks --- files/mygui/openmw_enchanting_dialog.layout | 2 -- files/mygui/openmw_merchantrepair.layout | 20 ++++++++------- files/mygui/openmw_persuasion_dialog.layout | 14 +++++------ files/mygui/openmw_spell_buying_window.layout | 22 ++++++++-------- .../mygui/openmw_spellcreation_dialog.layout | 14 ++++------- files/mygui/openmw_trade_window.layout | 5 ++-- files/mygui/openmw_trainingwindow.layout | 20 +++++++++------ files/mygui/openmw_travel_window.layout | 25 ++++++++++--------- 8 files changed, 62 insertions(+), 60 deletions(-) diff --git a/files/mygui/openmw_enchanting_dialog.layout b/files/mygui/openmw_enchanting_dialog.layout index ed62c8dc63..b90fc7a775 100644 --- a/files/mygui/openmw_enchanting_dialog.layout +++ b/files/mygui/openmw_enchanting_dialog.layout @@ -141,8 +141,6 @@ - - diff --git a/files/mygui/openmw_merchantrepair.layout b/files/mygui/openmw_merchantrepair.layout index da7f37fe77..23ab6008ff 100644 --- a/files/mygui/openmw_merchantrepair.layout +++ b/files/mygui/openmw_merchantrepair.layout @@ -1,26 +1,28 @@ - + - - - + + + + + - - - + + + - + - + diff --git a/files/mygui/openmw_persuasion_dialog.layout b/files/mygui/openmw_persuasion_dialog.layout index 87851b479b..6fb2989141 100644 --- a/files/mygui/openmw_persuasion_dialog.layout +++ b/files/mygui/openmw_persuasion_dialog.layout @@ -1,17 +1,13 @@ - + - + - - - - @@ -39,7 +35,11 @@ - + + + + + diff --git a/files/mygui/openmw_spell_buying_window.layout b/files/mygui/openmw_spell_buying_window.layout index 73820c3d48..0350f1e278 100644 --- a/files/mygui/openmw_spell_buying_window.layout +++ b/files/mygui/openmw_spell_buying_window.layout @@ -1,26 +1,28 @@ - + - - - + + + + + - - - + + + - - + + - + diff --git a/files/mygui/openmw_spellcreation_dialog.layout b/files/mygui/openmw_spellcreation_dialog.layout index 90b95b2f42..11197bf2a9 100644 --- a/files/mygui/openmw_spellcreation_dialog.layout +++ b/files/mygui/openmw_spellcreation_dialog.layout @@ -1,10 +1,9 @@ - + - @@ -16,9 +15,7 @@ - - - + @@ -33,7 +30,6 @@ - @@ -46,7 +42,6 @@ - @@ -70,7 +65,7 @@ - + @@ -83,8 +78,9 @@ + + - diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index 8668243cc5..b2017661b6 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -29,10 +29,10 @@ - + - + @@ -63,7 +63,6 @@ - diff --git a/files/mygui/openmw_trainingwindow.layout b/files/mygui/openmw_trainingwindow.layout index d6cea8727b..c58bd0ab3a 100644 --- a/files/mygui/openmw_trainingwindow.layout +++ b/files/mygui/openmw_trainingwindow.layout @@ -1,22 +1,26 @@ - - - - + - + + + + + - - + + + + + - + diff --git a/files/mygui/openmw_travel_window.layout b/files/mygui/openmw_travel_window.layout index 4b383ee7c4..3603f7dcbf 100644 --- a/files/mygui/openmw_travel_window.layout +++ b/files/mygui/openmw_travel_window.layout @@ -1,28 +1,29 @@ - + - - - - + + + + + + - - - - + + + - - + + - + From abb334bc1e0e77ed142afda1e6f003f7def6995d Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 3 Feb 2015 22:43:15 +0100 Subject: [PATCH 085/214] Missing change for the tool rename --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fe213b49a..b5cd54babc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -714,7 +714,7 @@ if (WIN32) if (BUILD_OPENCS) # QT triggers an informational warning that the object layout may differ when compiled with /vd2 set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435") - set_target_properties(opencs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS}) + set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS}) endif (BUILD_OPENCS) if (BUILD_MWINIIMPORTER) set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") From 14923f3e8bf0fb07c2ee05e0c048e412fb9f91ab Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 23:05:06 +0100 Subject: [PATCH 086/214] Fix for broken unsetRefNum --- apps/openmw/mwworld/cellref.cpp | 6 +++--- apps/openmw/mwworld/cellref.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 744e0e27a4..d2cced3b86 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -5,19 +5,19 @@ namespace MWWorld { - ESM::RefNum CellRef::getRefNum() const + const ESM::RefNum& CellRef::getRefNum() const { return mCellRef.mRefNum; } bool CellRef::hasContentFile() const { - return getRefNum().hasContentFile(); + return mCellRef.mRefNum.hasContentFile(); } void CellRef::unsetRefNum() { - getRefNum().unset(); + mCellRef.mRefNum.unset(); } std::string CellRef::getRefId() const diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index 054fd7fc68..f063b27272 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -23,7 +23,7 @@ namespace MWWorld } // Note: Currently unused for items in containers - ESM::RefNum getRefNum() const; + const ESM::RefNum& getRefNum() const; // Set RefNum to its default state. void unsetRefNum(); From fbb8998184f49ff077bb4941de88abb9931e5043 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 16:41:14 +0100 Subject: [PATCH 087/214] Account for not yet listed cells in getInteriorPtrs --- apps/openmw/mwworld/cells.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index fd5ec20dce..2aa817fa50 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -241,26 +241,30 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) void MWWorld::Cells::getExteriorPtrs(const std::string &name, std::vector &out) { - for (std::map, CellStore>::iterator iter = mExteriors.begin(); - iter!=mExteriors.end(); ++iter) + const MWWorld::Store &cells = mStore.get(); + for (MWWorld::Store::iterator iter = cells.extBegin(); iter != cells.extEnd(); ++iter) { - Ptr ptr = getPtrAndCache (name, iter->second); + CellStore *cellStore = getCellStore (&(*iter)); + + Ptr ptr = getPtrAndCache (name, *cellStore); + if (!ptr.isEmpty()) out.push_back(ptr); } - } void MWWorld::Cells::getInteriorPtrs(const std::string &name, std::vector &out) { - for (std::map::iterator iter = mInteriors.begin(); - iter!=mInteriors.end(); ++iter) + const MWWorld::Store &cells = mStore.get(); + for (MWWorld::Store::iterator iter = cells.intBegin(); iter != cells.intEnd(); ++iter) { - Ptr ptr = getPtrAndCache (name, iter->second); + CellStore *cellStore = getCellStore (&(*iter)); + + Ptr ptr = getPtrAndCache (name, *cellStore); + if (!ptr.isEmpty()) out.push_back(ptr); } - } int MWWorld::Cells::countSavedGameRecords() const From 1f036c0381f3cbaaf3f21670d998b3f422a339c3 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Wed, 4 Feb 2015 12:06:29 -0600 Subject: [PATCH 088/214] Patch for COC Spawn Issue. OMW Bug #1079 Fall back to the first static's position, if there are no door markers. --- apps/openmw/mwworld/worldimp.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1036d8ce6a..e08000b0b1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2383,6 +2383,7 @@ namespace MWWorld bool World::findInteriorPosition(const std::string &name, ESM::Position &pos) { typedef MWWorld::CellRefList::List DoorList; + typedef MWWorld::CellRefList::List StaticList; pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; pos.pos[0] = pos.pos[1] = pos.pos[2] = 0; @@ -2427,6 +2428,13 @@ namespace MWWorld } } } + // Fall back to the first static location. + const StaticList &statics = cellStore->get().mList; + if ( statics.begin() != statics.end() ) { + pos = statics.begin()->mRef.getPosition(); + return true; + } + return false; } From 0c6e2170dbb5c880b4c3c8df3ff43566849cd804 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 31 Jan 2015 23:27:34 +0100 Subject: [PATCH 089/214] Include cleanup --- apps/launcher/graphicspage.cpp | 2 +- apps/openmw/mwbase/environment.hpp | 4 ++-- apps/openmw/mwbase/inputmanager.hpp | 4 +--- apps/openmw/mwbase/soundmanager.hpp | 4 +--- apps/openmw/mwbase/windowmanager.hpp | 18 +++++++++++------- apps/openmw/mwbase/world.hpp | 14 +++++--------- apps/openmw/mwdialogue/scripttest.cpp | 2 ++ apps/openmw/mwgui/hud.cpp | 1 + apps/openmw/mwgui/inventorywindow.cpp | 2 ++ apps/openmw/mwgui/itemmodel.cpp | 2 ++ apps/openmw/mwgui/journalviewmodel.cpp | 2 ++ apps/openmw/mwgui/loadingscreen.cpp | 2 ++ apps/openmw/mwgui/mainmenu.cpp | 1 + apps/openmw/mwgui/mapwindow.cpp | 1 + apps/openmw/mwgui/settingswindow.cpp | 1 + apps/openmw/mwgui/tooltips.cpp | 1 + apps/openmw/mwgui/waitdialog.cpp | 1 + apps/openmw/mwgui/windowbase.cpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 7 ++++--- apps/openmw/mwmechanics/actors.hpp | 1 + apps/openmw/mwmechanics/character.cpp | 2 ++ apps/openmw/mwrender/animation.cpp | 1 + apps/openmw/mwrender/globalmap.cpp | 1 + apps/openmw/mwscript/animationextensions.cpp | 1 + apps/openmw/mwstate/statemanagerimp.cpp | 1 + apps/openmw/mwworld/livecellref.cpp | 3 ++- extern/sdl4ogre/events.h | 6 +++--- extern/sdl4ogre/sdlcursormanager.cpp | 3 +++ extern/sdl4ogre/sdlcursormanager.hpp | 5 +++-- 30 files changed, 66 insertions(+), 34 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 1f85bb5e7b..dccf8bb8ce 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -10,7 +10,7 @@ #define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ #endif // MAC_OS_X_VERSION_MIN_REQUIRED -#include +#include #include #include diff --git a/apps/openmw/mwbase/environment.hpp b/apps/openmw/mwbase/environment.hpp index eb636ea2fb..7f7919f813 100644 --- a/apps/openmw/mwbase/environment.hpp +++ b/apps/openmw/mwbase/environment.hpp @@ -1,5 +1,5 @@ -#ifndef GAME_BASE_INVIRONMENT_H -#define GAME_BASE_INVIRONMENT_H +#ifndef GAME_BASE_ENVIRONMENT_H +#define GAME_BASE_ENVIRONMENT_H namespace MWBase { diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index d44da4974d..11eb1721f2 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -3,8 +3,6 @@ #include -#include - namespace MWBase { /// \brief Interface for input manager (implemented in MWInput) @@ -29,7 +27,7 @@ namespace MWBase virtual void changeInputMode(bool guiMode) = 0; - virtual void processChangedSettings(const Settings::CategorySettingVector& changed) = 0; + virtual void processChangedSettings(const std::vector< std::pair >& changed) = 0; virtual void setDragDrop(bool dragDrop) = 0; diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index bc2f3f1c61..a4c08f06fe 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -5,8 +5,6 @@ #include -#include - #include "../mwworld/ptr.hpp" namespace Ogre @@ -74,7 +72,7 @@ namespace MWBase virtual ~SoundManager() {} - virtual void processChangedSettings(const Settings::CategorySettingVector& settings) = 0; + virtual void processChangedSettings(const std::vector< std::pair >& settings) = 0; virtual void stopMusic() = 0; ///< Stops music if it's playing diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 69027d7341..fc745d3e68 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -5,16 +5,20 @@ #include #include -#include - -#include - -#include - #include "../mwmechanics/stat.hpp" #include "../mwgui/mode.hpp" +namespace Loading +{ + class Listener; +} + +namespace Translation +{ + class Storage; +} + namespace MyGUI { class Gui; @@ -267,7 +271,7 @@ namespace MWBase */ virtual std::string getGameSettingString(const std::string &id, const std::string &default_) = 0; - virtual void processChangedSettings(const Settings::CategorySettingVector& changed) = 0; + virtual void processChangedSettings(const std::vector< std::pair >& changed) = 0; virtual void windowResized(int x, int y) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 9d8fc90a1f..3af2a27752 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -4,25 +4,21 @@ #include #include -#include - #include -#include "../mwworld/globals.hpp" #include "../mwworld/ptr.hpp" namespace Ogre { class Vector2; class Vector3; + class Quaternion; + class Image; } -namespace OEngine +namespace Loading { - namespace Physic - { - class PhysicEngine; - } + class Listener; } namespace ESM @@ -390,7 +386,7 @@ namespace MWBase virtual bool canPlaceObject (float cursorX, float cursorY) = 0; ///< @return true if it is possible to place on object at specified cursor location - virtual void processChangedSettings (const Settings::CategorySettingVector& settings) = 0; + virtual void processChangedSettings (const std::vector< std::pair >& settings) = 0; virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0; diff --git a/apps/openmw/mwdialogue/scripttest.cpp b/apps/openmw/mwdialogue/scripttest.cpp index b2c8f536a2..fd477365f0 100644 --- a/apps/openmw/mwdialogue/scripttest.cpp +++ b/apps/openmw/mwdialogue/scripttest.cpp @@ -1,5 +1,7 @@ #include "scripttest.hpp" +#include + #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 13a5c559c1..1f7ead6f56 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -10,6 +10,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index ed0f505f53..ae7d60d442 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index f5135ce80e..8224fd55b0 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -1,5 +1,7 @@ #include "itemmodel.hpp" +#include + #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/store.hpp" diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index add2ac62c7..3a86613f61 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -8,6 +8,8 @@ #include +#include + #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 270066c97a..9e3343c782 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -15,6 +15,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/statemanager.hpp" diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index f1c4c40885..6ad4da3bfb 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -9,6 +9,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 61712a470e..13e2e39049 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index f8741a67a2..2810934522 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -15,6 +15,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 2849688c2b..2750717372 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -8,6 +8,7 @@ #include #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 718e04e52e..fedb0324e9 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 7f2eaec2ec..8fdcf6b207 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 975ee6c29f..a35498deaa 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -19,6 +19,9 @@ #include #include +#include +#include + #include #include @@ -26,6 +29,8 @@ #include +#include + #include #include diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index a08c59a2fb..b3eb9cd0a9 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -5,13 +5,14 @@ This class owns and controls all the MW specific windows in the GUI. It can enable/disable Gui mode, and is responsible for sending and retrieving information from the Gui. - - MyGUI should be initialized separately before creating instances of - this class. **/ +#include + #include "../mwbase/windowmanager.hpp" +#include + #include "mapwindow.hpp" #include diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 39598b2a25..70f1b47d91 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "movement.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 91b3757146..449c030f45 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -27,6 +27,8 @@ #include "creaturestats.hpp" #include "security.hpp" +#include + #include "../mwrender/animation.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ec53983092..50afc5afdd 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index f0f6158ed4..de78748b57 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -11,6 +11,7 @@ #include #include +#include #include diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index 613cf7d24e..00b8a9620f 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -2,6 +2,7 @@ #include "animationextensions.hpp" #include +#include #include #include diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index a282f152ad..d623ba4654 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwworld/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp index dd313632b8..bfc708185d 100644 --- a/apps/openmw/mwworld/livecellref.cpp +++ b/apps/openmw/mwworld/livecellref.cpp @@ -1,6 +1,7 @@ - #include "livecellref.hpp" +#include + #include #include "../mwbase/environment.hpp" diff --git a/extern/sdl4ogre/events.h b/extern/sdl4ogre/events.h index 0fb4d6f060..6961e81fc8 100644 --- a/extern/sdl4ogre/events.h +++ b/extern/sdl4ogre/events.h @@ -1,8 +1,8 @@ #ifndef _SFO_EVENTS_H #define _SFO_EVENTS_H -#include - +#include +#include //////////// // Events // @@ -65,7 +65,7 @@ public: virtual ~WindowListener() {} /** @remarks The window's visibility changed */ - virtual void windowVisibilityChange( bool visible ) {}; + virtual void windowVisibilityChange( bool visible ) {} /** @remarks The window got / lost input focus */ virtual void windowFocusChange( bool have_focus ) {} diff --git a/extern/sdl4ogre/sdlcursormanager.cpp b/extern/sdl4ogre/sdlcursormanager.cpp index 5ef274b7e7..7623d57dbf 100644 --- a/extern/sdl4ogre/sdlcursormanager.cpp +++ b/extern/sdl4ogre/sdlcursormanager.cpp @@ -4,6 +4,9 @@ #include #include +#include +#include + #include namespace SFO diff --git a/extern/sdl4ogre/sdlcursormanager.hpp b/extern/sdl4ogre/sdlcursormanager.hpp index 7e3e59b4a5..58324fc01c 100644 --- a/extern/sdl4ogre/sdlcursormanager.hpp +++ b/extern/sdl4ogre/sdlcursormanager.hpp @@ -1,11 +1,12 @@ #ifndef SDL4OGRE_CURSORMANAGER_H #define SDL4OGRE_CURSORMANAGER_H -#include - #include "cursormanager.hpp" #include +struct SDL_Cursor; +struct SDL_Surface; + namespace SFO { class SDLCursorManager : From 6d097fbfbd8f051de27bfcd81bb0746f1509bf47 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Feb 2015 00:26:06 +0100 Subject: [PATCH 090/214] Normalise spelling of "levelled" throughout the code --- apps/esmtool/record.cpp | 4 ++-- apps/essimporter/importcellref.cpp | 4 ++-- apps/openmw/mwmechanics/levelledlist.hpp | 8 ++++---- apps/openmw/mwmechanics/npcstats.cpp | 2 +- apps/openmw/mwscript/miscextensions.cpp | 10 +++++----- components/esm/loadlevlist.cpp | 6 +++--- components/esm/loadlevlist.hpp | 12 ++++++------ 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index df2631c13f..e167278f3d 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -837,7 +837,7 @@ void Record::print() std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl; std::cout << " Flags: " << creatureListFlags(mData.mFlags) << std::endl; std::cout << " Number of items: " << mData.mList.size() << std::endl; - std::vector::iterator iit; + std::vector::iterator iit; for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) std::cout << " Creature: Level: " << iit->mLevel << " Creature: " << iit->mId << std::endl; @@ -849,7 +849,7 @@ void Record::print() std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl; std::cout << " Flags: " << itemListFlags(mData.mFlags) << std::endl; std::cout << " Number of items: " << mData.mList.size() << std::endl; - std::vector::iterator iit; + std::vector::iterator iit; for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) std::cout << " Inventory: Level: " << iit->mLevel << " Item: " << iit->mId << std::endl; diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index 906b2ed242..cca356b2a8 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -22,7 +22,7 @@ namespace ESSImport ActorData::load(esm); if (esm.isNextSub("LVCR")) { - // occurs on leveled creature spawner references + // occurs on levelled creature spawner references // probably some identifier for the creature that has been spawned? unsigned char lvcr; esm.getHT(lvcr); @@ -32,7 +32,7 @@ namespace ESSImport mEnabled = true; esm.getHNOT(mEnabled, "ZNAM"); - // DATA should occur for all references, except leveled creature spawners + // DATA should occur for all references, except levelled creature spawners // I've seen DATA *twice* on a creature record, and with the exact same content too! weird // alarmvoi0000.ess esm.getHNOT(mPos, "DATA", 24); diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index 96410c35d7..de652a9c84 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -12,9 +12,9 @@ namespace MWMechanics { /// @return ID of resulting item, or empty if none - inline std::string getLevelledItem (const ESM::LeveledListBase* levItem, bool creature, unsigned char failChance=0) + inline std::string getLevelledItem (const ESM::LevelledListBase* levItem, bool creature, unsigned char failChance=0) { - const std::vector& items = levItem->mList; + const std::vector& items = levItem->mList; const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); int playerLevel = player.getClass().getCreatureStats(player).getLevel(); @@ -27,7 +27,7 @@ namespace MWMechanics std::vector candidates; int highestLevel = 0; - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) { if (it->mLevel > highestLevel && it->mLevel <= playerLevel) highestLevel = it->mLevel; @@ -39,7 +39,7 @@ namespace MWMechanics allLevels = levItem->mFlags & ESM::CreatureLevList::AllLevels; std::pair highest = std::make_pair(-1, ""); - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) { if (playerLevel >= it->mLevel && (allLevels || it->mLevel == highestLevel)) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index c517b4df8a..7219d6185a 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -200,7 +200,7 @@ void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, if (value.getProgress()>=1) { - // skill leveled up + // skill levelled up increaseSkill(skillIndex, class_, false); } } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 37bb4235e2..bffeef768c 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -34,24 +34,24 @@ namespace { - void addToLevList(ESM::LeveledListBase* list, const std::string& itemId, int level) + void addToLevList(ESM::LevelledListBase* list, const std::string& itemId, int level) { - for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) + for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) { if (it->mLevel == level && itemId == it->mId) return; } - ESM::LeveledListBase::LevelItem item; + ESM::LevelledListBase::LevelItem item; item.mId = itemId; item.mLevel = level; list->mList.push_back(item); } - void removeFromLevList(ESM::LeveledListBase* list, const std::string& itemId, int level) + void removeFromLevList(ESM::LevelledListBase* list, const std::string& itemId, int level) { // level of -1 removes all items with that itemId - for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) + for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) { if (level != -1 && it->mLevel != level) { diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 6385b9a718..f2c695c1f1 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -7,7 +7,7 @@ namespace ESM { -void LeveledListBase::load(ESMReader &esm) +void LevelledListBase::load(ESMReader &esm) { esm.getHNT(mFlags, "DATA"); esm.getHNT(mChanceNone, "NNAM"); @@ -34,7 +34,7 @@ void LeveledListBase::load(ESMReader &esm) esm.getHNT(li.mLevel, "INTV"); } } -void LeveledListBase::save(ESMWriter &esm) const +void LevelledListBase::save(ESMWriter &esm) const { esm.writeHNT("DATA", mFlags); esm.writeHNT("NNAM", mChanceNone); @@ -47,7 +47,7 @@ void LeveledListBase::save(ESMWriter &esm) const } } - void LeveledListBase::blank() + void LevelledListBase::blank() { mFlags = 0; mChanceNone = 0; diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index a4e1b85c2d..bcea2b234c 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -11,14 +11,14 @@ class ESMReader; class ESMWriter; /* - * Leveled lists. Since these have identical layout, I only bothered + * Levelled lists. Since these have identical layout, I only bothered * to implement it once. * - * We should later implement the ability to merge leveled lists from + * We should later implement the ability to merge levelled lists from * several files. */ -struct LeveledListBase +struct LevelledListBase { int mFlags; unsigned char mChanceNone; // Chance that none are selected (0-100) @@ -43,7 +43,7 @@ struct LeveledListBase ///< Set record to default state (does not touch the ID). }; -struct CreatureLevList: LeveledListBase +struct CreatureLevList: LevelledListBase { static unsigned int sRecordId; @@ -61,7 +61,7 @@ struct CreatureLevList: LeveledListBase } }; -struct ItemLevList: LeveledListBase +struct ItemLevList: LevelledListBase { static unsigned int sRecordId; @@ -72,7 +72,7 @@ struct ItemLevList: LeveledListBase // list is instantiated, instead of // giving several identical items // (used when a container has more - // than one instance of one leveled + // than one instance of one levelled // list.) AllLevels = 0x02 // Calculate from all levels <= player // level, not just the closest below From 9825b68dfb6d5ab015d283c6bb858246b40ba9b2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Feb 2015 16:19:05 +0100 Subject: [PATCH 091/214] Fix SDL eating SIGINT signals in the launcher (Fixes #2328) --- apps/launcher/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index e4fae74f4d..5c3f384581 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -26,6 +27,8 @@ int main(int argc, char *argv[]) qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError()); return 0; } + signal(SIGINT, SIG_DFL); // We don't want to use the SDL event loop in the launcher, + // so reset SIGINT which SDL wants to redirect to an SDL_Quit event. QApplication app(argc, argv); From 6ea59c93abf46402f505c8dd8519b42a7249dc15 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Feb 2015 04:20:33 +0100 Subject: [PATCH 092/214] Ignore the object scale in Move instruction (Fixes #2275) --- apps/openmw/mwscript/transformationextensions.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 3bbde20036..fcfc36995f 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -691,10 +691,10 @@ namespace MWScript if (!ptr.getRefData().getBaseNode()) return; - Ogre::Vector3 worldPos = ptr.getRefData().getBaseNode()->convertLocalToWorldPosition(posChange); - - dynamic_cast(runtime.getContext()).updatePtr( - MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z)); + Ogre::Vector3 diff = ptr.getRefData().getBaseNode()->getOrientation() * posChange; + Ogre::Vector3 worldPos(ptr.getRefData().getPosition().pos); + worldPos += diff; + MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z); } }; From 27dc49a1357c2078d2305f0859efd3ccc3de8639 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 00:53:30 +0100 Subject: [PATCH 093/214] Rewrite game settings manager Removes the abhorrent dependency on Ogre for this code and improves the error handling. --- apps/openmw/engine.cpp | 6 +- apps/openmw/mwbase/inputmanager.hpp | 4 +- apps/openmw/mwbase/soundmanager.hpp | 4 +- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwbase/world.hpp | 3 +- components/settings/settings.cpp | 228 +++++++++++++++------------ components/settings/settings.hpp | 13 +- 7 files changed, 139 insertions(+), 121 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 859baebe4a..a9a7f06324 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -292,14 +292,10 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) else throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed."); - // load user settings if they exist, otherwise just load the default settings as user settings + // load user settings if they exist const std::string settingspath = mCfgMgr.getUserConfigPath().string() + "/settings.cfg"; if (boost::filesystem::exists(settingspath)) settings.loadUser(settingspath); - else if (boost::filesystem::exists(localdefault)) - settings.loadUser(localdefault); - else if (boost::filesystem::exists(globaldefault)) - settings.loadUser(globaldefault); mFpsLevel = settings.getInt("fps", "HUD"); diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 11eb1721f2..a53d8d9dcd 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -2,6 +2,8 @@ #define GAME_MWBASE_INPUTMANAGER_H #include +#include +#include namespace MWBase { @@ -27,7 +29,7 @@ namespace MWBase virtual void changeInputMode(bool guiMode) = 0; - virtual void processChangedSettings(const std::vector< std::pair >& changed) = 0; + virtual void processChangedSettings(const std::set< std::pair >& changed) = 0; virtual void setDragDrop(bool dragDrop) = 0; diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index a4c08f06fe..f3381a8fda 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -2,7 +2,7 @@ #define GAME_MWBASE_SOUNDMANAGER_H #include - +#include #include #include "../mwworld/ptr.hpp" @@ -72,7 +72,7 @@ namespace MWBase virtual ~SoundManager() {} - virtual void processChangedSettings(const std::vector< std::pair >& settings) = 0; + virtual void processChangedSettings(const std::set< std::pair >& settings) = 0; virtual void stopMusic() = 0; ///< Stops music if it's playing diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index fc745d3e68..c984b5e541 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -271,7 +271,7 @@ namespace MWBase */ virtual std::string getGameSettingString(const std::string &id, const std::string &default_) = 0; - virtual void processChangedSettings(const std::vector< std::pair >& changed) = 0; + virtual void processChangedSettings(const std::set< std::pair >& changed) = 0; virtual void windowResized(int x, int y) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 3af2a27752..154d96f7d4 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -386,7 +387,7 @@ namespace MWBase virtual bool canPlaceObject (float cursorX, float cursorY) = 0; ///< @return true if it is possible to place on object at specified cursor location - virtual void processChangedSettings (const std::vector< std::pair >& settings) = 0; + virtual void processChangedSettings (const std::set< std::pair >& settings) = 0; virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0; diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index 5fc2ca3c11..a9a78d0351 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -1,95 +1,144 @@ #include "settings.hpp" #include -#include -#include -#include #include -#include -#include +#include +#include +#include -using namespace Settings; +namespace Settings +{ -namespace bfs = boost::filesystem; - -Ogre::ConfigFile Manager::mFile = Ogre::ConfigFile(); -Ogre::ConfigFile Manager::mDefaultFile = Ogre::ConfigFile(); +CategorySettingValueMap Manager::mDefaultSettings = CategorySettingValueMap(); +CategorySettingValueMap Manager::mUserSettings = CategorySettingValueMap(); CategorySettingVector Manager::mChangedSettings = CategorySettingVector(); -CategorySettingValueMap Manager::mNewSettings = CategorySettingValueMap(); -void Manager::loadUser (const std::string& file) + +class SettingsFileParser { - Ogre::DataStreamPtr stream = openConstrainedFileDataStream(file.c_str()); - mFile.load(stream); -} +public: + SettingsFileParser() : mLine(0) {} -void Manager::loadDefault (const std::string& file) -{ - Ogre::DataStreamPtr stream = openConstrainedFileDataStream(file.c_str()); - mDefaultFile.load(stream); -} - -void Manager::saveUser(const std::string& file) -{ - bfs::ofstream fout((bfs::path(file))); - - Ogre::ConfigFile::SectionIterator seci = mFile.getSectionIterator(); - - while (seci.hasMoreElements()) + void loadSettingsFile (const std::string& file, CategorySettingValueMap& settings) { - Ogre::String sectionName = seci.peekNextKey(); - - if (sectionName.length() > 0) - fout << '\n' << '[' << seci.peekNextKey() << ']' << '\n'; - - Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext(); - Ogre::ConfigFile::SettingsMultiMap::iterator i; - for (i = settings->begin(); i != settings->end(); ++i) + mFile = file; + boost::filesystem::ifstream stream; + stream.open(boost::filesystem::path(file)); + std::string currentCategory; + mLine = 0; + while (!stream.eof() && !stream.fail()) { - fout << i->first.c_str() << " = " << i->second.c_str() << '\n'; - } + ++mLine; + std::string line; + std::getline( stream, line ); - CategorySettingValueMap::iterator it = mNewSettings.begin(); - while (it != mNewSettings.end()) - { - if (it->first.first == sectionName) + size_t i = 0; + if (!skipWhiteSpace(i, line)) + continue; + + if (line[i] == '#') // skip comment + continue; + + if (line[i] == '[') { - fout << it->first.second << " = " << it->second << '\n'; - mNewSettings.erase(it++); + size_t end = line.find(']', i); + if (end == std::string::npos) + fail("unterminated category"); + + currentCategory = line.substr(i+1, end - (i+1)); + boost::algorithm::trim(currentCategory); + i = end+1; } - else - ++it; + + if (!skipWhiteSpace(i, line)) + continue; + + if (currentCategory.empty()) + fail("empty category name"); + + size_t settingEnd = line.find('=', i); + if (settingEnd == std::string::npos) + fail("unterminated setting name"); + + std::string setting = line.substr(i, (settingEnd-i)); + boost::algorithm::trim(setting); + + size_t valueBegin = settingEnd+1; + std::string value = line.substr(valueBegin); + boost::algorithm::trim(value); + + if (settings.insert(std::make_pair(std::make_pair(currentCategory, setting), value)).second == false) + fail(std::string("duplicate setting: [" + currentCategory + "] " + setting)); } } - std::string category = ""; - for (CategorySettingValueMap::iterator it = mNewSettings.begin(); - it != mNewSettings.end(); ++it) +private: + /// Increment i until it longer points to a whitespace character + /// in the string or has reached the end of the string. + /// @return false if we have reached the end of the string + bool skipWhiteSpace(size_t& i, std::string& str) { - if (category != it->first.first) + while (i < str.size() && std::isspace(str[i], std::locale::classic())) { - category = it->first.first; - fout << '\n' << '[' << category << ']' << '\n'; + ++i; } - fout << it->first.second << " = " << it->second << '\n'; + return i < str.size(); } - fout.close(); + void fail(const std::string& message) + { + std::stringstream error; + error << "Error on line " << mLine << " in " << mFile << ":\n" << message; + throw std::runtime_error(error.str()); + } + + std::string mFile; + int mLine; +}; + +void Manager::loadDefault(const std::string &file) +{ + SettingsFileParser parser; + parser.loadSettingsFile(file, mDefaultSettings); } -std::string Manager::getString (const std::string& setting, const std::string& category) +void Manager::loadUser(const std::string &file) { - if (mNewSettings.find(std::make_pair(category, setting)) != mNewSettings.end()) - return mNewSettings[std::make_pair(category, setting)]; + SettingsFileParser parser; + parser.loadSettingsFile(file, mUserSettings); +} - std::string defaultval = mDefaultFile.getSetting(setting, category, "NOTFOUND"); - std::string val = mFile.getSetting(setting, category, defaultval); +void Manager::saveUser(const std::string &file) +{ + boost::filesystem::ofstream stream; + stream.open(boost::filesystem::path(file)); + std::string currentCategory; + for (CategorySettingValueMap::iterator it = mUserSettings.begin(); it != mUserSettings.end(); ++it) + { + if (it->first.first != currentCategory) + { + currentCategory = it->first.first; + stream << "\n[" << currentCategory << "]\n"; + } + stream << it->first.second << " = " << it->second << "\n"; + } +} - if (val == "NOTFOUND") - throw std::runtime_error("Trying to retrieve a non-existing setting: " + setting + " Make sure the settings-default.cfg file was properly installed."); - return val; +std::string Manager::getString(const std::string &setting, const std::string &category) +{ + CategorySettingValueMap::key_type key = std::make_pair(category, setting); + CategorySettingValueMap::iterator it = mUserSettings.find(key); + if (it != mUserSettings.end()) + return it->second; + + it = mDefaultSettings.find(key); + if (it != mDefaultSettings.end()) + return it->second; + + throw std::runtime_error(std::string("Trying to retrieve a non-existing setting: ") + setting + + ".\nMake sure the settings-default.cfg file file was properly installed."); } float Manager::getFloat (const std::string& setting, const std::string& category) @@ -107,51 +156,20 @@ bool Manager::getBool (const std::string& setting, const std::string& category) return Ogre::StringConverter::parseBool( getString(setting, category) ); } -void Manager::setString (const std::string& setting, const std::string& category, const std::string& value) +void Manager::setString(const std::string &setting, const std::string &category, const std::string &value) { - CategorySetting s = std::make_pair(category, setting); + CategorySettingValueMap::key_type key = std::make_pair(category, setting); - bool found=false; - try + CategorySettingValueMap::iterator found = mUserSettings.find(key); + if (found != mUserSettings.end()) { - Ogre::ConfigFile::SettingsIterator it = mFile.getSettingsIterator(category); - while (it.hasMoreElements()) - { - Ogre::ConfigFile::SettingsMultiMap::iterator i = it.current(); - - if ((*i).first == setting) - { - if ((*i).second != value) - { - mChangedSettings.push_back(std::make_pair(category, setting)); - (*i).second = value; - } - found = true; - } - - it.getNext(); - } + if (found->second == value) + return; } - catch (Ogre::Exception&) - {} - if (!found) - { - if (mNewSettings.find(s) != mNewSettings.end()) - { - if (mNewSettings[s] != value) - { - mChangedSettings.push_back(std::make_pair(category, setting)); - mNewSettings[s] = value; - } - } - else - { - if (mDefaultFile.getSetting(setting, category) != value) - mChangedSettings.push_back(std::make_pair(category, setting)); - mNewSettings[s] = value; - } - } + mUserSettings[key] = value; + + mChangedSettings.insert(key); } void Manager::setInt (const std::string& setting, const std::string& category, const int value) @@ -159,12 +177,12 @@ void Manager::setInt (const std::string& setting, const std::string& category, c setString(setting, category, Ogre::StringConverter::toString(value)); } -void Manager::setFloat (const std::string& setting, const std::string& category, const float value) +void Manager::setFloat (const std::string &setting, const std::string &category, const float value) { setString(setting, category, Ogre::StringConverter::toString(value)); } -void Manager::setBool (const std::string& setting, const std::string& category, const bool value) +void Manager::setBool(const std::string &setting, const std::string &category, const bool value) { setString(setting, category, Ogre::StringConverter::toString(value)); } @@ -175,3 +193,5 @@ const CategorySettingVector Manager::apply() mChangedSettings.clear(); return vec; } + +} diff --git a/components/settings/settings.hpp b/components/settings/settings.hpp index 03b0b517ca..c16ff5a1ef 100644 --- a/components/settings/settings.hpp +++ b/components/settings/settings.hpp @@ -1,12 +1,14 @@ #ifndef COMPONENTS_SETTINGS_H #define COMPONENTS_SETTINGS_H -#include +#include +#include +#include namespace Settings { typedef std::pair < std::string, std::string > CategorySetting; - typedef std::vector< std::pair > CategorySettingVector; + typedef std::set< std::pair > CategorySettingVector; typedef std::map < CategorySetting, std::string > CategorySettingValueMap; /// @@ -15,15 +17,12 @@ namespace Settings class Manager { public: - static Ogre::ConfigFile mFile; - static Ogre::ConfigFile mDefaultFile; + static CategorySettingValueMap mDefaultSettings; + static CategorySettingValueMap mUserSettings; static CategorySettingVector mChangedSettings; ///< tracks all the settings that were changed since the last apply() call - static CategorySettingValueMap mNewSettings; - ///< tracks all the settings that are in the default file, but not in user file yet - void loadDefault (const std::string& file); ///< load file as the default settings (can be overridden by user settings) From 955505c167800109590f4c56f40c679cef344611 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 01:05:40 +0100 Subject: [PATCH 094/214] Remove unused function --- apps/openmw/engine.cpp | 10 +--------- apps/openmw/engine.hpp | 4 ---- apps/openmw/mwgui/windowmanagerimp.cpp | 5 ++--- apps/openmw/mwgui/windowmanagerimp.hpp | 3 +-- 4 files changed, 4 insertions(+), 18 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a9a7f06324..c70acaba8d 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -170,7 +170,6 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) : mOgre (0) - , mFpsLevel(0) , mVerboseScripts (false) , mSkipMenu (false) , mUseSound (true) @@ -297,8 +296,6 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) if (boost::filesystem::exists(settingspath)) settings.loadUser(settingspath); - mFpsLevel = settings.getInt("fps", "HUD"); - // load nif overrides NifOverrides::Overrides nifOverrides; std::string transparencyOverrides = "/transparency-overrides.cfg"; @@ -373,7 +370,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setInputManager (input); MWGui::WindowManager* window = new MWGui::WindowManager( - mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), + mExtensions, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); mEnvironment.setWindowManager (window); @@ -574,11 +571,6 @@ void OMW::Engine::setSoundUsage(bool soundUsage) mUseSound = soundUsage; } -void OMW::Engine::showFPS(int level) -{ - mFpsLevel = level; -} - void OMW::Engine::setEncoding(const ToUTF8::FromType& encoding) { mEncoding = encoding; diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 079dd922cc..3b088595c0 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -71,7 +71,6 @@ namespace OMW OEngine::Render::OgreRenderer *mOgre; std::string mCellName; std::vector mContentFiles; - int mFpsLevel; bool mVerboseScripts; bool mSkipMenu; bool mUseSound; @@ -151,9 +150,6 @@ namespace OMW */ void addContentFile(const std::string& file); - /// Enable fps counter - void showFPS(int level); - /// Enable or disable verbose script output void setScriptsVerbosity(bool scriptsVerbosity); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a35498deaa..715f47c46e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -96,7 +96,7 @@ namespace MWGui { WindowManager::WindowManager( - const Compiler::Extensions& extensions, int fpsLevel, OEngine::Render::OgreRenderer *ogre, + const Compiler::Extensions& extensions, OEngine::Render::OgreRenderer *ogre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) : mConsoleOnlyScripts(consoleOnlyScripts) @@ -167,7 +167,6 @@ namespace MWGui , mForceHidden(GW_None) , mAllowed(GW_ALL) , mRestAllowed(true) - , mShowFPSLevel(fpsLevel) , mFPS(0.0f) , mTriangleCount(0) , mBatchCount(0) @@ -269,7 +268,7 @@ namespace MWGui trackWindow(mDialogueWindow, "dialogue"); mContainerWindow = new ContainerWindow(mDragAndDrop); trackWindow(mContainerWindow, "container"); - mHud = new HUD(mCustomMarkers, mShowFPSLevel, mDragAndDrop); + mHud = new HUD(mCustomMarkers, Settings::Manager::getInt("fps", "HUD"), mDragAndDrop); mToolTips = new ToolTips(); mScrollWindow = new ScrollWindow(); mBookWindow = new BookWindow(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index b3eb9cd0a9..9f01b136cf 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -97,7 +97,7 @@ namespace MWGui typedef std::pair Faction; typedef std::vector FactionList; - WindowManager(const Compiler::Extensions& extensions, int fpsLevel, + WindowManager(const Compiler::Extensions& extensions, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap); @@ -451,7 +451,6 @@ namespace MWGui void updateVisible(); // Update visibility of all windows based on mode, shown and allowed settings - int mShowFPSLevel; float mFPS; unsigned int mTriangleCount; unsigned int mBatchCount; From ab9100fa904898606cc41f6df706b85a583bc2dc Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 13:12:58 +0100 Subject: [PATCH 095/214] Prevent dropping item on itself in ContentModel (Fixes #2334) Also improves the drop indicator, it is now shown in between items instead of on an item. --- components/contentselector/model/contentmodel.cpp | 7 +++---- components/contentselector/model/contentmodel.hpp | 1 - components/contentselector/view/contentselector.cpp | 3 ++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index b81b1cbf6a..198bbffbb1 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -15,8 +15,7 @@ ContentSelectorModel::ContentModel::ContentModel(QObject *parent, QIcon warningI mMimeType ("application/omwcontent"), mMimeTypes (QStringList() << mMimeType), mColumnCount (1), - mDragDropFlags (Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled), - mDropActions (Qt::CopyAction | Qt::MoveAction) + mDropActions (Qt::MoveAction) { setEncoding ("win1252"); uncheckAll(); @@ -104,7 +103,7 @@ QModelIndex ContentSelectorModel::ContentModel::indexFromItem(const EsmFile *ite Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index) const { if (!index.isValid()) - return Qt::NoItemFlags; + return Qt::ItemIsDropEnabled; const EsmFile *file = item(index.row()); @@ -152,7 +151,7 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index if (gamefileChecked) { if (allDependenciesFound) - returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | mDragDropFlags; + returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled; else returnFlags = Qt::ItemIsSelectable; } diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 2ced40f047..6af5425c77 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -89,7 +89,6 @@ namespace ContentSelectorModel QString mMimeType; QStringList mMimeTypes; int mColumnCount; - Qt::ItemFlags mDragDropFlags; Qt::DropActions mDropActions; }; } diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 2d560e054b..ad023e5b22 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -15,7 +15,8 @@ ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) : QObject(parent) { - ui.setupUi (parent); + ui.setupUi(parent); + ui.addonView->setDragDropMode(QAbstractItemView::InternalMove); buildContentModel(); buildGameFileView(); From 2bf1dd8f46fa3bf19fb5416bc6b269631495a84f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 14:01:31 +0100 Subject: [PATCH 096/214] Make the status badges consistent, again --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1698a7ebc3..ed21b852f5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ 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) +[![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg?style=plastic)](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. From aa6ebcd75cd95c5423b7216759f19cfc6d65224a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Feb 2015 23:43:56 +0100 Subject: [PATCH 097/214] Change stolen items handling to match MW (Fixes #1443, Fixes #2290) --- apps/openmw/mwbase/mechanicsmanager.hpp | 4 +++- apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 24 ++++++++++++++++--- .../mwmechanics/mechanicsmanagerimp.hpp | 4 +++- apps/openmw/mwworld/actiontake.cpp | 2 +- 6 files changed, 30 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 33a2ef1eaa..58f2f6ee53 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -129,7 +129,9 @@ namespace MWBase /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0; /// Utility to check if taking this item is illegal and calling commitCrime if so - virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count) = 0; + /// @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, + int count) = 0; /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) = 0; /// Attempt sleeping in a bed. If this is illegal, call commitCrime. diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 53b1e679a0..579730f42f 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -285,7 +285,7 @@ namespace MWGui if (mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead()) return true; else - MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, count); + MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, mPtr, count); } return true; } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index ae7d60d442..5cb67c048d 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -624,7 +624,7 @@ namespace MWGui throw std::runtime_error("Added item not found"); mDragAndDrop->startDrag(i, mSortModel, mTradeModel, mItemView, count); - MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, count); + MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, MWWorld::Ptr(), count); if (MWBase::Environment::get().getWindowManager()->getSpellWindow()) MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index d52dcb43c2..caa242338c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -936,11 +936,29 @@ namespace MWMechanics commitCrime(ptr, victim, OT_Trespassing); } - void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, int count) + void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container, + int count) { MWWorld::Ptr victim; - if (isAllowedToUse(ptr, item, victim)) - return; + + if (!container.isEmpty()) + { + // Inherit the owner of the container + if (isAllowedToUse(ptr, container, victim)) + return; + } + else + { + if (isAllowedToUse(ptr, item, victim)) + return; + + if (!item.getCellRef().hasContentFile()) + { + // this is a manually placed item, which means it was already stolen + return; + } + } + commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 2f443ad592..79580c0502 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -121,7 +121,9 @@ namespace MWMechanics /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker); /// Utility to check if taking this item is illegal and calling commitCrime if so - virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count); + /// @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, + int count); /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item); /// Attempt sleeping in a bed. If this is illegal, call commitCrime. diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index 548a949819..269d941dc6 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -16,7 +16,7 @@ namespace MWWorld void ActionTake::executeImp (const Ptr& actor) { MWBase::Environment::get().getMechanicsManager()->itemTaken( - actor, getTarget(), getTarget().getRefData().getCount()); + actor, getTarget(), MWWorld::Ptr(), getTarget().getRefData().getCount()); actor.getClass().getContainerStore (actor).add (getTarget(), getTarget().getRefData().getCount(), actor); MWBase::Environment::get().getWorld()->deleteObject (getTarget()); } From 8087a7d920ebd20d63f0b820856a45e795b9ab2c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 00:21:35 +0100 Subject: [PATCH 098/214] Add possibility to dress up corpses (Fixes #2221) --- apps/openmw/mwworld/inventorystore.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 4950be9126..020f9561a5 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -133,12 +133,11 @@ 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.getRefData().getHandle() != "player") - && !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf()) - && !actorPtr.getClass().getCreatureStats(actorPtr).isDead()) + if (actorPtr.getRefData().getHandle() != "player" + && !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf())) { std::string type = itemPtr.getTypeName(); - if ((type == typeid(ESM::Armor).name()) || (type == typeid(ESM::Clothing).name()) || (type == typeid(ESM::Weapon).name())) + if (type == typeid(ESM::Armor).name() || type == typeid(ESM::Clothing).name()) autoEquip(actorPtr); } @@ -234,7 +233,9 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) // ...unless this is a companion, he should always equip items given to him. if (!Misc::StringUtils::ciEqual(test.getCellRef().getOwner(), actor.getCellRef().getRefId()) && (actor.getClass().getScript(actor).empty() || - !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"))) + !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion")) + && !actor.getClass().getCreatureStats(actor).isDead() // Corpses can be dressed up by the player as desired + ) { continue; } @@ -506,8 +507,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor && !(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())) { std::string type = item.getTypeName(); - if (((type == typeid(ESM::Armor).name()) || (type == typeid(ESM::Clothing).name())) - && !actor.getClass().getCreatureStats(actor).isDead()) + if (type == typeid(ESM::Armor).name() || type == typeid(ESM::Clothing).name()) autoEquip(actor); } From f8b4ff300412344c652a104b8d77ecc7aa281b0f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 01:25:37 +0100 Subject: [PATCH 099/214] Documentation fix --- components/terrain/quadtreenode.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index 6265727011..e8392b8e40 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -98,7 +98,6 @@ namespace Terrain DefaultWorld* getTerrain() { return mTerrain; } /// Adjust LODs for the given camera position, possibly splitting up chunks or merging them. - /// @param force Always choose to render this node, even if not the perfect LOD. /// @return Did we (or all of our children) choose to render? bool update (const Ogre::Vector3& cameraPos); @@ -124,7 +123,6 @@ namespace Terrain /// call this method on their children. /// @note Do not call this before World::areLayersLoaded() == true /// @param area area in image space to put the quad - /// @param quads collect quads here so they can be deleted later void prepareForCompositeMap(Ogre::TRect area); /// Create a chunk for this node from the given data. From c1862cbfc28063be922c98f39e2a7489596a7211 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 02:39:47 +0100 Subject: [PATCH 100/214] Clarify documentation for --load-savegame --- README.md | 4 +++- apps/openmw/main.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ed21b852f5..9207c5728d 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,9 @@ Command line options of the blacklist is enabled) --script-blacklist-use [=arg(=1)] (=1) enable script blacklisting - --load-savegame arg load a save game file on game startup + --load-savegame arg load a save game file on game startup + (specify an absolute or relative + filename for this option) --skip-menu [=arg(=1)] (=0) skip main menu on game startup --new-game [=arg(=1)] (=0) run new game sequence (ignored if skip-menu=0) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index b96b90989c..f4875e68a1 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -153,7 +153,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ->default_value(true), "enable script blacklisting") ("load-savegame", bpo::value()->default_value(""), - "load a save game file on game startup") + "load a save game file on game startup (specify an absolute or relative filename for this option)") ("skip-menu", bpo::value()->implicit_value(true) ->default_value(false), "skip main menu on game startup") From 9d9cabf40d1b6fd73c90db416de8c4b9bf980b87 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 6 Feb 2015 12:24:06 +1300 Subject: [PATCH 101/214] Fix: Importer creates a single Content List (Fixes #2345) --- apps/launcher/datafilespage.cpp | 9 ++++++--- apps/launcher/datafilespage.hpp | 4 ++++ apps/launcher/settingspage.cpp | 22 +++++++++++++++++----- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index ff1364b08c..7861894b08 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -20,6 +20,9 @@ #include "utils/textinputdialog.hpp" #include "utils/profilescombobox.hpp" + +const char *Launcher::DataFilesPage::mDefaultContentListName = "Default"; + Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings, Config::LauncherSettings &launcherSettings, QWidget *parent) : mCfgMgr(cfg) , mGameSettings(gameSettings) @@ -48,9 +51,9 @@ void Launcher::DataFilesPage::buildView() ui.deleteProfileButton->setToolTip ("Delete an existing Content List"); //combo box - ui.profilesComboBox->addItem ("Default"); + ui.profilesComboBox->addItem(mDefaultContentListName); ui.profilesComboBox->setPlaceholderText (QString("Select a Content List...")); - ui.profilesComboBox->setCurrentIndex(ui.profilesComboBox->findText(QLatin1String("Default"))); + ui.profilesComboBox->setCurrentIndex(ui.profilesComboBox->findText(QLatin1String(mDefaultContentListName))); // Add the actions to the toolbuttons ui.newProfileButton->setDefaultAction (ui.newProfileAction); @@ -284,7 +287,7 @@ void Launcher::DataFilesPage::updateOkButton(const QString &text) void Launcher::DataFilesPage::checkForDefaultProfile() { //don't allow deleting "Default" profile - bool success = (ui.profilesComboBox->currentText() != "Default"); + bool success = (ui.profilesComboBox->currentText() != mDefaultContentListName); ui.deleteProfileAction->setEnabled (success); ui.profilesComboBox->setEditEnabled (success); diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 73b840c5c8..1e0fc8e7a8 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -58,6 +58,10 @@ namespace Launcher void on_newProfileAction_triggered(); void on_deleteProfileAction_triggered(); + public: + /// Content List that is aways present + const static char *mDefaultContentListName; + private: TextInputDialog *mProfileDialog; diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index ace8f43103..88c60766b7 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -11,6 +11,7 @@ #include #include "utils/textinputdialog.hpp" +#include "datafilespage.hpp" using namespace Process; @@ -198,22 +199,33 @@ void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus if (exitCode != 0 || exitStatus == QProcess::CrashExit) return; - // Re-read the settings in their current state + // Importer may have changed settings, so refresh mMain->reloadSettings(); // Import selected data files from openmw.cfg if (addonsCheckBox->isChecked()) { + // Because we've reloaded settings, the current content list matches content in OpenMW.cfg + QString oldContentListName = mLauncherSettings.getCurrentContentListName(); if (mProfileDialog->exec() == QDialog::Accepted) { - const QString profile(mProfileDialog->lineEdit()->text()); + // remove the current content list to prevent duplication + //... except, not allowed to delete the Default content list + if (oldContentListName.compare(DataFilesPage::mDefaultContentListName) != 0) + { + mLauncherSettings.removeContentList(oldContentListName); + } + + const QString newContentListName(mProfileDialog->lineEdit()->text()); const QStringList files(mGameSettings.getContentList()); - mLauncherSettings.setCurrentContentListName(profile); - mLauncherSettings.setContentList(profile, files); + mLauncherSettings.setCurrentContentListName(newContentListName); + mLauncherSettings.setContentList(newContentListName, files); + + // Make DataFiles Page load the new content list. + mMain->reloadSettings(); } } - mMain->reloadSettings(); importerButton->setEnabled(true); } From cac250a90d213d33e0560b0b49da1b17c790bba0 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 6 Feb 2015 12:45:15 +1300 Subject: [PATCH 102/214] Fixed typo in comment. --- apps/launcher/datafilespage.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 1e0fc8e7a8..d25d20fc9e 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -59,7 +59,7 @@ namespace Launcher void on_deleteProfileAction_triggered(); public: - /// Content List that is aways present + /// Content List that is always present const static char *mDefaultContentListName; private: From bea88c3643b78ddf81dbb50a367688b2b16589f9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 21:18:43 +0100 Subject: [PATCH 103/214] Stolen item tracking overhaul part 2 (Fixes #2338) --- apps/openmw/mwbase/mechanicsmanager.hpp | 12 +- apps/openmw/mwclass/container.cpp | 9 +- apps/openmw/mwclass/creature.cpp | 5 +- apps/openmw/mwclass/npc.cpp | 6 +- apps/openmw/mwgui/enchantingdialog.cpp | 3 +- apps/openmw/mwgui/inventoryitemmodel.cpp | 11 +- apps/openmw/mwgui/itemmodel.hpp | 13 +- apps/openmw/mwgui/tooltips.cpp | 10 ++ apps/openmw/mwgui/tradeitemmodel.cpp | 4 +- apps/openmw/mwgui/tradewindow.cpp | 5 +- .../mwmechanics/mechanicsmanagerimp.cpp | 120 +++++++++++++++--- .../mwmechanics/mechanicsmanagerimp.hpp | 20 ++- apps/openmw/mwstate/statemanagerimp.cpp | 1 + apps/openmw/mwworld/cellref.cpp | 9 ++ apps/openmw/mwworld/cellref.hpp | 2 + apps/openmw/mwworld/class.hpp | 2 + apps/openmw/mwworld/containerstore.cpp | 53 ++++---- apps/openmw/mwworld/containerstore.hpp | 8 +- apps/openmw/mwworld/worldimp.cpp | 14 +- components/CMakeLists.txt | 2 +- components/esm/defs.hpp | 1 + components/esm/stolenitems.cpp | 47 +++++++ components/esm/stolenitems.hpp | 24 ++++ 23 files changed, 289 insertions(+), 92 deletions(-) create mode 100644 components/esm/stolenitems.cpp create mode 100644 components/esm/stolenitems.hpp diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 58f2f6ee53..f7fc515f57 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -138,9 +138,6 @@ namespace MWBase /// @return was it illegal, and someone saw you doing it? virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed) = 0; - /// @return is \a ptr allowed to take/use \a item or is it a crime? - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim) = 0; - enum PersuasionType { PT_Admire, @@ -205,6 +202,15 @@ namespace MWBase virtual void keepPlayerAlive() = 0; virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0; + + virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer) = 0; + + /// List the owners that the player has stolen this item from (the owner can be an NPC or a faction). + /// + virtual std::vector > getStolenItemOwners(const std::string& itemid) = 0; + + /// Has the player stolen this item from the given owner? + virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; }; } diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index c6a7bbf741..5f49a74b6c 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -59,8 +59,10 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); + // setting ownership not needed, since taking items from a container inherits the + // container's owner automatically data->mContainerStore.fill( - ref->mBase->mInventory, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank(), MWBase::Environment::get().getWorld()->getStore()); + ref->mBase->mInventory, ""); // store ptr.getRefData().setCustomData (data.release()); @@ -82,7 +84,10 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank()); + + // setting ownership not needed, since taking items from a container inherits the + // container's owner automatically + store.restock(list, ptr, ""); } void Container::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index df3f9c0d30..e44f4ffc12 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -139,8 +139,7 @@ namespace MWClass // store ptr.getRefData().setCustomData(data.release()); - getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr), "", -1, - MWBase::Environment::get().getWorld()->getStore()); + getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr)); if (ref->mBase->mFlags & ESM::Creature::Weapon) getInventoryStore(ptr).autoEquip(ptr); @@ -886,7 +885,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().getRefId(), "", -1); + store.restock(list, ptr, ptr.getCellRef().getRefId()); } int Creature::getBaseFightRating(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c55f81d91c..cedff12918 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -384,8 +384,8 @@ namespace MWClass } // inventory - data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr), "", -1, - MWBase::Environment::get().getWorld()->getStore()); + // setting ownership is used to make the NPC auto-equip his initial equipment only, and not bartered items + data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr)); data->mNpcStats.setGoldPool(gold); @@ -1328,7 +1328,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().getRefId(), "", -1); + store.restock(list, ptr, ptr.getCellRef().getRefId()); } int Npc::getBaseFightRating (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 3376858c1c..43f2493a98 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -339,7 +339,8 @@ namespace MWGui for (int i=0; i<2; ++i) { MWWorld::Ptr item = (i == 0) ? mEnchanting.getOldItem() : mEnchanting.getGem(); - if (Misc::StringUtils::ciEqual(item.getCellRef().getOwner(), mPtr.getCellRef().getRefId())) + if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(item.getCellRef().getRefId(), + mPtr.getCellRef().getRefId())) { std::string msg = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage49")->getString(); if (msg.find("%s") != std::string::npos) diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index cee0dc6eed..e8354b7406 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -65,16 +65,7 @@ MWWorld::Ptr InventoryItemModel::moveItem(const ItemStack &item, size_t count, I if (item.mFlags & ItemStack::Flag_Bound) return MWWorld::Ptr(); - bool setNewOwner = false; - - // Are you dead? Then you wont need that anymore - if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead() - // Make sure that the item is actually owned by the dead actor - // Prevents a potential exploit for resetting the owner of any item, by placing the item in a corpse - && Misc::StringUtils::ciEqual(item.mBase.getCellRef().getOwner(), mActor.getCellRef().getRefId())) - setNewOwner = true; - - MWWorld::Ptr ret = otherModel->copyItem(item, count, setNewOwner); + MWWorld::Ptr ret = otherModel->copyItem(item, count, false); removeItem(item, count); return ret; } diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index c1b243a761..53c7018e22 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -46,20 +46,27 @@ namespace MWGui ItemModel(); virtual ~ItemModel() {} - typedef int ModelIndex; + typedef int ModelIndex; // -1 means invalid index + /// Throws for invalid index or out of range index virtual ItemStack getItem (ModelIndex index) = 0; - ///< throws for invalid index + + /// The number of items in the model, this specifies the range of indices you can pass to + /// the getItem function (but this range is only valid until the next call to update()) virtual size_t getItemCount() = 0; + /// Returns an invalid index if the item was not found virtual ModelIndex getIndex (ItemStack item) = 0; + /// Rebuild the item model, this will invalidate existing model indices virtual void update() = 0; /// Move items from this model to \a otherModel. + /// @note Derived implementations may return an empty Ptr if the move was unsuccessful. virtual MWWorld::Ptr moveItem (const ItemStack& item, size_t count, ItemModel* otherModel); - /// @param setNewOwner Set the copied item's owner to the actor we are copying to, or keep the original owner? + /// @param setNewOwner If true, set the copied item's owner to the actor we are copying to, + /// otherwise reset owner to "" virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false) = 0; virtual void removeItem (const ItemStack& item, size_t count) = 0; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 2750717372..c6210ac642 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -13,6 +13,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -586,6 +587,15 @@ namespace MWGui ret += getMiscString(cellref.getFaction(), "Faction"); if (cellref.getFactionRank() > 0) ret += getValueString(cellref.getFactionRank(), "Rank"); + + std::vector > itemOwners = + MWBase::Environment::get().getMechanicsManager()->getStolenItemOwners(cellref.getRefId()); + + for (std::vector >::const_iterator it = itemOwners.begin(); it != itemOwners.end(); ++it) + { + ret += std::string("\nStolen ") + MyGUI::utility::toString(it->second) + " from " + it->first; + } + ret += getMiscString(cellref.getGlobalVariable(), "Global"); return ret; } diff --git a/apps/openmw/mwgui/tradeitemmodel.cpp b/apps/openmw/mwgui/tradeitemmodel.cpp index df0cbcac95..a5a2b3e881 100644 --- a/apps/openmw/mwgui/tradeitemmodel.cpp +++ b/apps/openmw/mwgui/tradeitemmodel.cpp @@ -135,11 +135,9 @@ namespace MWGui if (i == sourceModel->getItemCount()) throw std::runtime_error("The borrowed item disappeared"); - // reset owner while copying, but only for items bought by the player - bool setNewOwner = (mMerchant.isEmpty()); const ItemStack& item = sourceModel->getItem(i); // copy the borrowed items to our model - copyItem(item, it->mCount, setNewOwner); + copyItem(item, it->mCount); // then remove them from the source model sourceModel->removeItem(item, it->mCount); } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index fab7c63a6c..87b2362efa 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -300,7 +300,8 @@ namespace MWGui // check if the player is attempting to sell back an item stolen from this actor for (std::vector::iterator it = merchantBought.begin(); it != merchantBought.end(); ++it) { - if (Misc::StringUtils::ciEqual(it->mBase.getCellRef().getOwner(), mPtr.getCellRef().getRefId())) + if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(it->mBase.getCellRef().getRefId(), + mPtr.getCellRef().getRefId())) { std::string msg = gmst.find("sNotifyMessage49")->getString(); if (msg.find("%s") != std::string::npos) @@ -315,6 +316,8 @@ namespace MWGui } } + // TODO: move to mwmechanics + // Is the player buying? bool buying = (mCurrentMerchantOffer < 0); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index caa242338c..4e4a1a8a69 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -2,6 +2,8 @@ #include "mechanicsmanagerimp.hpp" #include "npcstats.hpp" +#include + #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" @@ -873,31 +875,31 @@ namespace MWMechanics mAI = true; } - bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim) + bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim) { - const std::string& owner = item.getCellRef().getOwner(); + const std::string& owner = cellref.getOwner(); bool isOwned = !owner.empty() && owner != "player"; - const std::string& faction = item.getCellRef().getFaction(); + const std::string& faction = cellref.getFaction(); bool isFactionOwned = false; if (!faction.empty() && ptr.getClass().isNpc()) { const std::map& factions = ptr.getClass().getNpcStats(ptr).getFactionRanks(); std::map::const_iterator found = factions.find(Misc::StringUtils::lowerCase(faction)); if (found == factions.end() - || found->second < item.getCellRef().getFactionRank()) + || found->second < cellref.getFactionRank()) isFactionOwned = true; } - const std::string& globalVariable = item.getCellRef().getGlobalVariable(); + const std::string& globalVariable = cellref.getGlobalVariable(); if (!globalVariable.empty() && MWBase::Environment::get().getWorld()->getGlobalInt(Misc::StringUtils::lowerCase(globalVariable)) == 1) { isOwned = false; isFactionOwned = false; } - if (!item.getCellRef().getOwner().empty()) - victim = MWBase::Environment::get().getWorld()->searchPtr(item.getCellRef().getOwner(), true); + if (!cellref.getOwner().empty()) + victim = MWBase::Environment::get().getWorld()->searchPtr(cellref.getOwner(), true); return (!isOwned && !isFactionOwned); } @@ -916,7 +918,7 @@ namespace MWMechanics } MWWorld::Ptr victim; - if (isAllowedToUse(ptr, bed, victim)) + if (isAllowedToUse(ptr, bed.getCellRef(), victim)) return false; if(commitCrime(ptr, victim, OT_SleepingInOwnedBed)) @@ -931,27 +933,82 @@ namespace MWMechanics void MechanicsManager::objectOpened(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item) { MWWorld::Ptr victim; - if (isAllowedToUse(ptr, item, victim)) + if (isAllowedToUse(ptr, item.getCellRef(), victim)) return; commitCrime(ptr, victim, OT_Trespassing); } + std::vector > MechanicsManager::getStolenItemOwners(const std::string& itemid) + { + std::vector > result; + StolenItemsMap::const_iterator it = mStolenItems.find(Misc::StringUtils::lowerCase(itemid)); + if (it == mStolenItems.end()) + return result; + else + { + const OwnerMap& owners = it->second; + for (OwnerMap::const_iterator ownerIt = owners.begin(); ownerIt != owners.end(); ++ownerIt) + result.push_back(std::make_pair(ownerIt->first.first, ownerIt->second)); + return result; + } + } + + bool MechanicsManager::isItemStolenFrom(const std::string &itemid, const std::string &ownerid) + { + StolenItemsMap::const_iterator it = mStolenItems.find(Misc::StringUtils::lowerCase(itemid)); + if (it == mStolenItems.end()) + return false; + const OwnerMap& owners = it->second; + OwnerMap::const_iterator ownerFound = owners.find(std::make_pair(Misc::StringUtils::lowerCase(ownerid), false)); + return ownerFound != owners.end(); + } + + void MechanicsManager::confiscateStolenItems(const MWWorld::Ptr &player, const MWWorld::Ptr &targetContainer) + { + MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); + for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) + { + StolenItemsMap::iterator stolenIt = mStolenItems.find(Misc::StringUtils::lowerCase(it->getClass().getId(*it))); + if (stolenIt == mStolenItems.end()) + continue; + OwnerMap& owners = stolenIt->second; + int itemCount = it->getRefData().getCount(); + for (OwnerMap::iterator ownerIt = owners.begin(); ownerIt != owners.end();) + { + int toRemove = std::min(itemCount, ownerIt->second); + itemCount -= toRemove; + ownerIt->second -= toRemove; + if (ownerIt->second == 0) + owners.erase(ownerIt++); + else + ++ownerIt; + } + + int toMove = it->getRefData().getCount() - itemCount; + + targetContainer.getClass().getContainerStore(targetContainer).add(*it, toMove, targetContainer); + store.remove(*it, toMove, player); + } + // TODO: unhardcode the locklevel + targetContainer.getClass().lock(targetContainer,50); + } + void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container, int count) { + if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + MWWorld::Ptr victim; + const MWWorld::CellRef* ownerCellRef = &item.getCellRef(); if (!container.isEmpty()) { // Inherit the owner of the container - if (isAllowedToUse(ptr, container, victim)) - return; + ownerCellRef = &container.getCellRef(); } else { - if (isAllowedToUse(ptr, item, victim)) - return; - if (!item.getCellRef().hasContentFile()) { // this is a manually placed item, which means it was already stolen @@ -959,6 +1016,20 @@ namespace MWMechanics } } + if (isAllowedToUse(ptr, *ownerCellRef, victim)) + return; + + Owner owner; + owner.first = ownerCellRef->getOwner(); + owner.second = false; + if (owner.first.empty()) + { + owner.first = ownerCellRef->getFaction(); + owner.second = true; + } + Misc::StringUtils::toLower(owner.first); + mStolenItems[Misc::StringUtils::lowerCase(item.getClass().getId(item))][owner] += count; + commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } @@ -967,7 +1038,7 @@ namespace MWMechanics // NOTE: victim may be empty // Only player can commit crime - if (player.getRefData().getHandle() != "player") + if (player != MWBase::Environment::get().getWorld()->getPlayerPtr()) return false; // Find all the actors within the alarm radius @@ -1369,22 +1440,37 @@ namespace MWMechanics int MechanicsManager::countSavedGameRecords() const { - return 1; // Death counter + return 1 // Death counter + +1; // Stolen items } void MechanicsManager::write(ESM::ESMWriter &writer, Loading::Listener &listener) const { mActors.write(writer, listener); + + ESM::StolenItems items; + items.mStolenItems = mStolenItems; + writer.startRecord(ESM::REC_STLN); + items.write(writer); + writer.endRecord(ESM::REC_STLN); } void MechanicsManager::readRecord(ESM::ESMReader &reader, uint32_t type) { - mActors.readRecord(reader, type); + if (type == ESM::REC_STLN) + { + ESM::StolenItems items; + items.load(reader); + mStolenItems = items.mStolenItems; + } + else + mActors.readRecord(reader, type); } void MechanicsManager::clear() { mActors.clear(); + mStolenItems.clear(); } bool MechanicsManager::isAggressive(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 79580c0502..d08334ae8c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -35,6 +35,11 @@ namespace MWMechanics Objects mObjects; Actors mActors; + typedef std::pair Owner; // < Owner id, bool isFaction > + typedef std::map OwnerMap; // < Owner, number of stolen items with this id from this owner > + typedef std::map StolenItemsMap; + StolenItemsMap mStolenItems; + public: void buildPlayer(); @@ -130,9 +135,6 @@ namespace MWMechanics /// @return was it illegal, and someone saw you doing it? Also returns fail when enemies are nearby virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed); - /// @return is \a ptr allowed to take/use \a item or is it a crime? - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim); - virtual void forceStateUpdate(const MWWorld::Ptr &ptr); virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); @@ -170,9 +172,21 @@ namespace MWMechanics virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const; + virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer); + + /// List the owners that the player has stolen this item from (the owner can be an NPC or a faction). + /// + virtual std::vector > getStolenItemOwners(const std::string& itemid); + + /// Has the player stolen this item from the given owner? + virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); + 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); }; } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index d623ba4654..0883bc63b3 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -421,6 +421,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str break; case ESM::REC_DCOU: + case ESM::REC_STLN: MWBase::Environment::get().getMechanicsManager()->readRecord(reader, n.val); break; diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index d2cced3b86..0d81e06368 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -117,6 +117,15 @@ namespace MWWorld return mCellRef.mGlobalVariable; } + void CellRef::resetGlobalVariable() + { + if (!mCellRef.mGlobalVariable.empty()) + { + mChanged = true; + mCellRef.mGlobalVariable.erase(); + } + } + void CellRef::setFactionRank(int factionRank) { if (factionRank != mCellRef.mFactionRank) diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index f063b27272..b8e85f286e 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -75,6 +75,8 @@ namespace MWWorld // Used by bed rent scripts to allow the player to use the bed for the duration of the rent. std::string getGlobalVariable() const; + void resetGlobalVariable(); + // ID of creature trapped in this soul gem std::string getSoul() const; void setSoul(const std::string& soul); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 751375c556..380d2a34b5 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -80,6 +80,8 @@ namespace MWWorld virtual std::string getId (const Ptr& ptr) const; ///< Return ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) + /// @note This function is currently redundant; the same ID can be retrieved by CellRef::getRefId. + /// Leaving it here for now in case we want to optimize later. virtual void insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const; virtual void insertObject(const Ptr& ptr, const std::string& mesh, MWWorld::PhysicsSystem& physics) const; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index b21486c2cc..c2906e4474 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -222,29 +222,22 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr MWWorld::ContainerStoreIterator it = end(); - if (setOwner && actorPtr.getClass().isActor()) + // 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 { - // 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 (actorPtr == player) - { - // No point in setting owner to the player - NPCs will not respect this anyway - // Additionally, setting it to "player" would make those items not stack with items that don't have an owner - itemPtr.getCellRef().setOwner(""); - } - else - itemPtr.getCellRef().setOwner(actorPtr.getCellRef().getRefId()); - - it = addImp(itemPtr, count); - - itemPtr.getCellRef().setOwner(oldOwner); + itemPtr.getCellRef().setOwner(""); } else { - it = addImp(itemPtr, count); + itemPtr.getCellRef().setOwner(actorPtr.getCellRef().getRefId()); } + it = addImp(itemPtr, count); + + itemPtr.getCellRef().setOwner(oldOwner); + // The copy of the original item we just made MWWorld::Ptr item = *it; @@ -258,6 +251,14 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr pos.pos[1] = 0; pos.pos[2] = 0; item.getCellRef().setPosition(pos); + + // reset ownership stuff, owner was already handled above + item.getCellRef().resetGlobalVariable(); + item.getCellRef().setFaction(""); + item.getCellRef().setFactionRank(-1); + + // must reset the RefNum on the copied item, so that the RefNum on the original item stays unique + // maybe we should do this in the copy constructor instead? item.getCellRef().unsetRefNum(); // destroy link to content file std::string script = item.getClass().getScript(item); @@ -399,19 +400,19 @@ int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor return count - toRemove; } -void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, int factionRank, const MWWorld::ESMStore& store) +void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner) { for (std::vector::const_iterator iter (items.mList.begin()); iter!=items.mList.end(); ++iter) { std::string id = Misc::StringUtils::lowerCase(iter->mItem.toString()); - addInitialItem(id, owner, faction, factionRank, iter->mCount); + addInitialItem(id, owner, iter->mCount); } flagAsModified(); } -void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int factionRank, +void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel, const std::string& levItem) { ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); @@ -423,7 +424,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: if (topLevel && std::abs(count) > 1 && levItem->mFlags & ESM::ItemLevList::Each) { for (int i=0; i 0 ? 1 : -1, true, levItem->mId); + addInitialItem(id, owner, count > 0 ? 1 : -1, true, levItem->mId); return; } else @@ -431,7 +432,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: std::string id = MWMechanics::getLevelledItem(ref.getPtr().get()->mBase, false); if (id.empty()) return; - addInitialItem(id, owner, faction, factionRank, count, false, levItem->mId); + addInitialItem(id, owner, count, false, levItem->mId); } } else @@ -447,13 +448,11 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: count = std::abs(count); ref.getPtr().getCellRef().setOwner(owner); - ref.getPtr().getCellRef().setFaction(faction); - ref.getPtr().getCellRef().setFactionRank(factionRank); addImp (ref.getPtr(), count); } } -void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction, int factionRank) +void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner) { // Remove the items already spawned by levelled items that will restock for (std::map::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) @@ -472,13 +471,13 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW if (MWBase::Environment::get().getWorld()->getStore().get().search(it->mItem.toString())) { - addInitialItem(item, owner, faction, factionRank, it->mCount, true); + addInitialItem(item, owner, it->mCount, true); } else { int currentCount = count(item); if (currentCount < std::abs(it->mCount)) - addInitialItem(item, owner, faction, factionRank, std::abs(it->mCount) - currentCount, true); + addInitialItem(item, owner, std::abs(it->mCount) - currentCount, true); } } flagAsModified(); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index d909a98ccf..e9750a6228 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -75,7 +75,7 @@ namespace MWWorld mutable float mCachedWeight; mutable bool mWeightUpToDate; ContainerStoreIterator addImp (const Ptr& ptr, int count); - void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int factionRank, int count, bool topLevel=true, const std::string& levItem = ""); + void addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel=true, const std::string& levItem = ""); template ContainerStoreIterator getState (CellRefList& collection, @@ -112,7 +112,7 @@ namespace MWWorld /// \attention Do not add items to an existing stack by increasing the count instead of /// calling this function! /// - /// @param setOwner Set the owner of the added item to \a actorPtr? + /// @param setOwner Set the owner of the added item to \a actorPtr? If false, the owner is reset to "". /// /// @return if stacking happened, return iterator to the item that was stacked against, otherwise iterator to the newly inserted item. @@ -151,10 +151,10 @@ namespace MWWorld virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2); ///< @return true if the two specified objects can stack with each other - void fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, int factionRank, const MWWorld::ESMStore& store); + void fill (const ESM::InventoryList& items, const std::string& owner); ///< Insert items into *this. - void restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction, int factionRank); + void restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner); virtual void clear(); ///< Empty container. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1036d8ce6a..933a1fa428 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2980,18 +2980,10 @@ namespace MWWorld if (!closestChest.isEmpty()) //Found a close chest { - ContainerStore& store = ptr.getClass().getContainerStore(ptr); - for (ContainerStoreIterator it = store.begin(); it != store.end(); ++it) //Move all stolen stuff into chest - { - MWWorld::Ptr dummy; - if (!MWBase::Environment::get().getMechanicsManager()->isAllowedToUse(getPlayerPtr(), *it, dummy)) - { - closestChest.getClass().getContainerStore(closestChest).add(*it, it->getRefData().getCount(), closestChest); - store.remove(*it, it->getRefData().getCount(), ptr); - } - } - closestChest.getClass().lock(closestChest,50); + MWBase::Environment::get().getMechanicsManager()->confiscateStolenItems(ptr, closestChest); } + else + std::cerr << "Failed to confiscate items: no stolen_goods container found" << std::endl; } void World::goToJail() diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 814dde6a29..6f8352ddbb 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -63,7 +63,7 @@ add_component_dir (esm loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile - aisequence magiceffects util custommarkerstate + aisequence magiceffects util custommarkerstate stolenitems ) add_component_dir (esmterrain diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 60926d562d..7ef8102c29 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -117,6 +117,7 @@ enum RecNameInts REC_MARK = FourCC<'M','A','R','K'>::value, REC_ENAB = FourCC<'E','N','A','B'>::value, REC_CAM_ = FourCC<'C','A','M','_'>::value, + REC_STLN = FourCC<'S','T','L','N'>::value, // format 1 REC_FILT = FourCC<'F','I','L','T'>::value, diff --git a/components/esm/stolenitems.cpp b/components/esm/stolenitems.cpp new file mode 100644 index 0000000000..c51b0b99b0 --- /dev/null +++ b/components/esm/stolenitems.cpp @@ -0,0 +1,47 @@ +#include "stolenitems.hpp" + +#include +#include + +namespace ESM +{ + + void StolenItems::write(ESMWriter &esm) const + { + for (StolenItemsMap::const_iterator it = mStolenItems.begin(); it != mStolenItems.end(); ++it) + { + esm.writeHNString("NAME", it->first); + for (std::map, int>::const_iterator ownerIt = it->second.begin(); + ownerIt != it->second.end(); ++ownerIt) + { + if (ownerIt->first.second) + esm.writeHNString("FNAM", ownerIt->first.first); + else + esm.writeHNString("ONAM", ownerIt->first.first); + esm.writeHNT("COUN", ownerIt->second); + } + } + } + + void StolenItems::load(ESMReader &esm) + { + while (esm.isNextSub("NAME")) + { + std::string itemid = esm.getHString(); + + std::map, int> ownerMap; + while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM")) + { + std::string subname = esm.retSubName().toString(); + std::string owner = esm.getHString(); + bool isFaction = (subname == "FNAM"); + int count; + esm.getHNT(count, "COUN"); + ownerMap.insert(std::make_pair(std::make_pair(owner, isFaction), count)); + } + + mStolenItems[itemid] = ownerMap; + } + } + +} diff --git a/components/esm/stolenitems.hpp b/components/esm/stolenitems.hpp new file mode 100644 index 0000000000..928fbbf757 --- /dev/null +++ b/components/esm/stolenitems.hpp @@ -0,0 +1,24 @@ +#ifndef OPENMW_COMPONENTS_ESM_STOLENITEMS_H +#define OPENMW_COMPONENTS_ESM_STOLENITEMS_H + +#include +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + struct StolenItems + { + typedef std::map, int> > StolenItemsMap; + StolenItemsMap mStolenItems; + + void load(ESM::ESMReader& esm); + void write(ESM::ESMWriter& esm) const; + }; + +} + +#endif From 356d1c7657124ccad4987a78fb0672e379909070 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 22:10:58 +0100 Subject: [PATCH 104/214] ESSImport: convert stolen item tracker --- apps/essimporter/converter.hpp | 35 ++++++++++++++++++++++++++++++---- apps/openmw/mwgui/tooltips.cpp | 2 +- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 7759956058..c23083f8e9 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "importcrec.hpp" #include "importcntc.hpp" @@ -387,24 +388,50 @@ public: virtual void read(ESM::ESMReader &esm) { std::string itemid = esm.getHNString("NAME"); + Misc::StringUtils::toLower(itemid); while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM")) { if (esm.retSubName().toString() == "FNAM") { std::string factionid = esm.getHString(); - mFactionStolenItems.insert(std::make_pair(itemid, factionid)); + mStolenItems[itemid].insert(std::make_pair(Misc::StringUtils::lowerCase(factionid), true)); } else { std::string ownerid = esm.getHString(); - mStolenItems.insert(std::make_pair(itemid, ownerid)); + mStolenItems[itemid].insert(std::make_pair(Misc::StringUtils::lowerCase(ownerid), false)); } } } + virtual void write(ESM::ESMWriter &esm) + { + ESM::StolenItems items; + for (std::map >::const_iterator it = mStolenItems.begin(); it != mStolenItems.end(); ++it) + { + std::map, int> owners; + for (std::set::const_iterator ownerIt = it->second.begin(); ownerIt != it->second.end(); ++ownerIt) + { + owners.insert(std::make_pair(std::make_pair(ownerIt->first, ownerIt->second) + // Since OpenMW doesn't suffer from the owner contamination bug, + // it needs a count argument. But for legacy savegames, we don't know + // this count, so must assume all items of that ID are stolen, + // like vanilla MW did. + ,std::numeric_limits::max())); + } + + items.mStolenItems.insert(std::make_pair(it->first, owners)); + } + + esm.startRecord(ESM::REC_STLN); + items.write(esm); + esm.endRecord(ESM::REC_STLN); + } + private: - std::multimap mStolenItems; - std::multimap mFactionStolenItems; + typedef std::pair Owner; // + + std::map > mStolenItems; }; /// Seen responses for a dialogue topic? diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index c6210ac642..2c10004a63 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -593,7 +593,7 @@ namespace MWGui for (std::vector >::const_iterator it = itemOwners.begin(); it != itemOwners.end(); ++it) { - ret += std::string("\nStolen ") + MyGUI::utility::toString(it->second) + " from " + it->first; + ret += std::string("\nStolen from ") + it->first; } ret += getMiscString(cellref.getGlobalVariable(), "Global"); From dd8aab2a7ff2597d1665dfefc2d2773a2fa71d23 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 22:17:30 +0100 Subject: [PATCH 105/214] Adjust help for --load-savegame again --- README.md | 5 +++-- apps/openmw/main.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9207c5728d..63a3138960 100644 --- a/README.md +++ b/README.md @@ -69,8 +69,9 @@ Command line options --script-blacklist-use [=arg(=1)] (=1) enable script blacklisting --load-savegame arg load a save game file on game startup - (specify an absolute or relative - filename for this option) + (specify an absolute filename or a + filename relative to the current + working directory) --skip-menu [=arg(=1)] (=0) skip main menu on game startup --new-game [=arg(=1)] (=0) run new game sequence (ignored if skip-menu=0) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index f4875e68a1..475fe63a2d 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -153,7 +153,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ->default_value(true), "enable script blacklisting") ("load-savegame", bpo::value()->default_value(""), - "load a save game file on game startup (specify an absolute or relative filename for this option)") + "load a save game file on game startup (specify an absolute filename or a filename relative to the current working directory)") ("skip-menu", bpo::value()->implicit_value(true) ->default_value(false), "skip main menu on game startup") From ae77eacd7ea5f3ef5766138178d73345256f2b6e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 23:15:12 +0100 Subject: [PATCH 106/214] Skill progress refactoring --- apps/openmw/mwgui/statswindow.cpp | 6 ++- apps/openmw/mwmechanics/npcstats.cpp | 54 +++++++++++------------- apps/openmw/mwmechanics/npcstats.hpp | 6 +-- apps/openmw/mwscript/statsextensions.cpp | 17 -------- 4 files changed, 31 insertions(+), 52 deletions(-) diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index a407aedc72..f624d751d9 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -383,11 +383,15 @@ namespace MWGui const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second; int base = stat.getBase(); int modified = stat.getModified(); - int progressPercent = stat.getProgress() * 100; + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); + int progressRequirement = player.getClass().getNpcStats(player).getSkillProgressRequirement(skillId, + *esmStore.get().find(player.get()->mBase->mClass)); + int progressPercent = int(int(stat.getProgress()) / float(progressRequirement) * 100.f); + const ESM::Skill* skill = esmStore.get().find(skillId); std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 7219d6185a..bd1cd55721 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -125,32 +125,9 @@ bool MWMechanics::NpcStats::isInFaction (const std::string& faction) const return (mFactionRank.find(Misc::StringUtils::lowerCase(faction)) != mFactionRank.end()); } -float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& class_, int usageType, - int level, float extraFactor) const +float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const ESM::Class& class_) const { - if (level<0) - level = static_cast (getSkill (skillIndex).getBase()); - - const ESM::Skill *skill = - MWBase::Environment::get().getWorld()->getStore().get().find (skillIndex); - - float skillFactor = 1; - - if (usageType>=4) - throw std::runtime_error ("skill usage type out of range"); - - if (usageType>=0) - { - skillFactor = skill->mData.mUseValue[usageType]; - - if (skillFactor<0) - throw std::runtime_error ("invalid skill gain factor"); - - if (skillFactor==0) - return 0; - } - - skillFactor *= extraFactor; + float progressRequirement = 1 + getSkill (skillIndex).getBase(); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -173,11 +150,15 @@ float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& cla break; } + progressRequirement *= typeFactor; + if (typeFactor<=0) throw std::runtime_error ("invalid skill type factor"); float specialisationFactor = 1; + const ESM::Skill *skill = + MWBase::Environment::get().getWorld()->getStore().get().find (skillIndex); if (skill->mData.mSpecialization==class_.mData.mSpecialization) { specialisationFactor = gmst.find ("fSpecialSkillBonus")->getFloat(); @@ -185,7 +166,9 @@ float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& cla if (specialisationFactor<=0) throw std::runtime_error ("invalid skill specialisation factor"); } - return 1.0 / ((level+1) * (1.0/skillFactor) * typeFactor * specialisationFactor); + progressRequirement *= specialisationFactor; + + return progressRequirement; } void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, int usageType, float extraFactor) @@ -194,11 +177,24 @@ void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, if(mIsWerewolf) return; + const ESM::Skill *skill = + MWBase::Environment::get().getWorld()->getStore().get().find (skillIndex); + float skillGain = 1; + if (usageType>=4) + throw std::runtime_error ("skill usage type out of range"); + if (usageType>=0) + { + skillGain = skill->mData.mUseValue[usageType]; + if (skillGain<0) + throw std::runtime_error ("invalid skill gain factor"); + } + skillGain *= extraFactor; + MWMechanics::SkillValue& value = getSkill (skillIndex); - value.setProgress(value.getProgress() + getSkillGain (skillIndex, class_, usageType, -1, extraFactor)); + value.setProgress(value.getProgress() + skillGain); - if (value.getProgress()>=1) + if (int(value.getProgress())>=int(getSkillProgressRequirement(skillIndex, class_))) { // skill levelled up increaseSkill(skillIndex, class_, false); @@ -256,7 +252,7 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}", MWGui::ShowInDialogueMode_Never); } - getSkill (skillIndex).setBase (base); + getSkill(skillIndex).setBase (base); if (!preserveProgress) getSkill(skillIndex).setProgress(0); } diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index fc4f297db0..1cb62276fe 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -74,11 +74,7 @@ namespace MWMechanics bool isInFaction (const std::string& faction) const; - float getSkillGain (int skillIndex, const ESM::Class& class_, int usageType = -1, - int level = -1, float extraFactor=1.f) const; - ///< \param usageType: Usage specific factor, specified in the respective skill record; - /// -1: use a factor of 1.0 instead. - /// \param level Level to base calculation on; -1: use current level. + float getSkillProgressRequirement (int skillIndex, const ESM::Class& class_) const; void useSkill (int skillIndex, const ESM::Class& class_, int usageType = -1, float extraFactor=1.f); ///< Increase skill by usage. diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index f0cf12e5ea..abef636ccf 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -348,29 +348,12 @@ namespace MWScript MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats (ptr); - MWWorld::LiveCellRef *ref = ptr.get(); - - assert (ref); - - const ESM::Class& class_ = - *MWBase::Environment::get().getWorld()->getStore().get().find (ref->mBase->mClass); - - float level = stats.getSkill(mIndex).getBase(); - float progress = stats.getSkill(mIndex).getProgress(); - int newLevel = value - (stats.getSkill(mIndex).getModified() - stats.getSkill(mIndex).getBase()); if (newLevel<0) newLevel = 0; - progress = (progress / stats.getSkillGain (mIndex, class_, -1, level)) - * stats.getSkillGain (mIndex, class_, -1, newLevel); - - if (progress>=1) - progress = 0.999999999; - stats.getSkill (mIndex).setBase (newLevel); - stats.getSkill (mIndex).setProgress(progress); } }; From f0b1d889c0f9f054207b07194f583f6a355d336e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 23:24:49 +0100 Subject: [PATCH 107/214] ESSImport: import player skill progress --- apps/essimporter/convertplayer.cpp | 5 ++--- apps/openmw/mwmechanics/npcstats.hpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/essimporter/convertplayer.cpp b/apps/essimporter/convertplayer.cpp index ef22660f56..532efa7f5b 100644 --- a/apps/essimporter/convertplayer.cpp +++ b/apps/essimporter/convertplayer.cpp @@ -17,6 +17,8 @@ namespace ESSImport } for (int i=0; i<8; ++i) out.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i]; + for (int i=0; i<27; ++i) + out.mObject.mNpcStats.mSkills[i].mRegular.mProgress = pcdt.mPNAM.mSkillProgress[i]; out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress; if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Weapon) @@ -24,9 +26,6 @@ namespace ESSImport if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Spell) out.mObject.mCreatureStats.mDrawState = 2; - // TODO: convert PNAM.mSkillProgress, needs to be converted to uniform scale - // (or change openmw to accept non-uniform skill progress) - firstPersonCam = (pcdt.mPNAM.mCameraState == PCDT::CameraState_FirstPerson); for (std::vector::const_iterator it = pcdt.mKnownDialogueTopics.begin(); diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 1cb62276fe..224366a3e3 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -23,7 +23,7 @@ namespace MWMechanics class NpcStats : public CreatureStats { int mDisposition; - SkillValue mSkill[ESM::Skill::Length]; + SkillValue mSkill[ESM::Skill::Length]; // SkillValue.mProgress used by the player only SkillValue mWerewolfSkill[ESM::Skill::Length]; int mReputation; int mCrimeId; From 5096e5dc0c1cadad9d9b14ec9175a30e210411e6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Feb 2015 23:45:01 +0100 Subject: [PATCH 108/214] esmtool minor/major skills fix --- apps/esmtool/record.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index e167278f3d..97b0635fe5 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -535,10 +535,10 @@ void Record::print() std::cout << " Specialization: " << specializationLabel(mData.mData.mSpecialization) << " (" << mData.mData.mSpecialization << ")" << std::endl; for (int i = 0; i != 5; i++) - std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][0]) + std::cout << " Minor Skill: " << skillLabel(mData.mData.mSkills[i][0]) << " (" << mData.mData.mSkills[i][0] << ")" << std::endl; for (int i = 0; i != 5; i++) - std::cout << " Minor Skill: " << skillLabel(mData.mData.mSkills[i][1]) + std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][1]) << " (" << mData.mData.mSkills[i][1] << ")" << std::endl; } From 55cd9b526c93a44e22ccd784df93e590c61b1b04 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 00:56:32 +0100 Subject: [PATCH 109/214] Skill progress bar changed to match MW --- apps/essimporter/importacdt.hpp | 2 +- apps/openmw/mwgui/statswindow.cpp | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 1e0317049d..47055092de 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -61,7 +61,7 @@ namespace ESSImport bool mHasACSC; ACSC mACSC; - int mSkills[27][2]; + int mSkills[27][2]; // skills, base and modified // creature combat stats, base and modified // I think these can be ignored in the conversion, because it is not possible diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index f624d751d9..2a22f42393 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -376,9 +376,8 @@ namespace MWGui for (SkillList::const_iterator it = skills.begin(); it != end; ++it) { int skillId = *it; - if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes + if (skillId < 0 || skillId >= ESM::Skill::Length) // Skip unknown skill indexes continue; - assert(skillId >= 0 && skillId < ESM::Skill::Length); const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second; int base = stat.getBase(); @@ -388,9 +387,14 @@ namespace MWGui const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); - int progressRequirement = player.getClass().getNpcStats(player).getSkillProgressRequirement(skillId, + float progressRequirement = player.getClass().getNpcStats(player).getSkillProgressRequirement(skillId, *esmStore.get().find(player.get()->mBase->mClass)); - int progressPercent = int(int(stat.getProgress()) / float(progressRequirement) * 100.f); + + // This is how vanilla MW displays the progress bar (I think). Note it's slightly inaccurate, + // due to the int casting in the skill levelup logic. Also the progress label could in rare cases + // reach 100% without the skill levelling up. + // Leaving the original display logic for now, for consistency with ess-imported savegames. + int progressPercent = int(float(stat.getProgress()) / float(progressRequirement) * 100.f + 0.5f); const ESM::Skill* skill = esmStore.get().find(skillId); From b5e0e45c78716e37dbeeaebb49c3d198a71ef140 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 01:03:10 +0100 Subject: [PATCH 110/214] Fix iLevelUpTotal not being used in the levelUp logic --- apps/openmw/mwmechanics/npcstats.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index bd1cd55721..9d3d967b9e 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -264,13 +264,14 @@ int MWMechanics::NpcStats::getLevelProgress () const void MWMechanics::NpcStats::levelUp() { - mLevelProgress -= 10; - for (int i=0; i &gmst = MWBase::Environment::get().getWorld()->getStore().get(); + mLevelProgress -= gmst.find("iLevelUpTotal")->getInt(); + + for (int i=0; i Date: Thu, 5 Feb 2015 01:08:26 +0100 Subject: [PATCH 111/214] Cap the displayed attribute multiplier in levelup to attribute points left to 100 --- apps/openmw/mwgui/levelupdialog.cpp | 1 + apps/openmw/mwmechanics/npcstats.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 8553811aac..6759824f98 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -176,6 +176,7 @@ namespace MWGui availableAttributes++; int mult = pcStats.getLevelupAttributeMultiplier (i); + mult = std::min(mult, 100-pcStats.getAttribute(i).getBase()); text->setCaption(mult <= 1 ? "" : "x" + MyGUI::utility::toString(mult)); } else diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 9d3d967b9e..3aa034a3c4 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -268,6 +268,7 @@ void MWMechanics::NpcStats::levelUp() MWBase::Environment::get().getWorld()->getStore().get(); mLevelProgress -= gmst.find("iLevelUpTotal")->getInt(); + mLevelProgress = std::max(0, mLevelProgress); // might be necessary when levelup was invoked via console for (int i=0; i Date: Thu, 5 Feb 2015 01:15:42 +0100 Subject: [PATCH 112/214] UI consistency fix in levelup dialog --- apps/openmw/mwgui/levelupdialog.cpp | 3 ++- files/mygui/openmw_levelup_dialog.layout | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 6759824f98..c392372ff3 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -139,7 +139,6 @@ namespace MWGui if(world->getStore().get().isDynamic(cls->mId)) { - // Vanilla uses thief.dds for custom classes. // Choosing Stealth specialization and Speed/Agility as attributes, if possible. Otherwise fall back to first class found. MWWorld::SharedIterator it = world->getStore().get().begin(); for(; it != world->getStore().get().end(); ++it) @@ -173,6 +172,7 @@ namespace MWGui if (pcStats.getAttribute(i).getBase() < 100) { mAttributes[i]->setEnabled(true); + mAttributeValues[i]->setEnabled(true); availableAttributes++; int mult = pcStats.getLevelupAttributeMultiplier (i); @@ -182,6 +182,7 @@ namespace MWGui else { mAttributes[i]->setEnabled(false); + mAttributeValues[i]->setEnabled(false); text->setCaption(""); } diff --git a/files/mygui/openmw_levelup_dialog.layout b/files/mygui/openmw_levelup_dialog.layout index 190f16e5d9..ead181d26a 100644 --- a/files/mygui/openmw_levelup_dialog.layout +++ b/files/mygui/openmw_levelup_dialog.layout @@ -50,7 +50,7 @@ - + @@ -64,7 +64,7 @@ - + @@ -78,7 +78,7 @@ - + @@ -92,7 +92,7 @@ - + @@ -107,7 +107,7 @@ - + @@ -121,7 +121,7 @@ - + @@ -135,7 +135,7 @@ - + @@ -149,7 +149,7 @@ - + From d18d2a1882a297e21364b8f7aaaba5b4abf7d77e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 04:28:05 +0100 Subject: [PATCH 113/214] Skip rest of LEVI record if it has no items (Bug #2348) --- components/esm/loadlevlist.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index f2c695c1f1..0d02677648 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -19,7 +19,10 @@ void LevelledListBase::load(ESMReader &esm) mList.resize(len); } else + { + esm.skipRecord(); return; + } // TODO: Merge with an existing lists here. This can be done // simply by adding the lists together, making sure that they are From 01b41778720b71dcefc4a26860861cebefd04429 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 04:29:52 +0100 Subject: [PATCH 114/214] Make sure birthsign spells are added when loading savegame --- apps/openmw/mwworld/player.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index c1e176b910..8f3560a691 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -260,9 +260,20 @@ namespace MWWorld mCellStore = world.getExterior(0,0); } - if (!player.mBirthsign.empty() && - !world.getStore().get().search (player.mBirthsign)) - throw std::runtime_error ("invalid player state record (birthsign)"); + if (!player.mBirthsign.empty()) + { + const ESM::BirthSign* sign = world.getStore().get().search (player.mBirthsign); + if (!sign) + throw std::runtime_error ("invalid player state record (birthsign does not exist)"); + + // To handle the case where a birth sign was edited in between play sessions (does not yet handle removing the old spells) + // Also needed for ess-imported savegames which do not specify the birtsign spells in the player's spell list. + for (std::vector::const_iterator iter (sign->mPowers.mList.begin()); + iter!=sign->mPowers.mList.end(); ++iter) + { + getPlayer().getClass().getCreatureStats(getPlayer()).getSpells().add (*iter); + } + } mCurrentCrimeId = player.mCurrentCrimeId; mPaidCrimeId = player.mPaidCrimeId; From cff0127ce70d1eafb7474d0821adfd6aee7bdb77 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 04:31:50 +0100 Subject: [PATCH 115/214] Update comment on merging levelled lists --- components/esm/loadlevlist.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 0d02677648..2cbfac0b40 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -24,11 +24,12 @@ void LevelledListBase::load(ESMReader &esm) return; } - // TODO: Merge with an existing lists here. This can be done - // simply by adding the lists together, making sure that they are - // sorted by level. A better way might be to exclude repeated - // items. Also, some times we don't want to merge lists, just - // overwrite. Figure out a way to give the user this option. + // If this levelled list was already loaded by a previous content file, + // we overwrite the list. Merging lists should probably be left to external tools, + // with the limited amount of information there is in the records, all merging methods + // will be flawed in some way. For a proper fix the ESM format would have to be changed + // to actually track list changes instead of including the whole list for every file + // that does something with that list. for (size_t i = 0; i < mList.size(); i++) { From 4c6b9f8266b67e34bc6c6552c3a3ff0a0c0e406b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Feb 2015 15:39:53 +0100 Subject: [PATCH 116/214] Remove redundant decoder in ContentModel --- components/contentselector/model/contentmodel.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 198bbffbb1..56a86f87f6 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -442,11 +442,6 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon"; dir.setNameFilters(filters); - QTextCodec *codec = QTextCodec::codecForName("UTF8"); - - // Create a decoder for non-latin characters in esx metadata - QTextDecoder *decoder = codec->makeDecoder(); - foreach (const QString &path, dir.entryList()) { QFileInfo info(dir.absoluteFilePath(path)); @@ -466,11 +461,11 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) foreach (const ESM::Header::MasterData &item, fileReader.getGameFiles()) file->addGameFile(QString::fromStdString(item.name)); - file->setAuthor (decoder->toUnicode(fileReader.getAuthor().c_str())); + file->setAuthor (QString::fromUtf8(fileReader.getAuthor().c_str())); file->setDate (info.lastModified()); file->setFormat (fileReader.getFormat()); file->setFilePath (info.absoluteFilePath()); - file->setDescription(decoder->toUnicode(fileReader.getDesc().c_str())); + file->setDescription(QString::fromUtf8(fileReader.getDesc().c_str())); // Put the file in the table addFile(file); @@ -483,8 +478,6 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) } - delete decoder; - sortFiles(); } From 5534306eb332f42160dc79093c2c9894149baae9 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Fri, 6 Feb 2015 08:59:00 +0200 Subject: [PATCH 117/214] Few rename fixes --- CMakeLists.txt | 2 +- apps/opencs/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b5cd54babc..ab4363e2ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -761,7 +761,7 @@ if (APPLE) set(OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}") - set(OPENCS_BUNDLE_NAME "OpenCS.app") + set(OPENCS_BUNDLE_NAME "OpenMW-CS.app") set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}") set(ABSOLUTE_PLUGINS "") diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e713c65bc6..0b83feb450 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -211,5 +211,5 @@ target_link_libraries(openmw-cs ) if(APPLE) - INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW-CS COMPONENT BUNDLE) + INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE) endif() From 28eb766bbaab526ad35e0d4e06f7a5148c7e3e44 Mon Sep 17 00:00:00 2001 From: Rosanne DiMesio Date: Fri, 6 Feb 2015 14:27:12 -0600 Subject: [PATCH 118/214] Respect LIB_SUFFIX --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b5cd54babc..f2fd9b8de6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -392,7 +392,7 @@ IF(NOT WIN32 AND NOT APPLE) # Linux building # Paths SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries") - SET(LIBDIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Where to install libraries") + SET(LIBDIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "Where to install libraries") SET(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location") SET(GLOBAL_DATA_PATH "${DATAROOTDIR}/games/" CACHE PATH "Set data path prefix") SET(DATADIR "${GLOBAL_DATA_PATH}/openmw" CACHE PATH "Sets the openmw data directories to a non-default location") From 1d9e9735730a6b0db4aab7a716432d973f13317d Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 7 Feb 2015 04:05:28 +0100 Subject: [PATCH 119/214] Add training progress bar, implement jail screen, tweak wait dialog (Fixes #1714) --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/windowmanager.hpp | 3 + apps/openmw/mwgui/jailscreen.cpp | 136 ++++++++++++++++++++++++ apps/openmw/mwgui/jailscreen.hpp | 33 ++++++ apps/openmw/mwgui/mode.hpp | 1 + apps/openmw/mwgui/timeadvancer.cpp | 73 +++++++++++++ apps/openmw/mwgui/timeadvancer.hpp | 40 +++++++ apps/openmw/mwgui/trainingwindow.cpp | 22 ++++ apps/openmw/mwgui/trainingwindow.hpp | 8 ++ apps/openmw/mwgui/waitdialog.cpp | 94 ++++++++-------- apps/openmw/mwgui/waitdialog.hpp | 13 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 15 +++ apps/openmw/mwgui/windowmanagerimp.hpp | 4 + apps/openmw/mwscript/miscextensions.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 54 +--------- 15 files changed, 395 insertions(+), 105 deletions(-) create mode 100644 apps/openmw/mwgui/jailscreen.cpp create mode 100644 apps/openmw/mwgui/jailscreen.hpp create mode 100644 apps/openmw/mwgui/timeadvancer.cpp create mode 100644 apps/openmw/mwgui/timeadvancer.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index cb6cc301b8..eabbb7577e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -41,7 +41,7 @@ add_openmw_dir (mwgui itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview - draganddrop + draganddrop timeadvancer jailscreen ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index c984b5e541..32994a5a6d 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -63,6 +63,7 @@ namespace MWGui class ContainerWindow; class DialogueWindow; class WindowModal; + class JailScreen; enum ShowInDialogueMode { ShowInDialogueMode_IfPossible, @@ -114,6 +115,8 @@ namespace MWBase virtual void removeGuiMode (MWGui::GuiMode mode) = 0; ///< can be anywhere in the stack + virtual void goToJail(int days) = 0; + virtual void updatePlayer() = 0; virtual MWGui::GuiMode getMode() const = 0; diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp new file mode 100644 index 0000000000..0155ee5ff0 --- /dev/null +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -0,0 +1,136 @@ +#include +#include +#include +#include + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" + +#include "../mwmechanics/npcstats.hpp" + +#include "../mwworld/esmstore.hpp" +#include "../mwworld/store.hpp" +#include "../mwworld/class.hpp" + +#include "jailscreen.hpp" + +namespace MWGui +{ + JailScreen::JailScreen() + : WindowBase("openmw_loading_screen.layout"), + mTimeAdvancer(0.0125), + mDays(1), + mFadeTimeRemaining(0) + { + getWidget(mLoadingText, "LoadingText"); + getWidget(mProgressBar, "ProgressBar"); + getWidget(mLoadingBox, "LoadingBox"); + + setVisible(false); + + mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &JailScreen::onJailProgressChanged); + mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &JailScreen::onJailFinished); + + mLoadingText->setCaptionWithReplacing("#{sInPrisonTitle}"); + + center(); + } + + void JailScreen::goToJail(int days) + { + mDays = days; + + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5); + mFadeTimeRemaining = 0.5; + + setVisible(false); + mProgressBar->setScrollRange(days*24+1); + mProgressBar->setScrollPosition(0); + mProgressBar->setTrackSize(0); + } + + void JailScreen::onFrame(float dt) + { + mTimeAdvancer.onFrame(dt); + + if (mFadeTimeRemaining <= 0) + return; + + mFadeTimeRemaining -= dt; + + if (mFadeTimeRemaining <= 0) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWBase::Environment::get().getWorld()->teleportToClosestMarker(player, "prisonmarker"); + + setVisible(true); + mTimeAdvancer.run(mDays*24); + } + } + + void JailScreen::onJailProgressChanged(int cur, int /*total*/) + { + mProgressBar->setScrollPosition(0); + mProgressBar->setTrackSize(cur / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()); + } + + void JailScreen::onJailFinished() + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + MWBase::Environment::get().getWorld()->advanceTime(mDays * 24); + for (int i=0; irest(true); + + std::set skills; + for (int day=0; day (RAND_MAX) + 1) * ESM::Skill::Length; + skills.insert(skill); + + MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill); + if (skill == ESM::Skill::Security || skill == ESM::Skill::Sneak) + value.setBase(std::min(100, value.getBase()+1)); + else + value.setBase(value.getBase()-1); + } + + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + + std::string message; + if (mDays == 1) + message = gmst.find("sNotifyMessage42")->getString(); + else + message = gmst.find("sNotifyMessage43")->getString(); + + std::stringstream dayStr; + dayStr << mDays; + if (message.find("%d") != std::string::npos) + message.replace(message.find("%d"), 2, dayStr.str()); + + for (std::set::iterator it = skills.begin(); it != skills.end(); ++it) + { + std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[*it])->getString(); + std::stringstream skillValue; + skillValue << player.getClass().getNpcStats(player).getSkill(*it).getBase(); + std::string skillMsg = gmst.find("sNotifyMessage44")->getString(); + if (*it == ESM::Skill::Sneak || *it == ESM::Skill::Security) + skillMsg = gmst.find("sNotifyMessage39")->getString(); + + if (skillMsg.find("%s") != std::string::npos) + skillMsg.replace(skillMsg.find("%s"), 2, skillName); + if (skillMsg.find("%d") != std::string::npos) + skillMsg.replace(skillMsg.find("%d"), 2, skillValue.str()); + message += "\n" + skillMsg; + } + + std::vector buttons; + buttons.push_back("#{sOk}"); + MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons); + } +} diff --git a/apps/openmw/mwgui/jailscreen.hpp b/apps/openmw/mwgui/jailscreen.hpp new file mode 100644 index 0000000000..06e9a3aa07 --- /dev/null +++ b/apps/openmw/mwgui/jailscreen.hpp @@ -0,0 +1,33 @@ +#ifndef MWGUI_JAILSCREEN_H +#define MWGUI_JAILSCREEN_H + +#include "windowbase.hpp" +#include "timeadvancer.hpp" + +namespace MWGui +{ + class JailScreen : public WindowBase + { + public: + JailScreen(); + void goToJail(int days); + + void onFrame(float dt); + + private: + int mDays; + + float mFadeTimeRemaining; + + MyGUI::Widget* mLoadingBox; + MyGUI::TextBox* mLoadingText; + MyGUI::ScrollBar* mProgressBar; + + void onJailProgressChanged(int cur, int total); + void onJailFinished(); + + TimeAdvancer mTimeAdvancer; + }; +} + +#endif diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index a1688d2e53..db851e0674 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -46,6 +46,7 @@ namespace MWGui GM_Loading, GM_LoadingWallpaper, + GM_Jail, GM_QuickKeysMenu }; diff --git a/apps/openmw/mwgui/timeadvancer.cpp b/apps/openmw/mwgui/timeadvancer.cpp new file mode 100644 index 0000000000..43504ce870 --- /dev/null +++ b/apps/openmw/mwgui/timeadvancer.cpp @@ -0,0 +1,73 @@ +#include "timeadvancer.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +namespace MWGui +{ + TimeAdvancer::TimeAdvancer(float delay) + : mRunning(false), + mCurHour(0), + mHours(1), + mInterruptAt(-1), + mDelay(delay), + mRemainingTime(delay) + { + } + + void TimeAdvancer::run(int hours, int interruptAt) + { + mHours = hours; + mCurHour = 0; + mInterruptAt = interruptAt; + mRemainingTime = mDelay; + + mRunning = true; + } + + void TimeAdvancer::stop() + { + mRunning = false; + } + + void TimeAdvancer::onFrame(float dt) + { + if (!mRunning) + return; + + if (mCurHour == mInterruptAt) + { + stop(); + eventInterrupted(); + return; + } + + mRemainingTime -= dt; + + while (mRemainingTime <= 0) + { + mRemainingTime += mDelay; + ++mCurHour; + + if (mCurHour <= mHours) + eventProgressChanged(mCurHour, mHours); + else + { + stop(); + eventFinished(); + return; + } + + } + } + + int TimeAdvancer::getHours() + { + return mHours; + } + + bool TimeAdvancer::isRunning() + { + return mRunning; + } +} diff --git a/apps/openmw/mwgui/timeadvancer.hpp b/apps/openmw/mwgui/timeadvancer.hpp new file mode 100644 index 0000000000..8367b5a8b2 --- /dev/null +++ b/apps/openmw/mwgui/timeadvancer.hpp @@ -0,0 +1,40 @@ +#ifndef MWGUI_TIMEADVANCER_H +#define MWGUI_TIMEADVANCER_H + +#include + +namespace MWGui +{ + class TimeAdvancer + { + public: + TimeAdvancer(float delay); + + void run(int hours, int interruptAt=-1); + void stop(); + void onFrame(float dt); + + int getHours(); + bool isRunning(); + + // signals + typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; + typedef MyGUI::delegates::CMultiDelegate2 EventHandle_IntInt; + + EventHandle_IntInt eventProgressChanged; + EventHandle_Void eventInterrupted; + EventHandle_Void eventFinished; + + private: + bool mRunning; + + int mCurHour; + int mHours; + int mInterruptAt; + + float mDelay; + float mRemainingTime; + }; +} + +#endif diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 88ba62cc1e..5a5f611153 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -40,12 +40,18 @@ namespace MWGui TrainingWindow::TrainingWindow() : WindowBase("openmw_trainingwindow.layout") , mFadeTimeRemaining(0) + , mTimeAdvancer(0.05) { getWidget(mTrainingOptions, "TrainingOptions"); getWidget(mCancelButton, "CancelButton"); getWidget(mPlayerGold, "PlayerGold"); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onCancelButtonClicked); + + mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &TrainingWindow::onTrainingProgressChanged); + mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &TrainingWindow::onTrainingFinished); + + mProgressBar.setVisible(false); } void TrainingWindow::open() @@ -173,12 +179,28 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->rest(false); MWBase::Environment::get().getMechanicsManager()->rest(false); + mProgressBar.setVisible(true); + mProgressBar.setProgress(0, 2); + mTimeAdvancer.run(2); + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.25); mFadeTimeRemaining = 0.5; } + void TrainingWindow::onTrainingProgressChanged(int cur, int total) + { + mProgressBar.setProgress(cur, total); + } + + void TrainingWindow::onTrainingFinished() + { + mProgressBar.setVisible(false); + } + void TrainingWindow::onFrame(float dt) { + mTimeAdvancer.onFrame(dt); + if (mFadeTimeRemaining <= 0) return; diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index 1fc902b20a..7c45820626 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -3,6 +3,8 @@ #include "windowbase.hpp" #include "referenceinterface.hpp" +#include "timeadvancer.hpp" +#include "waitdialog.hpp" namespace MWGui { @@ -26,11 +28,17 @@ namespace MWGui void onCancelButtonClicked (MyGUI::Widget* sender); void onTrainingSelected(MyGUI::Widget* sender); + void onTrainingProgressChanged(int cur, int total); + void onTrainingFinished(); + MyGUI::Widget* mTrainingOptions; MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; float mFadeTimeRemaining; + + WaitDialogProgressBar mProgressBar; + TimeAdvancer mTimeAdvancer; }; } diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index fedb0324e9..ad873a7c3f 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -49,12 +49,11 @@ namespace MWGui WaitDialog::WaitDialog() : WindowBase("openmw_wait_dialog.layout") , mProgressBar() - , mWaiting(false) + , mTimeAdvancer(0.05) , mSleeping(false) , mHours(1) - , mRemainingTime(0.05) - , mCurHour(0) , mManualHours(1) + , mFadeTimeRemaining(0) , mInterruptAt(-1) { getWidget(mDateTimeText, "DateTimeText"); @@ -70,6 +69,10 @@ namespace MWGui mWaitButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WaitDialog::onWaitButtonClicked); mHourSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &WaitDialog::onHourSliderChangedPosition); + mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &WaitDialog::onWaitingProgressChanged); + mTimeAdvancer.eventInterrupted += MyGUI::newDelegate(this, &WaitDialog::onWaitingInterrupted); + mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &WaitDialog::onWaitingFinished); + mProgressBar.setVisible (false); } @@ -133,11 +136,9 @@ namespace MWGui MWBase::World* world = MWBase::Environment::get().getWorld(); MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.2); + mFadeTimeRemaining = 0.4; setVisible(false); - mProgressBar.setVisible (true); - mWaiting = true; - mCurHour = 0; mHours = hoursToWait; // FIXME: move this somewhere else? @@ -164,8 +165,7 @@ namespace MWGui } } - mRemainingTime = 0.05; - mProgressBar.setProgress (0, mHours); + mProgressBar.setProgress (0, hoursToWait); } void WaitDialog::onCancelButtonClicked(MyGUI::Widget* sender) @@ -179,6 +179,36 @@ namespace MWGui mManualHours = position+1; } + void WaitDialog::onWaitingProgressChanged(int cur, int total) + { + mProgressBar.setProgress(cur, total); + MWBase::Environment::get().getWorld()->advanceTime(1); + MWBase::Environment::get().getMechanicsManager()->rest(mSleeping); + } + + void WaitDialog::onWaitingInterrupted() + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sSleepInterrupt}"); + MWBase::Environment::get().getWorld()->spawnRandomCreature(mInterruptCreatureList); + stopWaiting(); + } + + void WaitDialog::onWaitingFinished() + { + stopWaiting(); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWMechanics::NpcStats &pcstats = player.getClass().getNpcStats(player); + + // trigger levelup if possible + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + if (mSleeping && pcstats.getLevelProgress () >= gmst.find("iLevelUpTotal")->getInt()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup); + } + } + void WaitDialog::setCanRest (bool canRest) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -205,45 +235,17 @@ namespace MWGui void WaitDialog::onFrame(float dt) { - if (!mWaiting) + mTimeAdvancer.onFrame(dt); + + if (mFadeTimeRemaining <= 0) return; - if (mCurHour == mInterruptAt) + mFadeTimeRemaining -= dt; + + if (mFadeTimeRemaining <= 0) { - MWBase::Environment::get().getWindowManager()->messageBox("#{sSleepInterrupt}"); - MWBase::Environment::get().getWorld()->spawnRandomCreature(mInterruptCreatureList); - stopWaiting(); - } - - mRemainingTime -= dt; - - while (mRemainingTime < 0) - { - mRemainingTime += 0.05; - ++mCurHour; - mProgressBar.setProgress (mCurHour, mHours); - - if (mCurHour <= mHours) - { - MWBase::Environment::get().getWorld ()->advanceTime (1); - MWBase::Environment::get().getMechanicsManager ()->rest (mSleeping); - } - } - - if (mCurHour > mHours) - { - stopWaiting(); - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - const MWMechanics::NpcStats &pcstats = player.getClass().getNpcStats(player); - - // trigger levelup if possible - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); - if (mSleeping && pcstats.getLevelProgress () >= gmst.find("iLevelUpTotal")->getInt()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup); - } + mProgressBar.setVisible(true); + mTimeAdvancer.run(mHours, mInterruptAt); } } @@ -253,14 +255,14 @@ namespace MWGui mProgressBar.setVisible (false); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Rest); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_RestBed); - mWaiting = false; + mTimeAdvancer.stop(); } void WaitDialog::wakeUp () { mSleeping = false; - mWaiting = false; + mTimeAdvancer.stop(); stopWaiting(); } diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 435c1cb547..e8f58c574d 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -1,6 +1,8 @@ #ifndef MWGUI_WAIT_DIALOG_H #define MWGUI_WAIT_DIALOG_H +#include "timeadvancer.hpp" + #include "windowbase.hpp" namespace MWGui @@ -38,7 +40,7 @@ namespace MWGui void bedActivated() { setCanRest(true); } - bool getSleeping() { return mWaiting && mSleeping; } + bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } void wakeUp(); void autosave(); @@ -51,12 +53,11 @@ namespace MWGui MyGUI::Button* mCancelButton; MWGui::Widgets::MWScrollBar* mHourSlider; - bool mWaiting; + TimeAdvancer mTimeAdvancer; bool mSleeping; - int mCurHour; int mHours; int mManualHours; // stores the hours to rest selected via slider - float mRemainingTime; + float mFadeTimeRemaining; int mInterruptAt; std::string mInterruptCreatureList; @@ -68,6 +69,10 @@ namespace MWGui void onCancelButtonClicked(MyGUI::Widget* sender); void onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position); + void onWaitingProgressChanged(int cur, int total); + void onWaitingInterrupted(); + void onWaitingFinished(); + void setCanRest(bool canRest); void startWaiting(int hoursToWait); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 715f47c46e..d67ab17e07 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -91,6 +91,7 @@ #include "draganddrop.hpp" #include "container.hpp" #include "controllers.hpp" +#include "jailscreen.hpp" namespace MWGui { @@ -143,6 +144,7 @@ namespace MWGui , mHitFader(NULL) , mScreenFader(NULL) , mDebugWindow(NULL) + , mJailScreen(NULL) , mTranslationDataStorage (translationDataStorage) , mCharGen(NULL) , mInputBlocker(NULL) @@ -290,6 +292,7 @@ namespace MWGui mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); trackWindow(mCompanionWindow, "companion"); + mJailScreen = new JailScreen(); mWerewolfFader = new ScreenFader("textures\\werewolfoverlay.dds"); mBlindnessFader = new ScreenFader("black.png"); @@ -402,6 +405,7 @@ namespace MWGui delete mScreenFader; delete mBlindnessFader; delete mDebugWindow; + delete mJailScreen; delete mCursorManager; @@ -467,6 +471,7 @@ namespace MWGui mInventoryWindow->setTrading(false); mRecharge->setVisible(false); mVideoBackground->setVisible(false); + mJailScreen->setVisible(false); mHud->setVisible(mHudEnabled && mGuiEnabled); mToolTips->setVisible(mGuiEnabled); @@ -612,6 +617,9 @@ namespace MWGui case GM_Journal: mJournal->setVisible(true); break; + case GM_Jail: + mJailScreen->setVisible(true); + break; case GM_LoadingWallpaper: case GM_Loading: // Don't need to show anything here - GM_LoadingWallpaper covers everything else anyway, @@ -912,6 +920,7 @@ namespace MWGui mCompanionWindow->checkReferenceAvailable(); mConsole->checkReferenceAvailable(); mCompanionWindow->onFrame(); + mJailScreen->onFrame(frameDuration); mWerewolfFader->update(frameDuration); mBlindnessFader->update(frameDuration); @@ -1187,6 +1196,12 @@ namespace MWGui updateVisible(); } + void WindowManager::goToJail(int days) + { + pushGuiMode(MWGui::GM_Jail); + mJailScreen->goToJail(days); + } + void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent) { mSelectedSpell = spellId; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 9f01b136cf..19c5e31664 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -90,6 +90,7 @@ namespace MWGui class WindowModal; class ScreenFader; class DebugWindow; + class JailScreen; class WindowManager : public MWBase::WindowManager { @@ -128,6 +129,8 @@ namespace MWGui virtual void popGuiMode(); virtual void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack + virtual void goToJail(int days); + virtual GuiMode getMode() const; virtual bool containsMode(GuiMode mode) const; @@ -404,6 +407,7 @@ namespace MWGui ScreenFader* mHitFader; ScreenFader* mScreenFader; DebugWindow* mDebugWindow; + JailScreen* mJailScreen; Translation::Storage& mTranslationDataStorage; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index bffeef768c..40a356125c 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1008,7 +1008,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime &runtime) { /// \todo implement jail check - runtime.push (0); + runtime.push (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Jail); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a8238d161e..af3fa5b3e9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3019,59 +3019,7 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); - MWWorld::Ptr player = getPlayerPtr(); - teleportToClosestMarker(player, "prisonmarker"); - - int days = mDaysInPrison; - advanceTime(days * 24); - for (int i=0; irest (true); - - std::set skills; - for (int day=0; day (RAND_MAX) + 1) * ESM::Skill::Length; - skills.insert(skill); - - MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill); - if (skill == ESM::Skill::Security || skill == ESM::Skill::Sneak) - value.setBase(std::min(100, value.getBase()+1)); - else - value.setBase(value.getBase()-1); - } - - const Store& gmst = getStore().get(); - - std::string message; - if (days == 1) - message = gmst.find("sNotifyMessage42")->getString(); - else - message = gmst.find("sNotifyMessage43")->getString(); - - std::stringstream dayStr; - dayStr << days; - if (message.find("%d") != std::string::npos) - message.replace(message.find("%d"), 2, dayStr.str()); - - for (std::set::iterator it = skills.begin(); it != skills.end(); ++it) - { - std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[*it])->getString(); - std::stringstream skillValue; - skillValue << player.getClass().getNpcStats(player).getSkill(*it).getBase(); - std::string skillMsg = gmst.find("sNotifyMessage44")->getString(); - if (*it == ESM::Skill::Sneak || *it == ESM::Skill::Security) - skillMsg = gmst.find("sNotifyMessage39")->getString(); - - if (skillMsg.find("%s") != std::string::npos) - skillMsg.replace(skillMsg.find("%s"), 2, skillName); - if (skillMsg.find("%d") != std::string::npos) - skillMsg.replace(skillMsg.find("%d"), 2, skillValue.str()); - message += "\n" + skillMsg; - } - - std::vector buttons; - buttons.push_back("#{sOk}"); - MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons); + MWBase::Environment::get().getWindowManager()->goToJail(mDaysInPrison); } } From 2d17eaa5ea5ad5e57928649cf0553f01a8413e20 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Fri, 6 Feb 2015 19:21:40 -0600 Subject: [PATCH 120/214] Fix argument name for setSunDirection. --- apps/openmw/mwrender/renderingmanager.cpp | 4 ++-- apps/openmw/mwrender/renderingmanager.hpp | 2 +- apps/openmw/mwrender/sky.cpp | 4 ++-- apps/openmw/mwrender/sky.hpp | 2 +- apps/openmw/mwworld/weather.cpp | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3ffd787c71..3e95648c42 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -630,12 +630,12 @@ void RenderingManager::sunDisable(bool real) } } -void RenderingManager::setSunDirection(const Ogre::Vector3& direction, bool is_moon) +void RenderingManager::setSunDirection(const Ogre::Vector3& direction, bool is_night) { // direction * -1 (because 'direction' is camera to sun vector and not sun to camera), if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.y, -direction.z)); - mSkyManager->setSunDirection(direction, is_moon); + mSkyManager->setSunDirection(direction, is_night); } void RenderingManager::setGlare(bool glare) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index d4b85133d9..9f029c1b91 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -141,7 +141,7 @@ public: void setAmbientColour(const Ogre::ColourValue& colour); void setSunColour(const Ogre::ColourValue& colour); - void setSunDirection(const Ogre::Vector3& direction, bool is_moon); + void setSunDirection(const Ogre::Vector3& direction, bool is_night); void sunEnable(bool real); ///< @param real whether or not to really disable the sunlight (otherwise just set diffuse to 0) void sunDisable(bool real); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 454ed88209..f6287de5ef 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -767,14 +767,14 @@ void SkyManager::setStormDirection(const Vector3 &direction) mStormDirection = direction; } -void SkyManager::setSunDirection(const Vector3& direction, bool is_moon) +void SkyManager::setSunDirection(const Vector3& direction, bool is_night) { if (!mCreated) return; mSun->setPosition(direction); mSunGlare->setPosition(direction); float height = direction.z; - float fade = is_moon ? 0.0 : (( height > 0.5) ? 1.0 : height * 2); + float fade = is_night ? 0.0 : (( height > 0.5) ? 1.0 : height * 2); sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(fade, height))); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 70251f4901..6950dbab34 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -153,7 +153,7 @@ namespace MWRender void setStormDirection(const Ogre::Vector3& direction); - void setSunDirection(const Ogre::Vector3& direction, bool is_moon); + void setSunDirection(const Ogre::Vector3& direction, bool is_night); void setMasserDirection(const Ogre::Vector3& direction); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index a74c247681..a893b657a5 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -443,13 +443,13 @@ void WeatherManager::update(float duration, bool paused) int facing = (mHour > 13.f) ? 1 : -1; - bool sun_is_moon = mHour >= mNightStart || mHour <= mSunriseTime; + bool is_night = mHour >= mNightStart || mHour <= mSunriseTime; Vector3 final( (height - 1) * facing, (height - 1) * facing, height); - mRendering->setSunDirection(final, sun_is_moon); + mRendering->setSunDirection(final, is_night); /* * TODO: import separated fadeInStart/Finish, fadeOutStart/Finish From c8a924196deacac0193f6698baa0bfa63a8f517d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 7 Feb 2015 17:22:29 +0100 Subject: [PATCH 121/214] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index f261ea4233..bc39b1c703 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -84,6 +84,7 @@ Programmers Paul McElroy (Greendogo) Pieter van der Kloet (pvdk) Radu-Marius Popovici (rpopovici) + rdimesio riothamus Robert MacGregor (Ragora) Rohit Nirmal From 1230cf49bf63cebe82e355e517ae58205afb9c31 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 7 Feb 2015 18:38:41 +0100 Subject: [PATCH 122/214] Properly center jail progress widget, fix a bug with it not disappearing if the console is open --- apps/openmw/mwgui/jailscreen.cpp | 11 ++--------- apps/openmw/mwgui/jailscreen.hpp | 2 -- files/mygui/CMakeLists.txt | 1 + files/mygui/openmw_jail_screen.layout | 15 +++++++++++++++ 4 files changed, 18 insertions(+), 11 deletions(-) create mode 100644 files/mygui/openmw_jail_screen.layout diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 0155ee5ff0..548b1b604c 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -1,7 +1,4 @@ -#include #include -#include -#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -19,22 +16,18 @@ namespace MWGui { JailScreen::JailScreen() - : WindowBase("openmw_loading_screen.layout"), + : WindowBase("openmw_jail_screen.layout"), mTimeAdvancer(0.0125), mDays(1), mFadeTimeRemaining(0) { - getWidget(mLoadingText, "LoadingText"); getWidget(mProgressBar, "ProgressBar"); - getWidget(mLoadingBox, "LoadingBox"); setVisible(false); mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &JailScreen::onJailProgressChanged); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &JailScreen::onJailFinished); - mLoadingText->setCaptionWithReplacing("#{sInPrisonTitle}"); - center(); } @@ -78,7 +71,7 @@ namespace MWGui void JailScreen::onJailFinished() { - MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Jail); MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); diff --git a/apps/openmw/mwgui/jailscreen.hpp b/apps/openmw/mwgui/jailscreen.hpp index 06e9a3aa07..7a544126db 100644 --- a/apps/openmw/mwgui/jailscreen.hpp +++ b/apps/openmw/mwgui/jailscreen.hpp @@ -19,8 +19,6 @@ namespace MWGui float mFadeTimeRemaining; - MyGUI::Widget* mLoadingBox; - MyGUI::TextBox* mLoadingText; MyGUI::ScrollBar* mProgressBar; void onJailProgressChanged(int cur, int total); diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 638266b0ce..13d1a9e1a4 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -86,6 +86,7 @@ set(MYGUI_FILES openmw_edit_note.layout openmw_debug_window.layout openmw_debug_window.skin.xml + openmw_jail_screen.layout DejaVuLGCSansMono.ttf ../launcher/images/openmw.png OpenMWResourcePlugin.xml diff --git a/files/mygui/openmw_jail_screen.layout b/files/mygui/openmw_jail_screen.layout new file mode 100644 index 0000000000..4385494e1c --- /dev/null +++ b/files/mygui/openmw_jail_screen.layout @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + From 9bbe6f8c5e52808e8b1886b3c594e01934dd892c Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 7 Feb 2015 18:39:05 +0100 Subject: [PATCH 123/214] Remove todo --- apps/openmw/mwscript/miscextensions.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 40a356125c..1cc1b25e4a 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1007,7 +1007,6 @@ namespace MWScript virtual void execute (Interpreter::Runtime &runtime) { - /// \todo implement jail check runtime.push (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Jail); } }; From 23024d2bebc2a376b062b2bbe94bfe880f9e975d Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sat, 7 Feb 2015 12:36:27 -0600 Subject: [PATCH 124/214] Re-work the sun's trajectory. OMW Bug #781 Have the sun travel 15 degrees south of vertical. --- apps/openmw/mwworld/weather.cpp | 44 +++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index a893b657a5..dcd8e5a114 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -1,5 +1,7 @@ #include "weather.hpp" +#include + #include #include "../mwbase/environment.hpp" @@ -427,29 +429,33 @@ void WeatherManager::update(float duration, bool paused) else mRendering->getSkyManager()->sunEnable(); - // sun angle - float height; + // Update the sun direction. Run it east to west at 15 degrees south from overhead. + // The sun's speed at day and night will differ, since mSunriseTime and mNightStart + // mark when the sun is level with the horizon. + { + assert( mNightStart > mSunriseTime ); - //Day duration - float dayDuration = (mNightStart - 1) - mSunriseTime; + float adjustedHour = mHour; + if ( mHour < mSunriseTime ) + adjustedHour += 24.f; - // rise at 6, set at 20 - if (mHour >= mSunriseTime && mHour <= mNightStart) - height = 1 - std::abs(((mHour - dayDuration) / 7.f)); - else if (mHour > mNightStart) - height = (mHour - mNightStart) / 4.f; - else //if (mHour > 0 && mHour < 6) - height = 1 - (mHour / mSunriseTime); + const bool is_night = mHour >= mNightStart || mHour <= mSunriseTime; + const float dayDuration = mNightStart - mSunriseTime; + const float nightDuration = 24.f - dayDuration; - int facing = (mHour > 13.f) ? 1 : -1; + double theta; + if ( !is_night ) { + theta = M_PI * (adjustedHour - mSunriseTime) / dayDuration; + } else { + theta = M_PI * (adjustedHour - mNightStart) / nightDuration; + } - bool is_night = mHour >= mNightStart || mHour <= mSunriseTime; - - Vector3 final( - (height - 1) * facing, - (height - 1) * facing, - height); - mRendering->setSunDirection(final, is_night); + Vector3 final( + cos( theta ), + -0.268, // approx tan( 15 degrees ) + sin( theta ) ); + mRendering->setSunDirection( final, is_night ); + } /* * TODO: import separated fadeInStart/Finish, fadeOutStart/Finish From 2223a69ab827e3315781bd3ddd32eda68dd7cc9b Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 7 Feb 2015 20:13:11 +0100 Subject: [PATCH 125/214] Fix getpcinjail returning 0 when the console is open --- apps/openmw/mwscript/miscextensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 1cc1b25e4a..20724cd23b 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1007,7 +1007,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime &runtime) { - runtime.push (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Jail); + runtime.push (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Jail)); } }; From c63ab673e1f1a09862d500400cb4cc3713dbc46e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Feb 2015 23:24:27 +0100 Subject: [PATCH 126/214] Revert "Add freedesktop.org mimeinfo for OpenMW save game files" This reverts commit 94002b0758a8825215074b5341b6ec6b0cd28660. Conflicts: CMakeLists.txt --- CMakeLists.txt | 3 --- files/openmw-mimeinfo.xml | 11 ----------- files/openmw.desktop | 13 ------------- 3 files changed, 27 deletions(-) delete mode 100644 files/openmw-mimeinfo.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index ab4363e2ec..d22e0b1292 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -371,8 +371,6 @@ configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters 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-mimeinfo.xml - "${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml") configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.desktop "${OpenMW_BINARY_DIR}/openmw-cs.desktop") endif() @@ -441,7 +439,6 @@ IF(NOT WIN32 AND NOT APPLE) # Install icon and desktop file INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-mimeinfo.xml" DESTINATION "${DATAROOTDIR}/mime/packages" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") IF(BUILD_OPENCS) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") diff --git a/files/openmw-mimeinfo.xml b/files/openmw-mimeinfo.xml deleted file mode 100644 index 1355383a5b..0000000000 --- a/files/openmw-mimeinfo.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - OpenMW Savegame - - - - diff --git a/files/openmw.desktop b/files/openmw.desktop index 6d64c5a7c4..36d01b33e9 100644 --- a/files/openmw.desktop +++ b/files/openmw.desktop @@ -8,16 +8,3 @@ TryExec=openmw-launcher Exec=openmw-launcher Icon=openmw Categories=Game;RolePlaying; - -[Desktop Entry] -Type=Application -Name=OpenMW -GenericName=Role Playing Game -Comment=An engine replacement for The Elder Scrolls III: Morrowind -Keywords=Morrowind;Reimplementation Mods;esm;bsa; -Exec=openmw --load-savegame=%f -Icon=openmw -Categories=Game;RolePlaying; -Terminal=false -NoDisplay=true -MimeType=application/x-openmw-savegame; From 01e32aef79fcdcf14c8dfcbb2d61d11589e05e31 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Feb 2015 14:34:31 +0100 Subject: [PATCH 127/214] Fix exception moving a disabled object between cells --- apps/openmw/mwrender/renderingmanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3ffd787c71..88ede1682c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -297,6 +297,8 @@ void RenderingManager::rotateObject(const MWWorld::Ptr &ptr) void RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { + if (!old.getRefData().getBaseNode()) + return; Ogre::SceneNode *child = mRendering.getScene()->getSceneNode(old.getRefData().getHandle()); From ad8790fba0b81e03027b3f778cda002eb213155d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Feb 2015 15:39:10 +0100 Subject: [PATCH 128/214] Fix setWaterLevel script instruction not affecting physics --- apps/openmw/mwsound/soundmanagerimp.cpp | 4 ++-- apps/openmw/mwworld/physicssystem.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d856f41ee6..0bc155118f 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -723,9 +723,9 @@ namespace MWSound MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - const ESM::Cell *cell = player.getCell()->getCell(); + const MWWorld::CellStore *cell = player.getCell(); - mListenerUnderwater = ((cell->mData.mFlags&cell->HasWater) && mListenerPos.z < cell->mWater); + mListenerUnderwater = ((cell->getCell()->mData.mFlags&ESM::Cell::HasWater) && mListenerPos.z < cell->getWaterLevel()); } void SoundManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index bea99029a4..d31ae520bd 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -862,9 +862,9 @@ namespace MWWorld for(;iter != mMovementQueue.end();++iter) { float waterlevel = -std::numeric_limits::max(); - const ESM::Cell *cell = iter->first.getCell()->getCell(); - if(cell->hasWater()) - waterlevel = cell->mWater; + const MWWorld::CellStore *cell = iter->first.getCell(); + if(cell->getCell()->hasWater()) + waterlevel = cell->getWaterLevel(); float oldHeight = iter->first.getRefData().getPosition().pos[2]; @@ -872,7 +872,7 @@ namespace MWWorld bool waterCollision = false; if (effects.get(ESM::MagicEffect::WaterWalking).getMagnitude() - && cell->hasWater() + && cell->getCell()->hasWater() && !world->isUnderwater(iter->first.getCell(), Ogre::Vector3(iter->first.getRefData().getPosition().pos))) waterCollision = true; From b542143e3a231bd7418ffc0975793ea2df5a1cb4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Feb 2015 21:04:01 +0100 Subject: [PATCH 129/214] Fix faction reputation case sensitivity issue (Fixes #2360) --- apps/openmw/mwmechanics/npcstats.cpp | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index c517b4df8a..f6e3090d73 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -125,6 +125,21 @@ bool MWMechanics::NpcStats::isInFaction (const std::string& faction) const return (mFactionRank.find(Misc::StringUtils::lowerCase(faction)) != mFactionRank.end()); } +int MWMechanics::NpcStats::getFactionReputation (const std::string& faction) const +{ + std::map::const_iterator iter = mFactionReputation.find (Misc::StringUtils::lowerCase(faction)); + + if (iter==mFactionReputation.end()) + return 0; + + return iter->second; +} + +void MWMechanics::NpcStats::setFactionReputation (const std::string& faction, int value) +{ + mFactionReputation[Misc::StringUtils::lowerCase(faction)] = value; +} + float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& class_, int usageType, int level, float extraFactor) const { @@ -329,21 +344,6 @@ void MWMechanics::NpcStats::setBounty (int bounty) mBounty = bounty; } -int MWMechanics::NpcStats::getFactionReputation (const std::string& faction) const -{ - std::map::const_iterator iter = mFactionReputation.find (faction); - - if (iter==mFactionReputation.end()) - return 0; - - return iter->second; -} - -void MWMechanics::NpcStats::setFactionReputation (const std::string& faction, int value) -{ - mFactionReputation[faction] = value; -} - int MWMechanics::NpcStats::getReputation() const { return mReputation; From 9dbd9af31c422fd236e300d53e350c7801ff027e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Feb 2015 21:26:58 +0100 Subject: [PATCH 130/214] Adjust fix for Bug #2360 to repair affected savegames --- apps/openmw/mwmechanics/npcstats.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index f6e3090d73..a3a29acab0 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -515,7 +515,7 @@ void MWMechanics::NpcStats::readState (const ESM::NpcStats& state) mFactionRank[iter->first] = iter->second.mRank; if (iter->second.mReputation) - mFactionReputation[iter->first] = iter->second.mReputation; + mFactionReputation[Misc::StringUtils::lowerCase(iter->first)] = iter->second.mReputation; } mDisposition = state.mDisposition; From ec3487b669c35e9df8260fa66f0c2f8de904cf5e Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sun, 8 Feb 2015 14:26:38 -0600 Subject: [PATCH 131/214] Sun trajectory: handle mNightStart <= mSunriseTime OMW Bug #781 Note: mNightStart == mSunriseTime is treated as 24-hour night. --- apps/openmw/mwworld/weather.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index dcd8e5a114..7a36d6ac73 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -429,30 +429,32 @@ void WeatherManager::update(float duration, bool paused) else mRendering->getSkyManager()->sunEnable(); - // Update the sun direction. Run it east to west at 15 degrees south from overhead. - // The sun's speed at day and night will differ, since mSunriseTime and mNightStart + // 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. { - assert( mNightStart > mSunriseTime ); - + // Shift times into a 24-hour window beginning at mSunriseTime... float adjustedHour = mHour; + float adjustedNightStart = mNightStart; if ( mHour < mSunriseTime ) adjustedHour += 24.f; + if ( mNightStart < mSunriseTime ) + adjustedNightStart += 24.f; - const bool is_night = mHour >= mNightStart || mHour <= mSunriseTime; - const float dayDuration = mNightStart - mSunriseTime; + const bool is_night = adjustedHour >= adjustedNightStart; + const float dayDuration = adjustedNightStart - mSunriseTime; const float nightDuration = 24.f - dayDuration; double theta; if ( !is_night ) { theta = M_PI * (adjustedHour - mSunriseTime) / dayDuration; } else { - theta = M_PI * (adjustedHour - mNightStart) / nightDuration; + theta = M_PI * (adjustedHour - adjustedNightStart) / nightDuration; } Vector3 final( cos( theta ), - -0.268, // approx tan( 15 degrees ) + -0.268f, // approx tan( -15 degrees ) sin( theta ) ); mRendering->setSunDirection( final, is_night ); } From df5a08b6de043ddde3f1f777921d55f9d43ab33b Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 15:01:49 +0100 Subject: [PATCH 132/214] Move manualref code out of header --- apps/openmw/mwclass/misc.cpp | 1 + apps/openmw/mwdialogue/scripttest.cpp | 1 + apps/openmw/mwgui/tradewindow.cpp | 1 + apps/openmw/mwmechanics/enchanting.cpp | 1 + apps/openmw/mwmechanics/levelledlist.hpp | 1 + apps/openmw/mwmechanics/obstacle.hpp | 2 - .../mwscript/transformationextensions.cpp | 1 + apps/openmw/mwworld/manualref.cpp | 67 +++++++++++++++++++ apps/openmw/mwworld/manualref.hpp | 62 +---------------- apps/openmw/mwworld/projectilemanager.cpp | 1 + 10 files changed, 75 insertions(+), 63 deletions(-) create mode 100644 apps/openmw/mwworld/manualref.cpp diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 271a7510e3..f9cfd8e0b6 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -12,6 +12,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/nullaction.hpp" diff --git a/apps/openmw/mwdialogue/scripttest.cpp b/apps/openmw/mwdialogue/scripttest.cpp index fd477365f0..3f46546100 100644 --- a/apps/openmw/mwdialogue/scripttest.cpp +++ b/apps/openmw/mwdialogue/scripttest.cpp @@ -3,6 +3,7 @@ #include #include "../mwworld/manualref.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 87b2362efa..40cf3e9bf7 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -16,6 +16,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 002831accb..de5921a702 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -2,6 +2,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index de652a9c84..691996410c 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -2,6 +2,7 @@ #define OPENMW_MECHANICS_LEVELLEDLIST_H #include "../mwworld/ptr.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index 76ab9d029b..e2d4d7b42c 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -1,8 +1,6 @@ #ifndef OPENMW_MECHANICS_OBSTACLE_H #define OPENMW_MECHANICS_OBSTACLE_H -//#include "../mwbase/world.hpp" -//#include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" namespace MWWorld diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index fcfc36995f..15fe580658 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -11,6 +11,7 @@ #include "../mwbase/environment.hpp" +#include "../mwworld/cellstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/player.hpp" diff --git a/apps/openmw/mwworld/manualref.cpp b/apps/openmw/mwworld/manualref.cpp new file mode 100644 index 0000000000..30b4fe353b --- /dev/null +++ b/apps/openmw/mwworld/manualref.cpp @@ -0,0 +1,67 @@ +#include "manualref.hpp" + +#include "esmstore.hpp" +#include "cellstore.hpp" + +namespace +{ + + template + void create(const MWWorld::Store& list, const std::string& name, boost::any& refValue, MWWorld::Ptr& ptrValue) + { + const T* base = list.find(name); + + ESM::CellRef cellRef; + cellRef.mRefNum.unset(); + cellRef.mRefID = name; + cellRef.mScale = 1; + cellRef.mFactionRank = 0; + cellRef.mChargeInt = -1; + cellRef.mGoldValue = 1; + cellRef.mEnchantmentCharge = -1; + cellRef.mTeleport = false; + cellRef.mLockLevel = 0; + cellRef.mReferenceBlocked = 0; + + MWWorld::LiveCellRef ref(cellRef, base); + + refValue = ref; + ptrValue = MWWorld::Ptr(&boost::any_cast&>(refValue), 0); + } +} + +MWWorld::ManualRef::ManualRef(const MWWorld::ESMStore& store, const std::string& name, const int count) +{ + std::string lowerName = Misc::StringUtils::lowerCase(name); + switch (store.find(lowerName)) + { + case ESM::REC_ACTI: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_ALCH: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_APPA: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_ARMO: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_BOOK: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_CLOT: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_CONT: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_CREA: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_DOOR: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_INGR: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_LEVC: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_LEVI: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_LIGH: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_LOCK: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_MISC: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_NPC_: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_PROB: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_REPA: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_STAT: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_WEAP: create(store.get(), lowerName, mRef, mPtr); break; + + case 0: + throw std::logic_error("failed to create manual cell ref for " + lowerName + " (unknown ID)"); + + default: + throw std::logic_error("failed to create manual cell ref for " + lowerName + " (unknown type)"); + } + + mPtr.getRefData().setCount(count); +} \ No newline at end of file diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index f32b074715..2fc5994710 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -3,9 +3,7 @@ #include -#include "esmstore.hpp" #include "ptr.hpp" -#include "cellstore.hpp" namespace MWWorld { @@ -18,66 +16,8 @@ namespace MWWorld ManualRef (const ManualRef&); ManualRef& operator= (const ManualRef&); - template - void create (const MWWorld::Store& list, const std::string& name) - { - const T* base = list.find(name); - - ESM::CellRef cellRef; - cellRef.mRefNum.unset(); - cellRef.mRefID = name; - cellRef.mScale = 1; - cellRef.mFactionRank = 0; - cellRef.mChargeInt = -1; - cellRef.mGoldValue = 1; - cellRef.mEnchantmentCharge = -1; - cellRef.mTeleport = false; - cellRef.mLockLevel = 0; - cellRef.mReferenceBlocked = 0; - - LiveCellRef ref(cellRef, base); - - mRef = ref; - mPtr = Ptr (&boost::any_cast&> (mRef), 0); - } - public: - - ManualRef (const MWWorld::ESMStore& store, const std::string& name, const int count=1) - { - std::string lowerName = Misc::StringUtils::lowerCase (name); - switch (store.find (lowerName)) - { - case ESM::REC_ACTI: create (store.get(), lowerName); break; - case ESM::REC_ALCH: create (store.get(), lowerName); break; - case ESM::REC_APPA: create (store.get(), lowerName); break; - case ESM::REC_ARMO: create (store.get(), lowerName); break; - case ESM::REC_BOOK: create (store.get(), lowerName); break; - case ESM::REC_CLOT: create (store.get(), lowerName); break; - case ESM::REC_CONT: create (store.get(), lowerName); break; - case ESM::REC_CREA: create (store.get(), lowerName); break; - case ESM::REC_DOOR: create (store.get(), lowerName); break; - case ESM::REC_INGR: create (store.get(), lowerName); break; - case ESM::REC_LEVC: create (store.get(), lowerName); break; - case ESM::REC_LEVI: create (store.get(), lowerName); break; - case ESM::REC_LIGH: create (store.get(), lowerName); break; - case ESM::REC_LOCK: create (store.get(), lowerName); break; - case ESM::REC_MISC: create (store.get(), lowerName); break; - case ESM::REC_NPC_: create (store.get(), lowerName); break; - case ESM::REC_PROB: create (store.get(), lowerName); break; - case ESM::REC_REPA: create (store.get(), lowerName); break; - case ESM::REC_STAT: create (store.get(), lowerName); break; - case ESM::REC_WEAP: create (store.get(), lowerName); break; - - case 0: - throw std::logic_error ("failed to create manual cell ref for " + lowerName + " (unknown ID)"); - - default: - throw std::logic_error ("failed to create manual cell ref for " + lowerName + " (unknown type)"); - } - - mPtr.getRefData().setCount(count); - } + ManualRef(const MWWorld::ESMStore& store, const std::string& name, const int count = 1); const Ptr& getPtr() const { diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 7af51fd28f..c97e4e3a50 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -9,6 +9,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwbase/soundmanager.hpp" From 8c49812d56f428c630fa3ab375e5a906f1b106e6 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 15:12:10 +0100 Subject: [PATCH 133/214] Remove unneeded include in obstacle.hpp --- apps/openmw/mwmechanics/aiwander.hpp | 1 + apps/openmw/mwmechanics/obstacle.hpp | 2 -- apps/openmw/mwworld/worldimp.cpp | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 975ebfb814..5e1b418139 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -17,6 +17,7 @@ namespace ESM { + class Cell; namespace AiSequence { struct AiWander; diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index e2d4d7b42c..e0ae9203d7 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -1,8 +1,6 @@ #ifndef OPENMW_MECHANICS_OBSTACLE_H #define OPENMW_MECHANICS_OBSTACLE_H -#include "../mwworld/cellstore.hpp" - namespace MWWorld { class Ptr; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a8238d161e..3ed2739671 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -44,6 +44,7 @@ #include "player.hpp" #include "manualref.hpp" +#include "cellstore.hpp" #include "cellfunctors.hpp" #include "containerstore.hpp" #include "inventorystore.hpp" From d3128a12b6bdb6deb579b4098e0f7e066358daf3 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 16:23:41 +0100 Subject: [PATCH 134/214] Remove a large include form mwbase/windowmanager.hpp --- apps/openmw/mwbase/windowmanager.hpp | 12 ++++++++++-- apps/openmw/mwgui/journalwindow.cpp | 1 + apps/openmw/mwgui/settingswindow.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.hpp | 1 + apps/openmw/mwmechanics/npcstats.hpp | 2 -- apps/openmw/mwscript/containerextensions.cpp | 2 ++ 7 files changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index c984b5e541..0d07312651 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -1,11 +1,11 @@ #ifndef GAME_MWBASE_WINDOWMANAGER_H #define GAME_MWBASE_WINDOWMANAGER_H +#include #include #include #include - -#include "../mwmechanics/stat.hpp" +#include #include "../mwgui/mode.hpp" @@ -42,6 +42,14 @@ namespace ESM struct CellId; } +namespace MWMechanics +{ + class AttributeValue; + template + class DynamicStat; + class SkillValue; +} + namespace MWWorld { class CellStore; diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index afff5601af..d7e27a2776 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 2810934522..a4f87e598b 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -14,6 +14,7 @@ #include +#include #include #include diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 715f47c46e..7f32f2b27d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -42,6 +42,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwmechanics/stat.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwsound/soundmanagerimp.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 9f01b136cf..dfeef982b4 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -12,6 +12,7 @@ #include "../mwbase/windowmanager.hpp" #include +#include #include "mapwindow.hpp" diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 224366a3e3..0b9090f285 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -6,8 +6,6 @@ #include #include -#include "stat.hpp" - #include "creaturestats.hpp" namespace ESM diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 58b1b375b4..69dfc9972b 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -14,6 +14,8 @@ #include #include +#include + #include #include "../mwbase/environment.hpp" From f2c5060cc09fd17a4fab0c5c4c36ca6c03e66670 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 16:37:20 +0100 Subject: [PATCH 135/214] Fix cstdint issue on travis GCC build --- apps/openmw/mwbase/windowmanager.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 0d07312651..36a99306b1 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWBASE_WINDOWMANAGER_H #define GAME_MWBASE_WINDOWMANAGER_H -#include +#include #include #include #include From cfcaf4528fa7f11a283afdd17276c4b5d1d9531c Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 16:50:34 +0100 Subject: [PATCH 136/214] Some more forward-declaring for OpenMW-CS --- apps/opencs/model/world/pathgrid.cpp | 3 ++- apps/opencs/model/world/pathgrid.hpp | 9 ++++++--- apps/opencs/model/world/subcellcollection.hpp | 11 ++++++++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/pathgrid.cpp b/apps/opencs/model/world/pathgrid.cpp index 1c82585df1..5c66e7d8ea 100644 --- a/apps/opencs/model/world/pathgrid.cpp +++ b/apps/opencs/model/world/pathgrid.cpp @@ -1,4 +1,5 @@ - +#include "cell.hpp" +#include "idcollection.hpp" #include "pathgrid.hpp" #include diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index 3c9fcff504..7ce5aff8c6 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -6,11 +6,14 @@ #include -#include "idcollection.hpp" -#include "cell.hpp" - namespace CSMWorld { + struct Cell; + template + struct IdAccessor; + template> + class IdCollection; + /// \brief Wrapper for Pathgrid record /// /// \attention The mData.mX and mData.mY fields of the ESM::Pathgrid struct are not used. diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index 28f0de6952..2100df4f49 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -1,10 +1,19 @@ #ifndef CSM_WOLRD_SUBCOLLECTION_H #define CSM_WOLRD_SUBCOLLECTION_H -#include "idcollection.hpp" +namespace ESM +{ + class ESMReader; +} namespace CSMWorld { + struct Cell; + template + struct IdAccessor; + template> + class IdCollection; + /// \brief Single type collection of top level records that are associated with cells template > class SubCellCollection : public IdCollection From f77ae711e426d873eefc8fc53af9a0b6b9c3b76b Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 17:10:09 +0100 Subject: [PATCH 137/214] Fix template closer --- apps/opencs/model/world/pathgrid.hpp | 2 +- apps/opencs/model/world/subcellcollection.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index 7ce5aff8c6..f13ad38c09 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -11,7 +11,7 @@ namespace CSMWorld struct Cell; template struct IdAccessor; - template> + template > class IdCollection; /// \brief Wrapper for Pathgrid record diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index 2100df4f49..4ed4308ea7 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -11,7 +11,7 @@ namespace CSMWorld struct Cell; template struct IdAccessor; - template> + template > class IdCollection; /// \brief Single type collection of top level records that are associated with cells From b714e5211d19a341a95bc10bcf4c9e0ef7271227 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 17:25:55 +0100 Subject: [PATCH 138/214] Redefinition of default template argument Sometimes it's annoying how MSVC casually allows you to break C++ standards --- apps/opencs/model/world/pathgrid.hpp | 4 +--- apps/opencs/model/world/subcellcollection.hpp | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index f13ad38c09..d8cc89f24f 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -9,9 +9,7 @@ namespace CSMWorld { struct Cell; - template - struct IdAccessor; - template > + template class IdCollection; /// \brief Wrapper for Pathgrid record diff --git a/apps/opencs/model/world/subcellcollection.hpp b/apps/opencs/model/world/subcellcollection.hpp index 4ed4308ea7..74bb6c9551 100644 --- a/apps/opencs/model/world/subcellcollection.hpp +++ b/apps/opencs/model/world/subcellcollection.hpp @@ -9,9 +9,7 @@ namespace ESM namespace CSMWorld { struct Cell; - template - struct IdAccessor; - template > + template class IdCollection; /// \brief Single type collection of top level records that are associated with cells From fce404acc5b09a8989444bd155f6fe939a4ac749 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 9 Feb 2015 17:45:48 +0100 Subject: [PATCH 139/214] Remove some including of mwbase/world.hpp Since ref.hpp is rather well used in OpenMW-CS this should help compile times there --- apps/openmw/mwscript/animationextensions.cpp | 1 + apps/openmw/mwscript/containerextensions.cpp | 1 + apps/openmw/mwscript/controlextensions.cpp | 1 + apps/openmw/mwscript/dialogueextensions.cpp | 1 + apps/openmw/mwscript/guiextensions.cpp | 2 +- apps/openmw/mwscript/miscextensions.cpp | 1 + apps/openmw/mwscript/ref.cpp | 29 ++++++++++++++++ apps/openmw/mwscript/ref.hpp | 33 +++++-------------- apps/openmw/mwscript/statsextensions.cpp | 1 + .../mwscript/transformationextensions.cpp | 1 + 10 files changed, 45 insertions(+), 26 deletions(-) create mode 100644 apps/openmw/mwscript/ref.cpp diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index 00b8a9620f..c43cdf5650 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -11,6 +11,7 @@ #include #include +#include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "interpretercontext.hpp" diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 69dfc9972b..86329191e3 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -20,6 +20,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index fb6b73be63..fd7fe47371 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -10,6 +10,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/inputmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index ea4b8d06e8..8b68052647 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -11,6 +11,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/journal.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwmechanics/npcstats.hpp" diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index f5549a1721..40c555f503 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -12,7 +12,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" - +#include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "interpretercontext.hpp" diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index bffeef768c..f4e82ebd4f 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -17,6 +17,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/scriptmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" diff --git a/apps/openmw/mwscript/ref.cpp b/apps/openmw/mwscript/ref.cpp new file mode 100644 index 0000000000..6347c2c2e5 --- /dev/null +++ b/apps/openmw/mwscript/ref.cpp @@ -0,0 +1,29 @@ +#include "ref.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "interpretercontext.hpp" + +MWWorld::Ptr MWScript::ExplicitRef::operator() (Interpreter::Runtime& runtime, bool required, + bool activeOnly) const +{ + std::string id = runtime.getStringLiteral(runtime[0].mInteger); + runtime.pop(); + + if (required) + return MWBase::Environment::get().getWorld()->getPtr(id, activeOnly); + else + return MWBase::Environment::get().getWorld()->searchPtr(id, activeOnly); +} + +MWWorld::Ptr MWScript::ImplicitRef::operator() (Interpreter::Runtime& runtime, bool required, + bool activeOnly) const +{ + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + return context.getReference(required); +} diff --git a/apps/openmw/mwscript/ref.hpp b/apps/openmw/mwscript/ref.hpp index 18f7453e44..e572f51471 100644 --- a/apps/openmw/mwscript/ref.hpp +++ b/apps/openmw/mwscript/ref.hpp @@ -3,14 +3,12 @@ #include -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - #include "../mwworld/ptr.hpp" -#include "interpretercontext.hpp" +namespace Interpreter +{ + class Runtime; +} namespace MWScript { @@ -18,31 +16,16 @@ namespace MWScript { static const bool implicit = false; - MWWorld::Ptr operator() (Interpreter::Runtime& runtime, bool required=true, - bool activeOnly = false) const - { - std::string id = runtime.getStringLiteral (runtime[0].mInteger); - runtime.pop(); - - if (required) - return MWBase::Environment::get().getWorld()->getPtr (id, activeOnly); - else - return MWBase::Environment::get().getWorld()->searchPtr (id, activeOnly); - } + MWWorld::Ptr operator() (Interpreter::Runtime& runtime, bool required = true, + bool activeOnly = false) const; }; struct ImplicitRef { static const bool implicit = true; - MWWorld::Ptr operator() (Interpreter::Runtime& runtime, bool required=true, - bool activeOnly = false) const - { - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - - return context.getReference(required); - } + MWWorld::Ptr operator() (Interpreter::Runtime& runtime, bool required = true, + bool activeOnly = false) const; }; } diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index abef636ccf..b8bb763885 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -18,6 +18,7 @@ #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 15fe580658..7af35a9ff6 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -10,6 +10,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/class.hpp" From a7320781a5e46400f359de39c032fbc233954919 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 9 Feb 2015 17:58:33 +0100 Subject: [PATCH 140/214] updated credits file --- AUTHORS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index bc39b1c703..59aa427218 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -33,7 +33,7 @@ Programmers Douglas Diniz (Dgdiniz) Douglas Mencken (dougmencken) dreamer-dead - dteviot + David Teviotdale (dteviot) Edmondo Tommasina (edmondo) Eduard Cot (trombonecot) Eli2 From dbd4abd6fe3ae3b3f1e812c8069b094bad50846e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Feb 2015 19:28:29 +0100 Subject: [PATCH 141/214] Fix ripples for D3D - added simpler effect (Fixes #1649) --- apps/openmw/engine.cpp | 1 + apps/openmw/mwrender/renderconst.hpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 3 +- apps/openmw/mwrender/ripplesimulation.cpp | 275 ++++++------------ apps/openmw/mwrender/ripplesimulation.hpp | 64 ++-- apps/openmw/mwrender/water.cpp | 20 +- apps/openmw/mwrender/water.hpp | 9 +- apps/openmw/mwworld/fallback.cpp | 9 + apps/openmw/mwworld/fallback.hpp | 1 + files/CMakeLists.txt | 7 +- files/materials/ripples.particle | 26 ++ files/materials/water.mat | 24 ++ files/materials/water.shader | 17 +- files/materials/watersim.mat | 59 ---- files/materials/watersim.shaderset | 31 -- files/materials/watersim_addimpulse.shader | 12 - files/materials/watersim_common.h | 25 -- files/materials/watersim_heightmap.shader | 51 ---- .../materials/watersim_heighttonormal.shader | 36 --- 19 files changed, 196 insertions(+), 475 deletions(-) create mode 100644 files/materials/ripples.particle delete mode 100644 files/materials/watersim.mat delete mode 100644 files/materials/watersim.shaderset delete mode 100644 files/materials/watersim_addimpulse.shader delete mode 100644 files/materials/watersim_common.h delete mode 100644 files/materials/watersim_heightmap.shader delete mode 100644 files/materials/watersim_heighttonormal.shader diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 859baebe4a..9b87c612d4 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -349,6 +349,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) addResourcesDirectory(mResDir / "mygui"); addResourcesDirectory(mResDir / "water"); addResourcesDirectory(mResDir / "shadows"); + addResourcesDirectory(mResDir / "materials"); OEngine::Render::WindowSettings windowSettings; windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index 4ac21ad510..cfd84cb32e 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -21,6 +21,7 @@ enum RenderQueueGroups RQG_UnderWater = Ogre::RENDER_QUEUE_4, RQG_Water = RQG_Alpha, + RQG_Ripples = RQG_Water+1, // Sky late (sun & sun flare) RQG_SkiesLate = Ogre::RENDER_QUEUE_SKIES_LATE diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 88ede1682c..8b7f04b19d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -175,7 +175,7 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b mDebugging = new Debugging(mRootNode, engine); mLocalMap = new MWRender::LocalMap(&mRendering, this); - mWater = new MWRender::Water(mRendering.getCamera(), this); + mWater = new MWRender::Water(mRendering.getCamera(), this, mFallback); setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); } @@ -693,6 +693,7 @@ void RenderingManager::enableLights(bool sun) void RenderingManager::notifyWorldSpaceChanged() { mEffectManager->clear(); + mWater->clearRipples(); } Ogre::Vector4 RenderingManager::boundingBoxToScreen(Ogre::AxisAlignedBox bounds) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 64b5e48c38..84794162f3 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -1,162 +1,72 @@ #include "ripplesimulation.hpp" -#include -#include -#include -#include -#include +#include + #include -#include -#include +#include +#include +#include #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwworld/fallback.hpp" + +#include "renderconst.hpp" + namespace MWRender { - -RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) - : mMainSceneMgr(mainSceneManager), - mTime(0), - mCurrentFrameOffset(0,0), - mPreviousFrameOffset(0,0), - mRippleCenter(0,0), - mTextureSize(512), - mRippleAreaLength(1000), - mImpulseSize(20), - mTexelOffset(0,0), - mFirstUpdate(true), - mRectangle(NULL), - mImpulse(NULL) +RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager, const MWWorld::Fallback* fallback) + : mSceneMgr(mainSceneManager) + , mParticleSystem(NULL) + , mSceneNode(NULL) { - Ogre::AxisAlignedBox aabInf; - aabInf.setInfinite(); + mRippleLifeTime = fallback->getFallbackFloat("Water_RippleLifetime"); + mRippleRotSpeed = fallback->getFallbackFloat("Water_RippleRotSpeed"); - mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); + // Unknown: + // fallback=Water_RippleScale,0.15, 6.5 + // fallback=Water_RippleAlphas,0.7, 0.1, 0.01 - mCamera = mSceneMgr->createCamera("RippleCamera"); + // Instantiate from ripples.particle file + mParticleSystem = mSceneMgr->createParticleSystem("openmw/Ripples", "openmw/Ripples"); - mRectangle = new Ogre::Rectangle2D(true); - mRectangle->setBoundingBox(aabInf); - mRectangle->setCorners(-1.0, 1.0, 1.0, -1.0, false); - Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - node->attachObject(mRectangle); + mParticleSystem->setRenderQueueGroup(RQG_Ripples); + mParticleSystem->setVisibilityFlags(RV_Effects); - mImpulse = new Ogre::Rectangle2D(true); - mImpulse->setCorners(-0.1, 0.1, 0.1, -0.1, false); - mImpulse->setBoundingBox(aabInf); - mImpulse->setMaterial("AddImpulse"); - Ogre::SceneNode* impulseNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - impulseNode->attachObject(mImpulse); + int rippleFrameCount = fallback->getFallbackInt("Water_RippleFrameCount"); + std::string tex = fallback->getFallbackString("Water_RippleTexture"); - //float w=0.05; - for (int i=0; i<4; ++i) - { - Ogre::TexturePtr texture; - if (i != 3) - texture = Ogre::TextureManager::getSingleton().createManual("RippleHeight" + Ogre::StringConverter::toString(i), - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mTextureSize, mTextureSize, 1, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); - else - texture = Ogre::TextureManager::getSingleton().createManual("RippleNormal", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mTextureSize, mTextureSize, 1, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); + sh::MaterialInstance* mat = sh::Factory::getInstance().getMaterialInstance("openmw/Ripple"); + mat->setProperty("anim_texture2", sh::makeProperty(new sh::StringValue(std::string("textures\\water\\") + tex + ".dds " + + Ogre::StringConverter::toString(rippleFrameCount) + + " " + + Ogre::StringConverter::toString(0.3)))); + // seems to be required to allocate mFreeParticles. TODO: patch Ogre to handle this better + mParticleSystem->_update(0.f); - Ogre::RenderTexture* rt = texture->getBuffer()->getRenderTarget(); - rt->removeAllViewports(); - rt->addViewport(mCamera); - rt->setAutoUpdated(false); - rt->getViewport(0)->setClearEveryFrame(false); - - // debug overlay - /* - Ogre::Rectangle2D* debugOverlay = new Ogre::Rectangle2D(true); - debugOverlay->setCorners(w*2-1, 0.9, (w+0.18)*2-1, 0.4, false); - w += 0.2; - debugOverlay->setBoundingBox(aabInf); - Ogre::SceneNode* debugNode = mMainSceneMgr->getRootSceneNode()->createChildSceneNode(); - debugNode->attachObject(debugOverlay); - - Ogre::MaterialPtr debugMaterial = Ogre::MaterialManager::getSingleton().create("RippleDebug" + Ogre::StringConverter::toString(i), - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - - if (i != 3) - debugMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("RippleHeight" + Ogre::StringConverter::toString(i)); - else - debugMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("RippleNormal"); - debugMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); - - debugOverlay->setMaterial("RippleDebug" + Ogre::StringConverter::toString(i)); - */ - - mRenderTargets[i] = rt; - mTextures[i] = texture; - } - - sh::Factory::getInstance().setSharedParameter("rippleTextureSize", sh::makeProperty( - new sh::Vector4(1.0/512, 1.0/512, 512, 512))); - sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty( - new sh::Vector3(0, 0, 0))); - sh::Factory::getInstance().setSharedParameter("rippleAreaLength", sh::makeProperty( - new sh::FloatValue(mRippleAreaLength))); - + mSceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); + mSceneNode->attachObject(mParticleSystem); } RippleSimulation::~RippleSimulation() { - delete mRectangle; - delete mImpulse; + if (mParticleSystem) + mSceneMgr->destroyParticleSystem(mParticleSystem); + mParticleSystem = NULL; - Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + if (mSceneNode) + mSceneMgr->destroySceneNode(mSceneNode); + mSceneNode = NULL; } void RippleSimulation::update(float dt, Ogre::Vector2 position) { - // try to keep 20 fps - mTime += dt; - - while (mTime >= 1/20.0 || mFirstUpdate) - { - mPreviousFrameOffset = mCurrentFrameOffset; - - mCurrentFrameOffset = position - mRippleCenter; - // add texel offsets from previous frame. - mCurrentFrameOffset += mTexelOffset; - - mTexelOffset = Ogre::Vector2(std::fmod(mCurrentFrameOffset.x, 1.0f/mTextureSize), - std::fmod(mCurrentFrameOffset.y, 1.0f/mTextureSize)); - - // now subtract new offset in order to snap to texels - mCurrentFrameOffset -= mTexelOffset; - - // texture coordinate space - mCurrentFrameOffset /= mRippleAreaLength; - - mRippleCenter = position; - - addImpulses(); - waterSimulation(); - heightMapToNormalMap(); - - swapHeightMaps(); - if (!mFirstUpdate) - mTime -= 1/20.0; - else - mFirstUpdate = false; - } - - sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty( - new sh::Vector3(mRippleCenter.x + mTexelOffset.x, mRippleCenter.y + mTexelOffset.y, 0))); -} - -void RippleSimulation::addImpulses() -{ - mRectangle->setVisible(false); - mImpulse->setVisible(true); - - /// \todo it should be more efficient to render all emitters at once + bool newParticle = false; for (std::vector::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it) { if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayerPtr()) @@ -165,69 +75,50 @@ void RippleSimulation::addImpulses() // for non-player actors this is done in updateObjectCell it->mPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); } - const float* _currentPos = it->mPtr.getRefData().getPosition().pos; - Ogre::Vector3 currentPos (_currentPos[0], _currentPos[1], _currentPos[2]); - - if ( (currentPos - it->mLastEmitPosition).length() > 2 - && MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), currentPos)) + Ogre::Vector3 currentPos (it->mPtr.getRefData().getPosition().pos); + currentPos.z = 0; + if ( (currentPos - it->mLastEmitPosition).length() > 10 + // Only emit when close to the water surface, not above it and not too deep in the water + && MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), + Ogre::Vector3(it->mPtr.getRefData().getPosition().pos)) + && !MWBase::Environment::get().getWorld()->isSubmerged(it->mPtr)) { it->mLastEmitPosition = currentPos; - Ogre::Vector2 pos (currentPos.x, currentPos.y); - pos -= mRippleCenter; - pos /= mRippleAreaLength; - float size = mImpulseSize / mRippleAreaLength; - mImpulse->setCorners(pos.x-size, pos.y+size, pos.x+size, pos.y-size, false); - - // don't render if we are offscreen - if (pos.x - size >= 1.0 || pos.y+size <= -1.0 || pos.x+size <= -1.0 || pos.y-size >= 1.0) - continue; - mRenderTargets[1]->update(); + newParticle = true; + Ogre::Particle* created = mParticleSystem->createParticle(); + if (!created) + break; // TODO: cleanup the oldest particle to make room +#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) + Ogre::Vector3& position = created->mPosition; + Ogre::Vector3& direction = created->mDirection; + Ogre::ColourValue& colour = created->mColour; + float& totalTimeToLive = created->mTotalTimeToLive; + float& timeToLive = created->mTimeToLive; + Ogre::Radian& rotSpeed = created->mRotationSpeed; + Ogre::Radian& rotation = created->mRotation; +#else + Ogre::Vector3& position = created->position; + Ogre::Vector3& direction = created->direction; + Ogre::ColourValue& colour = created->colour; + float& totalTimeToLive = created->totalTimeToLive; + float& timeToLive = created->timeToLive; + Ogre::Radian& rotSpeed = created->rotationSpeed; + Ogre::Radian& rotation = created->rotation; +#endif + timeToLive = totalTimeToLive = mRippleLifeTime; + colour = Ogre::ColourValue(0.f, 0.f, 0.f, 0.7); // Water_RippleAlphas.x? + direction = Ogre::Vector3(0,0,0); + position = currentPos; + position.z = 0; // Z is set by the Scene Node + rotSpeed = mRippleRotSpeed; + rotation = Ogre::Radian(Ogre::Math::RangeRandom(-Ogre::Math::PI, Ogre::Math::PI)); + created->setDimensions(50,50); } } - mImpulse->setVisible(false); - mRectangle->setVisible(true); -} - -void RippleSimulation::waterSimulation() -{ - mRectangle->setMaterial("HeightmapSimulation"); - - sh::Factory::getInstance().setTextureAlias("Heightmap0", mTextures[0]->getName()); - sh::Factory::getInstance().setTextureAlias("Heightmap1", mTextures[1]->getName()); - - sh::Factory::getInstance().setSharedParameter("currentFrameOffset", sh::makeProperty( - new sh::Vector3(mCurrentFrameOffset.x, mCurrentFrameOffset.y, 0))); - sh::Factory::getInstance().setSharedParameter("previousFrameOffset", sh::makeProperty( - new sh::Vector3(mPreviousFrameOffset.x, mPreviousFrameOffset.y, 0))); - - mRenderTargets[2]->update(); -} - -void RippleSimulation::heightMapToNormalMap() -{ - mRectangle->setMaterial("HeightToNormalMap"); - - sh::Factory::getInstance().setTextureAlias("Heightmap2", mTextures[2]->getName()); - - mRenderTargets[TEX_NORMAL]->update(); -} - -void RippleSimulation::swapHeightMaps() -{ - // 0 -> 1 -> 2 to 2 -> 0 ->1 - Ogre::RenderTexture* tmp = mRenderTargets[0]; - Ogre::TexturePtr tmp2 = mTextures[0]; - - mRenderTargets[0] = mRenderTargets[1]; - mTextures[0] = mTextures[1]; - - mRenderTargets[1] = mRenderTargets[2]; - mTextures[1] = mTextures[2]; - - mRenderTargets[2] = tmp; - mTextures[2] = tmp2; + if (newParticle) // now apparently needs another update, otherwise it won't render in the first frame after a particle is created. TODO: patch Ogre to handle this better + mParticleSystem->_update(0.f); } void RippleSimulation::addEmitter(const MWWorld::Ptr& ptr, float scale, float force) @@ -264,5 +155,15 @@ void RippleSimulation::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld: } } +void RippleSimulation::setWaterHeight(float height) +{ + mSceneNode->setPosition(0,0,height); +} + +void RippleSimulation::clear() +{ + mParticleSystem->clear(); +} + } diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index e203212cf0..4551476a4c 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -1,19 +1,19 @@ #ifndef RIPPLE_SIMULATION_H #define RIPPLE_SIMULATION_H -#include -#include -#include #include #include "../mwworld/ptr.hpp" namespace Ogre { - class RenderTexture; - class Camera; class SceneManager; - class Rectangle2D; + class ParticleSystem; +} + +namespace MWWorld +{ + class Fallback; } namespace MWRender @@ -30,9 +30,11 @@ struct Emitter class RippleSimulation { public: - RippleSimulation(Ogre::SceneManager* mainSceneManager); + RippleSimulation(Ogre::SceneManager* mainSceneManager, const MWWorld::Fallback* fallback); ~RippleSimulation(); + /// @param dt Time since the last frame + /// @param position Position of the player void update(float dt, Ogre::Vector2 position); /// adds an emitter, position will be tracked automatically @@ -40,47 +42,21 @@ public: void removeEmitter (const MWWorld::Ptr& ptr); void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); + /// Change the height of the water surface, thus moving all ripples with it + void setWaterHeight(float height); + + /// Remove all active ripples + void clear(); + private: - RippleSimulation(const RippleSimulation&); - RippleSimulation& operator=(const RippleSimulation&); + Ogre::SceneManager* mSceneMgr; + Ogre::ParticleSystem* mParticleSystem; + Ogre::SceneNode* mSceneNode; std::vector mEmitters; - Ogre::RenderTexture* mRenderTargets[4]; - Ogre::TexturePtr mTextures[4]; - - int mTextureSize; - float mRippleAreaLength; - float mImpulseSize; - - bool mFirstUpdate; - - Ogre::Camera* mCamera; - - // own scenemanager to render our simulation - Ogre::SceneManager* mSceneMgr; - Ogre::Rectangle2D* mRectangle; - - // scenemanager to create the debug overlays on - Ogre::SceneManager* mMainSceneMgr; - - static const int TEX_NORMAL = 3; - - Ogre::Rectangle2D* mImpulse; - - void addImpulses(); - void heightMapToNormalMap(); - void waterSimulation(); - void swapHeightMaps(); - - float mTime; - - Ogre::Vector2 mRippleCenter; - - Ogre::Vector2 mTexelOffset; - - Ogre::Vector2 mCurrentFrameOffset; - Ogre::Vector2 mPreviousFrameOffset; + float mRippleLifeTime; + float mRippleRotSpeed; }; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 44e1842696..456fc47e97 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -20,9 +20,6 @@ #include #include -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - using namespace Ogre; namespace MWRender @@ -187,7 +184,7 @@ void PlaneReflection::setVisibilityMask (int flags) // -------------------------------------------------------------------------------------------------------------------------------- -Water::Water (Ogre::Camera *camera, RenderingManager* rend) : +Water::Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallback* fallback) : mCamera (camera), mSceneMgr (camera->getSceneManager()), mIsUnderwater(false), mVisibilityFlags(0), mActive(1), mToggled(1), @@ -198,7 +195,7 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend) : mSimulation(NULL), mPlayer(0,0) { - mSimulation = new RippleSimulation(mSceneMgr); + mSimulation = new RippleSimulation(mSceneMgr, fallback); mSky = rend->getSkyManager(); @@ -313,6 +310,8 @@ void Water::setHeight(const float height) { mTop = height; + mSimulation->setWaterHeight(height); + mWaterPlane = Plane(Vector3::UNIT_Z, -height); if (mReflection) @@ -382,9 +381,13 @@ void Water::update(float dt, Ogre::Vector3 player) void Water::frameStarted(float dt) { + if (!mActive) + return; + + mSimulation->update(dt, mPlayer); + if (mReflection) { - mSimulation->update(dt, mPlayer); mReflection->update(); } } @@ -497,4 +500,9 @@ void Water::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) mSimulation->updateEmitterPtr(old, ptr); } +void Water::clearRipples() +{ + mSimulation->clear(); +} + } // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 6a7b05a3aa..10d0a06ffb 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -30,6 +30,11 @@ namespace Ogre struct RenderTargetEvent; } +namespace MWWorld +{ + class Fallback; +} + namespace MWRender { class SkyManager; @@ -145,9 +150,11 @@ namespace MWRender { Ogre::Vector2 mPlayer; public: - Water (Ogre::Camera *camera, RenderingManager* rend); + Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallback* fallback); ~Water(); + void clearRipples(); + void setActive(bool active); bool toggle(); diff --git a/apps/openmw/mwworld/fallback.cpp b/apps/openmw/mwworld/fallback.cpp index c0b21b2ef2..3a8154ca7c 100644 --- a/apps/openmw/mwworld/fallback.cpp +++ b/apps/openmw/mwworld/fallback.cpp @@ -22,6 +22,15 @@ namespace MWWorld else return boost::lexical_cast(fallback); } + int Fallback::getFallbackInt(const std::string& fall) const + { + std::string fallback=getFallbackString(fall); + if(fallback.empty()) + return 0; + else + return boost::lexical_cast(fallback); + } + bool Fallback::getFallbackBool(const std::string& fall) const { std::string fallback=getFallbackString(fall); diff --git a/apps/openmw/mwworld/fallback.hpp b/apps/openmw/mwworld/fallback.hpp index 6c5802e071..f69a5e57bb 100644 --- a/apps/openmw/mwworld/fallback.hpp +++ b/apps/openmw/mwworld/fallback.hpp @@ -15,6 +15,7 @@ namespace MWWorld Fallback(const std::map& fallback); std::string getFallbackString(const std::string& fall) const; float getFallbackFloat(const std::string& fall) const; + int getFallbackInt(const std::string& fall) const; bool getFallbackBool(const std::string& fall) const; Ogre::ColourValue getFallbackColour(const std::string& fall) const; }; diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 9b2325744e..da3451d93e 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -38,15 +38,10 @@ set(MATERIAL_FILES selection.mat selection.shader selection.shaderset - watersim_heightmap.shader - watersim_addimpulse.shader - watersim_heighttonormal.shader - watersim_common.h - watersim.mat - watersim.shaderset mygui.mat mygui.shader mygui.shaderset + ripples.particle ) copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") diff --git a/files/materials/ripples.particle b/files/materials/ripples.particle new file mode 100644 index 0000000000..e8402b6914 --- /dev/null +++ b/files/materials/ripples.particle @@ -0,0 +1,26 @@ +particle_system openmw/Ripples +{ + material openmw/Ripple + particle_width 50 + particle_height 50 + // To make the particles move with the scene node when the waterlevel changes + local_space true + quota 300 + billboard_type perpendicular_common + common_up_vector 0 1 0 + common_direction 0 0 1 + + affector ColourFader + { + alpha -0.33 + } + + affector Scaler + { + rate 100 + } + + affector Rotator + { + } +} diff --git a/files/materials/water.mat b/files/materials/water.mat index ade55f326f..cf03be39e5 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -75,3 +75,27 @@ material Water } } } + +material openmw/Ripple +{ + // this will be overridden by Water_RippleFrameCount fallback setting + anim_texture2 textures\water\ripple.dds 4 0.25 + pass + { + scene_blend alpha_blend + depth_write off + cull_hardware none + diffuse vertexcolour + emissive 1 1 1 + ambient 0 0 0 + texture_unit diffuseMap + { + create_in_ffp true + anim_texture2 $anim_texture2 + + // to make sure rotating doesn't cause the texture to repeat + tex_address_mode border + tex_border_colour 0 0 0 0 + } + } +} diff --git a/files/materials/water.shader b/files/materials/water.shader index 4dec57276d..373277d0b4 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -64,7 +64,6 @@ #include "shadows.h" #endif -#define RIPPLES 1 #define REFRACTION @shGlobalSettingBool(refraction) #ifdef SH_VERTEX_SHADER @@ -187,11 +186,6 @@ shInput(float3, screenCoordsPassthrough) shInput(float4, position) shInput(float, depthPassthrough) - - #if RIPPLES - shUniform(float3, rippleCenter) @shSharedParameter(rippleCenter, rippleCenter) - shUniform(float, rippleAreaLength) @shSharedParameter(rippleAreaLength, rippleAreaLength) - #endif shUniform(float, far) @shAutoConstant(far, far_clip_distance) @@ -203,10 +197,6 @@ shSampler2D(normalMap) shUniform(float4x4, wMat) @shAutoConstant(wMat, world_matrix) - - #if RIPPLES - shSampler2D(rippleNormalMap) - #endif shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) #define WIND_SPEED windDir_windSpeed.z @@ -296,12 +286,7 @@ normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y); - float4 worldPosition = shMatrixMult(wMat, float4(position.xyz, 1)); - float2 relPos = (worldPosition.xy - rippleCenter.xy) / rippleAreaLength + 0.5; - float3 normal_ripple = normalize(shSample(rippleNormalMap, relPos.xy).xyz * 2.0 - 1.0); - - //normal = normalize(normal + normal_ripple); - normal = normalize(float3(normal.x * BUMP + normal_ripple.x, normal.y * BUMP + normal_ripple.y, normal.z)); + normal = normalize(float3(normal.x * BUMP, normal.y * BUMP, normal.z)); normal = float3(normal.x, normal.y, -normal.z); // normal for sunlight scattering diff --git a/files/materials/watersim.mat b/files/materials/watersim.mat deleted file mode 100644 index b58b1a8512..0000000000 --- a/files/materials/watersim.mat +++ /dev/null @@ -1,59 +0,0 @@ -material HeightmapSimulation -{ - allow_fixed_function false - pass - { - depth_check off - depth_write off - vertex_program transform_vertex - fragment_program watersim_fragment - - texture_unit heightPrevSampler - { - tex_address_mode border - tex_border_colour 0 0 0 - texture_alias Heightmap0 - } - texture_unit heightCurrentSampler - { - tex_address_mode border - tex_border_colour 0 0 0 - texture_alias Heightmap1 - } - } -} - -material HeightToNormalMap -{ - allow_fixed_function false - pass - { - depth_check off - depth_write off - vertex_program transform_vertex - fragment_program height_to_normal_fragment - - texture_unit heightCurrentSampler - { - texture_alias Heightmap2 - } - } -} - -material AddImpulse -{ - allow_fixed_function false - pass - { - depth_check off - depth_write off - scene_blend alpha_blend - vertex_program transform_vertex - fragment_program add_impulse_fragment - - texture_unit alphaMap - { - texture circle.png - } - } -} diff --git a/files/materials/watersim.shaderset b/files/materials/watersim.shaderset deleted file mode 100644 index ea512e25f0..0000000000 --- a/files/materials/watersim.shaderset +++ /dev/null @@ -1,31 +0,0 @@ -shader_set transform_vertex -{ - source quad.shader - type vertex - profiles_cg vs_2_0 vp40 arbvp1 - profiles_hlsl vs_2_0 -} - -shader_set watersim_fragment -{ - source watersim_heightmap.shader - type fragment - profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 - profiles_hlsl ps_3_0 ps_2_0 -} - -shader_set height_to_normal_fragment -{ - source watersim_heighttonormal.shader - type fragment - profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 - profiles_hlsl ps_3_0 ps_2_0 -} - -shader_set add_impulse_fragment -{ - source watersim_addimpulse.shader - type fragment - profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 - profiles_hlsl ps_3_0 ps_2_0 -} diff --git a/files/materials/watersim_addimpulse.shader b/files/materials/watersim_addimpulse.shader deleted file mode 100644 index 3ca4192cd7..0000000000 --- a/files/materials/watersim_addimpulse.shader +++ /dev/null @@ -1,12 +0,0 @@ -#include "core.h" -#include "watersim_common.h" - - SH_BEGIN_PROGRAM - shInput(float2, UV) - shSampler2D(alphaMap) - - SH_START_PROGRAM - { - shOutputColour(0) = EncodeHeightmap(1.0); - shOutputColour(0).a = shSample (alphaMap, UV.xy).a; - } diff --git a/files/materials/watersim_common.h b/files/materials/watersim_common.h deleted file mode 100644 index aa7a636a06..0000000000 --- a/files/materials/watersim_common.h +++ /dev/null @@ -1,25 +0,0 @@ -float DecodeHeightmap(float4 heightmap) -{ - float4 table = float4(1.0, -1.0, 0.0, 0.0); - return dot(heightmap, table); -} - -float DecodeHeightmap(shTexture2D HeightmapSampler, float2 texcoord) -{ - float4 heightmap = shSample(HeightmapSampler, texcoord); - return DecodeHeightmap(heightmap); -} - -float4 EncodeHeightmap(float fHeight) -{ - float h = fHeight; - float positive = fHeight > 0.0 ? fHeight : 0.0; - float negative = fHeight < 0.0 ? -fHeight : 0.0; - - float4 color = float4(0,0,0,0); - - color.r = positive; - color.g = negative; - - return color; -} diff --git a/files/materials/watersim_heightmap.shader b/files/materials/watersim_heightmap.shader deleted file mode 100644 index ec8ae4174a..0000000000 --- a/files/materials/watersim_heightmap.shader +++ /dev/null @@ -1,51 +0,0 @@ -#include "core.h" - -#define DAMPING 0.95 - -#include "watersim_common.h" - - SH_BEGIN_PROGRAM - shInput(float2, UV) - shSampler2D(heightPrevSampler) - shSampler2D(heightCurrentSampler) - shUniform(float3, previousFrameOffset) @shSharedParameter(previousFrameOffset, previousFrameOffset) - shUniform(float3, currentFrameOffset) @shSharedParameter(currentFrameOffset, currentFrameOffset) - shUniform(float4, rippleTextureSize) @shSharedParameter(rippleTextureSize, rippleTextureSize) - - SH_START_PROGRAM - { -#if !SH_HLSL - const float3 offset[4] = float3[4]( - float3(-1.0, 0.0, 0.25), - float3( 1.0, 0.0, 0.25), - float3( 0.0,-1.0, 0.25), - float3( 0.0, 1.0, 0.25) - ); -#else - const float3 offset[4] = { - float3(-1.0, 0.0, 0.25), - float3( 1.0, 0.0, 0.25), - float3( 0.0,-1.0, 0.25), - float3( 0.0, 1.0, 0.25) - }; -#endif - - float fHeightPrev = DecodeHeightmap(heightPrevSampler, UV.xy + previousFrameOffset.xy + currentFrameOffset.xy); - - float fNeighCurrent = 0; - for ( int i=0; i<4; i++ ) - { - float2 vTexcoord = UV + currentFrameOffset.xy + offset[i].xy * rippleTextureSize.xy; - fNeighCurrent += (DecodeHeightmap(heightCurrentSampler, vTexcoord) * offset[i].z); - } - - float fHeight = fNeighCurrent * 2.0 - fHeightPrev; - - fHeight *= DAMPING; - - shOutputColour(0) = EncodeHeightmap(fHeight); - } - - - - diff --git a/files/materials/watersim_heighttonormal.shader b/files/materials/watersim_heighttonormal.shader deleted file mode 100644 index eaa4af4983..0000000000 --- a/files/materials/watersim_heighttonormal.shader +++ /dev/null @@ -1,36 +0,0 @@ -#include "core.h" -#include "watersim_common.h" - - SH_BEGIN_PROGRAM - shInput(float2, UV) - shSampler2D(heightCurrentSampler) - shUniform(float4, rippleTextureSize) @shSharedParameter(rippleTextureSize, rippleTextureSize) - - SH_START_PROGRAM - { -#if !SH_HLSL - float2 offset[4] = float2[4] ( - float2(-1.0, 0.0), - float2( 1.0, 0.0), - float2( 0.0,-1.0), - float2( 0.0, 1.0) - ); -#else - float2 offset[4] = { - float2(-1.0, 0.0), - float2( 1.0, 0.0), - float2( 0.0,-1.0), - float2( 0.0, 1.0) - }; -#endif - - float fHeightL = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[0]*rippleTextureSize.xy); - float fHeightR = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[1]*rippleTextureSize.xy); - float fHeightT = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[2]*rippleTextureSize.xy); - float fHeightB = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[3]*rippleTextureSize.xy); - - float3 n = float3(fHeightB - fHeightT, fHeightR - fHeightL, 1.0); - float3 normal = (n + 1.0) * 0.5; - - shOutputColour(0) = float4(normal.rgb, 1.0); - } From 801c0eb57c4300ffb35556711a84411a1b62b28a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Feb 2015 17:34:08 +0100 Subject: [PATCH 142/214] Detect Creature should detect alive creatures only (Fixes #2353) --- apps/openmw/mwworld/worldimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a60eae48a3..0694a3da6b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2886,6 +2886,9 @@ namespace MWWorld } else if (ptr.getClass().getTypeName() != typeid(ESM::Creature).name()) return false; + + if (ptr.getClass().getCreatureStats(ptr).isDead()) + return false; } if (mType == World::Detect_Key && !ptr.getClass().isKey(ptr)) return false; From 03257ecae538feb9fdd1482629a16883c57ca191 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Feb 2015 18:05:02 +0100 Subject: [PATCH 143/214] QString encoding fix --- apps/launcher/graphicspage.cpp | 10 +++++----- apps/launcher/main.cpp | 2 +- components/contentselector/model/contentmodel.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index dccf8bb8ce..cdb51348c8 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -67,7 +67,7 @@ bool Launcher::GraphicsPage::setupOgre() } catch(Ogre::Exception &ex) { - QString ogreError = QString::fromStdString(ex.getFullDescription().c_str()); + QString ogreError = QString::fromUtf8(ex.getFullDescription().c_str()); QMessageBox msgBox; msgBox.setWindowTitle("Error creating Ogre::Root"); msgBox.setIcon(QMessageBox::Critical); @@ -135,7 +135,7 @@ bool Launcher::GraphicsPage::setupSDL() msgBox.setWindowTitle(tr("Error receiving number of screens")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
SDL_GetNumDisplayModes failed:

") + QString::fromStdString(SDL_GetError()) + "
"); + msgBox.setText(tr("
SDL_GetNumDisplayModes failed:

") + QString::fromUtf8(SDL_GetError()) + "
"); msgBox.exec(); return false; } @@ -237,7 +237,7 @@ QStringList Launcher::GraphicsPage::getAvailableOptions(const QString &key, Ogre opt_it != i->second.possibleValues.end(); ++opt_it, ++idx) { if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) { - result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromStdString((*opt_it).c_str()).simplified(); + result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromUtf8((*opt_it).c_str()).simplified(); } } } @@ -266,7 +266,7 @@ QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen) msgBox.setWindowTitle(tr("Error receiving resolutions")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
SDL_GetNumDisplayModes failed:

") + QString::fromStdString(SDL_GetError()) + "
"); + msgBox.setText(tr("
SDL_GetNumDisplayModes failed:

") + QString::fromUtf8(SDL_GetError()) + "
"); msgBox.exec(); return result; } @@ -279,7 +279,7 @@ QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen) msgBox.setWindowTitle(tr("Error receiving resolutions")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
SDL_GetDisplayMode failed:

") + QString::fromStdString(SDL_GetError()) + "
"); + msgBox.setText(tr("
SDL_GetDisplayMode failed:

") + QString::fromUtf8(SDL_GetError()) + "
"); msgBox.exec(); return result; } diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 5c3f384581..11ea568692 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -24,7 +24,7 @@ int main(int argc, char *argv[]) SDL_SetMainReady(); if (SDL_Init(SDL_INIT_VIDEO) != 0) { - qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError()); + qDebug() << "SDL_Init failed: " << QString::fromUtf8(SDL_GetError()); return 0; } signal(SIGINT, SIG_DFL); // We don't want to use the SDL event loop in the launcher, diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 56a86f87f6..ec1fcc21e4 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -459,7 +459,7 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) EsmFile *file = new EsmFile(path); foreach (const ESM::Header::MasterData &item, fileReader.getGameFiles()) - file->addGameFile(QString::fromStdString(item.name)); + file->addGameFile(QString::fromUtf8(item.name.c_str())); file->setAuthor (QString::fromUtf8(fileReader.getAuthor().c_str())); file->setDate (info.lastModified()); From 399c24c64668046f879e788418def56285dd5d8f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Feb 2015 23:27:32 +0100 Subject: [PATCH 144/214] CMake cleanup: remove redundant setting of Permissions to default values --- CMakeLists.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b80d4c956..ed4136813c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -438,23 +438,23 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" ) # Install icon and desktop file - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") - INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + 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") IF(BUILD_OPENCS) - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") - INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "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") ENDIF(BUILD_OPENCS) # Install global configuration files - INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw") IF(BUILD_OPENCS) - INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") + INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs") ENDIF(BUILD_OPENCS) # Install resources - INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT "Resources") + INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" COMPONENT "Resources") INSTALL(DIRECTORY DESTINATION "${DATADIR}/data" COMPONENT "Resources") ENDIF(NOT WIN32 AND NOT APPLE) From 218f789d88ac1ea46ba9675dc9dcd67009602184 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Feb 2015 01:08:07 +0100 Subject: [PATCH 145/214] Fix player DrawState reset when selecting enchanted item (Fixes #2356) --- apps/openmw/mwgui/spellwindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 6d3c79b349..69365c1081 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -95,8 +95,9 @@ namespace MWGui return; } - MWBase::Environment::get().getWindowManager()->unsetSelectedSpell(); store.setSelectedEnchantItem(it); + // to reset WindowManager::mSelectedSpell immediately + MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(*it); updateSpells(); } From ee574e08ef48c2496ad522c9fa8aecd5b218dccc Mon Sep 17 00:00:00 2001 From: jacmoe Date: Tue, 3 Feb 2015 23:12:33 +0100 Subject: [PATCH 146/214] MIT License header added to all terrain component files. --- components/terrain/buffercache.cpp | 21 +++++++++++++++++++++ components/terrain/buffercache.hpp | 21 +++++++++++++++++++++ components/terrain/chunk.cpp | 21 +++++++++++++++++++++ components/terrain/chunk.hpp | 21 +++++++++++++++++++++ components/terrain/defaultworld.cpp | 21 +++++++++++++++++++++ components/terrain/defaultworld.hpp | 21 +++++++++++++++++++++ components/terrain/defs.hpp | 21 +++++++++++++++++++++ components/terrain/material.cpp | 21 +++++++++++++++++++++ components/terrain/material.hpp | 21 +++++++++++++++++++++ components/terrain/quadtreenode.cpp | 21 +++++++++++++++++++++ components/terrain/quadtreenode.hpp | 21 +++++++++++++++++++++ components/terrain/storage.cpp | 21 +++++++++++++++++++++ components/terrain/storage.hpp | 21 +++++++++++++++++++++ components/terrain/terraingrid.cpp | 21 +++++++++++++++++++++ components/terrain/terraingrid.hpp | 21 +++++++++++++++++++++ components/terrain/world.cpp | 21 +++++++++++++++++++++ components/terrain/world.hpp | 21 +++++++++++++++++++++ files/materials/terrain.shader | 22 ++++++++++++++++++++++ 18 files changed, 379 insertions(+) diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index 3d0b359104..01032bcdae 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "buffercache.hpp" #include diff --git a/components/terrain/buffercache.hpp b/components/terrain/buffercache.hpp index 51c0a61af2..887f0822ef 100644 --- a/components/terrain/buffercache.hpp +++ b/components/terrain/buffercache.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_BUFFERCACHE_H #define COMPONENTS_TERRAIN_BUFFERCACHE_H diff --git a/components/terrain/chunk.cpp b/components/terrain/chunk.cpp index 9c60ee0173..cce5abd363 100644 --- a/components/terrain/chunk.cpp +++ b/components/terrain/chunk.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "chunk.hpp" #include diff --git a/components/terrain/chunk.hpp b/components/terrain/chunk.hpp index 9b2ed76ac6..22b4f26ef4 100644 --- a/components/terrain/chunk.hpp +++ b/components/terrain/chunk.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_TERRAINBATCH_H #define COMPONENTS_TERRAIN_TERRAINBATCH_H diff --git a/components/terrain/defaultworld.cpp b/components/terrain/defaultworld.cpp index 9436582353..e14c64f3a0 100644 --- a/components/terrain/defaultworld.cpp +++ b/components/terrain/defaultworld.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "defaultworld.hpp" #include diff --git a/components/terrain/defaultworld.hpp b/components/terrain/defaultworld.hpp index 62441c4200..90e8cc2b6a 100644 --- a/components/terrain/defaultworld.hpp +++ b/components/terrain/defaultworld.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_H #define COMPONENTS_TERRAIN_H diff --git a/components/terrain/defs.hpp b/components/terrain/defs.hpp index 6859376532..6d173d1361 100644 --- a/components/terrain/defs.hpp +++ b/components/terrain/defs.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_DEFS_HPP #define COMPONENTS_TERRAIN_DEFS_HPP diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index a40e576ed9..4ff04ab93a 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "material.hpp" #include diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index b9000cb1b9..f35080e7c6 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_MATERIAL_H #define COMPONENTS_TERRAIN_MATERIAL_H diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 755c45c219..5fce5eae91 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "quadtreenode.hpp" #include diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index e8392b8e40..1ecd6fcd56 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_QUADTREENODE_H #define COMPONENTS_TERRAIN_QUADTREENODE_H diff --git a/components/terrain/storage.cpp b/components/terrain/storage.cpp index e69de29bb2..14009127d2 100644 --- a/components/terrain/storage.cpp +++ b/components/terrain/storage.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ diff --git a/components/terrain/storage.hpp b/components/terrain/storage.hpp index aa52ffc4bc..7846e91c6e 100644 --- a/components/terrain/storage.hpp +++ b/components/terrain/storage.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_STORAGE_H #define COMPONENTS_TERRAIN_STORAGE_H diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 6a66ac3d7c..269152e611 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "terraingrid.hpp" #include diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index 7cbf455760..97ef6d14d3 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_TERRAINGRID_H #define COMPONENTS_TERRAIN_TERRAINGRID_H diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 93caeb8df9..5cc2647c67 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "world.hpp" #include diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index beca7903ab..3e63b4c936 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_WORLD_H #define COMPONENTS_TERRAIN_WORLD_H diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index 8384588e4f..a4ca10fcc3 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + #include "core.h" #define IS_FIRST_PASS (@shPropertyString(pass_index) == 0) From 9da0a9f8c4dab03e1917d54ba8d8a4f23f02693f Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 10 Feb 2015 00:55:31 +0100 Subject: [PATCH 147/214] Enable link-time optimization on MSVC --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d22e0b1292..382a8e8e42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -384,6 +384,12 @@ if (CMAKE_COMPILER_IS_GNUCC) if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) SET(CMAKE_CXX_FLAGS "-Wno-unused-but-set-parameter ${CMAKE_CXX_FLAGS}") endif("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) +elseif (MSVC) + # Enable link-time code generation globally for all linking + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") endif (CMAKE_COMPILER_IS_GNUCC) IF(NOT WIN32 AND NOT APPLE) From 1a19253158bb3eba7fb671fb90886a286d247c81 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 10 Feb 2015 15:32:54 +0100 Subject: [PATCH 148/214] Fix MSVC build due to missing M_PI define Apparently the header guard on cmath only adds the defines if _USE_MATH_DEFINES is defined when cmath is included for the first time. So enabling that define and moving cmath up to be the first include, so that nothing else includes it without the define set. --- apps/openmw/mwworld/weather.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 7a36d6ac73..4440ed030e 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -1,7 +1,8 @@ -#include "weather.hpp" - +#define _USE_MATH_DEFINES #include +#include "weather.hpp" + #include #include "../mwbase/environment.hpp" From 3ccf4642b4e7f68c73c43ed451732789cf559683 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Feb 2015 20:25:57 +0100 Subject: [PATCH 149/214] Implement ToggleScripts --- apps/openmw/engine.cpp | 11 ++++++---- apps/openmw/mwbase/world.hpp | 3 +++ apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwscript/docs/vmformat.txt | 3 ++- apps/openmw/mwscript/miscextensions.cpp | 14 +++++++++++++ apps/openmw/mwworld/worldimp.cpp | 28 ++++++++++++++++++++----- apps/openmw/mwworld/worldimp.hpp | 4 ++++ components/compiler/extensions0.cpp | 1 + components/compiler/opcodes.hpp | 1 + 9 files changed, 56 insertions(+), 11 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 611f0a3045..669bae60a7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -109,11 +109,14 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { if (!paused) { - // local scripts - executeLocalScripts(); + if (MWBase::Environment::get().getWorld()->getScriptsEnabled()) + { + // local scripts + executeLocalScripts(); - // global scripts - MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); + // global scripts + MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); + } MWBase::Environment::get().getWorld()->markCellAsUnchanged(); } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 154d96f7d4..8180d0b1ab 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -489,6 +489,9 @@ namespace MWBase virtual bool toggleGodMode() = 0; + virtual bool toggleScripts() = 0; + virtual bool getScriptsEnabled() const = 0; + /** * @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met. * @param actor diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 5cb67c048d..4270c4be16 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -420,7 +420,7 @@ namespace MWGui // Give the script a chance to run once before we do anything else // this is important when setting pcskipequip as a reaction to onpcequip being set (bk_treasuryreport does this) - if (!script.empty()) + if (!script.empty() && MWBase::Environment::get().getWorld()->getScriptsEnabled()) { MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr); MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 41cc6b88a9..93720aef62 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -444,5 +444,6 @@ op 0x20002fd: AddToLevItem op 0x20002fe: RemoveFromLevItem op 0x20002ff: SetFactionReaction op 0x2000300: EnableLevelupMenu +op 0x2000301: ToggleScripts -opcodes 0x2000301-0x3ffffff unused +opcodes 0x2000302-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index cdc9f58cf8..52094947ce 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -915,6 +915,19 @@ namespace MWScript } }; + class OpToggleScripts : public Interpreter::Opcode0 + { + public: + virtual void execute (Interpreter::Runtime& runtime) + { + InterpreterContext& context = static_cast (runtime.getContext()); + + bool enabled = MWBase::Environment::get().getWorld()->toggleScripts(); + + context.report(enabled ? "Scripts -> On" : "Scripts -> Off"); + } + }; + class OpToggleGodMode : public Interpreter::Opcode0 { public: @@ -1220,6 +1233,7 @@ namespace MWScript interpreter.installSegment5 (Compiler::Misc::opcodeShowVars, new OpShowVars); interpreter.installSegment5 (Compiler::Misc::opcodeShowVarsExplicit, new OpShowVars); interpreter.installSegment5 (Compiler::Misc::opcodeToggleGodMode, new OpToggleGodMode); + interpreter.installSegment5 (Compiler::Misc::opcodeToggleScripts, new OpToggleScripts); interpreter.installSegment5 (Compiler::Misc::opcodeDisableLevitation, new OpEnableLevitation); interpreter.installSegment5 (Compiler::Misc::opcodeEnableLevitation, new OpEnableLevitation); interpreter.installSegment5 (Compiler::Misc::opcodeCast, new OpCast); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0694a3da6b..188f3cdad3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -151,7 +151,8 @@ namespace MWWorld mFallback(fallbackMap), mTeleportEnabled(true), mLevitationEnabled(true), mGodMode(false), mContentFiles (contentFiles), mGoToJail(false), mDaysInPrison(0), - mStartCell (startCell), mStartupScript(startupScript) + mStartCell (startCell), mStartupScript(startupScript), + mScriptsEnabled(true) { mPhysics = new PhysicsSystem(renderer); mPhysEngine = mPhysics->getEngine(); @@ -293,6 +294,7 @@ namespace MWWorld mDoorStates.clear(); mGodMode = false; + mScriptsEnabled = true; mSky = true; mTeleportEnabled = true; mLevitationEnabled = true; @@ -2587,6 +2589,17 @@ namespace MWWorld return mGodMode; } + bool World::toggleScripts() + { + mScriptsEnabled = !mScriptsEnabled; + return mScriptsEnabled; + } + + bool World::getScriptsEnabled() const + { + return mScriptsEnabled; + } + void World::loadContentFiles(const Files::Collections& fileCollections, const std::vector& content, ContentLoader& contentLoader) { @@ -3167,12 +3180,17 @@ namespace MWWorld breakInvisibility(actor); - if (!script.empty()) + if (mScriptsEnabled) { - getLocalScripts().setIgnore (object); - MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); + if (!script.empty()) + { + getLocalScripts().setIgnore (object); + MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); + } + if (!interpreterContext.hasActivationBeenHandled()) + interpreterContext.executeActivation(object, actor); } - if (!interpreterContext.hasActivationBeenHandled()) + else interpreterContext.executeActivation(object, actor); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 1d103c6a94..9980f6f906 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -82,6 +82,7 @@ namespace MWWorld boost::shared_ptr mProjectileManager; bool mGodMode; + bool mScriptsEnabled; std::vector mContentFiles; // not implemented @@ -572,6 +573,9 @@ namespace MWWorld virtual bool toggleGodMode(); + virtual bool toggleScripts(); + virtual bool getScriptsEnabled() const; + /** * @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met. * @param actor diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 70338669e3..c56ee2ffb5 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -303,6 +303,7 @@ namespace Compiler extensions.registerInstruction ("sv", "", opcodeShowVars, opcodeShowVarsExplicit); extensions.registerInstruction("tgm", "", opcodeToggleGodMode); extensions.registerInstruction("togglegodmode", "", opcodeToggleGodMode); + extensions.registerInstruction("togglescripts", "", opcodeToggleScripts); extensions.registerInstruction ("disablelevitation", "", opcodeDisableLevitation); extensions.registerInstruction ("enablelevitation", "", opcodeEnableLevitation); extensions.registerFunction ("getpcinjail", 'l', "", opcodeGetPcInJail); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index e5cf2e965e..a4aab8aa1b 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -278,6 +278,7 @@ namespace Compiler const int opcodeShowVars = 0x200021d; const int opcodeShowVarsExplicit = 0x200021e; const int opcodeToggleGodMode = 0x200021f; + const int opcodeToggleScripts = 0x2000301; const int opcodeDisableLevitation = 0x2000220; const int opcodeEnableLevitation = 0x2000221; const int opcodeCast = 0x2000227; From bf1839b3701df0937e096f8aed2f2b1c9c1b8c32 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Feb 2015 22:01:57 +0100 Subject: [PATCH 150/214] Always print the exception to stderr --- apps/openmw/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 475fe63a2d..82fda060ed 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -390,12 +390,12 @@ int main(int argc, char**argv) catch (std::exception &e) { #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE - if (isatty(fileno(stdin))) - std::cerr << "\nERROR: " << e.what() << std::endl; - else + if (!isatty(fileno(stdin))) #endif SDL_ShowSimpleMessageBox(0, "OpenMW: Fatal error", e.what(), NULL); + std::cerr << "\nERROR: " << e.what() << std::endl; + ret = 1; } From 9009889d240185fb50e251d175341288957852a8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 10 Feb 2015 23:16:25 +0100 Subject: [PATCH 151/214] Don't rely on subrecord order when reading (Fixes #2361) --- components/esm/aipackage.cpp | 67 +++++++----- components/esm/aipackage.hpp | 12 ++- components/esm/loadarmo.cpp | 103 ++++++++++++------ components/esm/loadarmo.hpp | 4 + components/esm/loadbook.cpp | 68 ++++++++---- components/esm/loadclot.cpp | 47 +++++++-- components/esm/loadcont.cpp | 11 +- components/esm/loadcont.hpp | 4 + components/esm/loaddoor.cpp | 52 +++++++--- components/esm/loadmgef.cpp | 75 ++++++++++---- components/esm/loadmisc.cpp | 55 +++++++--- components/esm/loadnpc.cpp | 196 +++++++++++++++++++++-------------- components/esm/loadrace.cpp | 32 +++++- components/esm/loadspel.cpp | 27 ++++- components/esm/loadweap.cpp | 62 +++++++---- components/esm/spelllist.cpp | 7 +- components/esm/spelllist.hpp | 5 + 17 files changed, 574 insertions(+), 253 deletions(-) diff --git a/components/esm/aipackage.cpp b/components/esm/aipackage.cpp index 209a1fe264..8ad64b7975 100644 --- a/components/esm/aipackage.cpp +++ b/components/esm/aipackage.cpp @@ -11,36 +11,55 @@ namespace ESM mServices = 0; } + void AIPackageList::add(ESMReader &esm) + { + AIPackage pack; + if (esm.retSubName() == AI_CNDT) { + mList.back().mCellName = esm.getHString(); + } else if (esm.retSubName() == AI_Wander) { + pack.mType = AI_Wander; + esm.getHExact(&pack.mWander, 14); + mList.push_back(pack); + } else if (esm.retSubName() == AI_Travel) { + pack.mType = AI_Travel; + esm.getHExact(&pack.mTravel, 16); + mList.push_back(pack); + } else if (esm.retSubName() == AI_Escort || + esm.retSubName() == AI_Follow) + { + pack.mType = + (esm.retSubName() == AI_Escort) ? AI_Escort : AI_Follow; + esm.getHExact(&pack.mTarget, 48); + mList.push_back(pack); + } else if (esm.retSubName() == AI_Activate) { + pack.mType = AI_Activate; + esm.getHExact(&pack.mActivate, 33); + mList.push_back(pack); + } else { // not AI package related data, so leave + return; + } + + } + void AIPackageList::load(ESMReader &esm) { mList.clear(); while (esm.hasMoreSubs()) { // initialize every iteration - AIPackage pack; - esm.getSubName(); - if (esm.retSubName() == 0x54444e43) { // CNDT - mList.back().mCellName = esm.getHString(); - } else if (esm.retSubName() == AI_Wander) { - pack.mType = AI_Wander; - esm.getHExact(&pack.mWander, 14); - mList.push_back(pack); - } else if (esm.retSubName() == AI_Travel) { - pack.mType = AI_Travel; - esm.getHExact(&pack.mTravel, 16); - mList.push_back(pack); - } else if (esm.retSubName() == AI_Escort || - esm.retSubName() == AI_Follow) + esm.getSubName(); + switch (esm.retSubName().val) { - pack.mType = - (esm.retSubName() == AI_Escort) ? AI_Escort : AI_Follow; - esm.getHExact(&pack.mTarget, 48); - mList.push_back(pack); - } else if (esm.retSubName() == AI_Activate) { - pack.mType = AI_Activate; - esm.getHExact(&pack.mActivate, 33); - mList.push_back(pack); - } else { // not AI package related data, so leave - return; + case AI_Wander: + case AI_Activate: + case AI_Escort: + case AI_Follow: + case AI_Travel: + case AI_CNDT: + + add(esm); + break; + default: + return; } } } diff --git a/components/esm/aipackage.hpp b/components/esm/aipackage.hpp index cbe82f16ed..30bd2ce04c 100644 --- a/components/esm/aipackage.hpp +++ b/components/esm/aipackage.hpp @@ -63,7 +63,8 @@ namespace ESM AI_Travel = 0x545f4941, AI_Follow = 0x465f4941, AI_Escort = 0x455f4941, - AI_Activate = 0x415f4941 + AI_Activate = 0x415f4941, + AI_CNDT = 0x54444e43 }; /// \note Used for storaging packages in a single container @@ -90,11 +91,12 @@ namespace ESM { std::vector mList; - /// \note This breaks consistency of subrecords reading: - /// after calling it subrecord name is already read, so - /// it needs to use retSubName() if needed. But, hey, there - /// is only one field left (XSCL) and only two records uses AI + /// Add a single AIPackage, assumes subrecord name was already read + void add(ESMReader &esm); + + /// TODO: remove this method. The ESM format does not guarantee that all AI packages follow one another void load(ESMReader &esm); + void save(ESMWriter &esm) const; }; } diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index f8c3a4718a..066551d6fe 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -7,52 +7,87 @@ namespace ESM { -void PartReferenceList::load(ESMReader &esm) -{ - mParts.clear(); - while (esm.isNextSub("INDX")) + void PartReferenceList::add(ESMReader &esm) { PartReference pr; esm.getHT(pr.mPart); // The INDX byte pr.mMale = esm.getHNOString("BNAM"); pr.mFemale = esm.getHNOString("CNAM"); mParts.push_back(pr); - } -} -void PartReferenceList::save(ESMWriter &esm) const -{ - for (std::vector::const_iterator it = mParts.begin(); it != mParts.end(); ++it) + } + + void PartReferenceList::load(ESMReader &esm) { - esm.writeHNT("INDX", it->mPart); - esm.writeHNOString("BNAM", it->mMale); - esm.writeHNOString("CNAM", it->mFemale); + mParts.clear(); + while (esm.isNextSub("INDX")) + { + add(esm); + } } -} -unsigned int Armor::sRecordId = REC_ARMO; + void PartReferenceList::save(ESMWriter &esm) const + { + for (std::vector::const_iterator it = mParts.begin(); it != mParts.end(); ++it) + { + esm.writeHNT("INDX", it->mPart); + esm.writeHNOString("BNAM", it->mMale); + esm.writeHNOString("CNAM", it->mFemale); + } + } -void Armor::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); - esm.getHNT(mData, "AODT", 24); - mIcon = esm.getHNOString("ITEX"); - mParts.load(esm); - mEnchant = esm.getHNOString("ENAM"); -} + unsigned int Armor::sRecordId = REC_ARMO; -void Armor::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNT("AODT", mData, 24); - esm.writeHNOCString("ITEX", mIcon); - mParts.save(esm); - esm.writeHNOCString("ENAM", mEnchant); -} + void Armor::load(ESMReader &esm) + { + mParts.mParts.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'A','O','D','T'>::value: + esm.getHT(mData, 24); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEnchant = esm.getHString(); + break; + case ESM::FourCC<'I','N','D','X'>::value: + mParts.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing CTDT subrecord"); + } + + void Armor::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNT("AODT", mData, 24); + esm.writeHNOCString("ITEX", mIcon); + mParts.save(esm); + esm.writeHNOCString("ENAM", mEnchant); + } void Armor::blank() { diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index 6be9dd9717..356dfc1c5e 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -55,6 +55,10 @@ struct PartReferenceList { std::vector mParts; + /// Load one part, assumes the subrecord name was already read + void add(ESMReader &esm); + + /// TODO: remove this method. The ESM format does not guarantee that all Part subrecords follow one another. void load(ESMReader &esm); void save(ESMWriter &esm) const; }; diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp index c8b7e94789..47f52fc31a 100644 --- a/components/esm/loadbook.cpp +++ b/components/esm/loadbook.cpp @@ -8,26 +8,54 @@ namespace ESM { unsigned int Book::sRecordId = REC_BOOK; -void Book::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "BKDT", 20); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); - mText = esm.getHNOString("TEXT"); - mEnchant = esm.getHNOString("ENAM"); -} -void Book::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("BKDT", mData, 20); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); - esm.writeHNOString("TEXT", mText); - esm.writeHNOCString("ENAM", mEnchant); -} + void Book::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'B','K','D','T'>::value: + esm.getHT(mData, 20); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEnchant = esm.getHString(); + break; + case ESM::FourCC<'T','E','X','T'>::value: + mText = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing BKDT subrecord"); + } + void Book::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("BKDT", mData, 20); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + esm.writeHNOString("TEXT", mText); + esm.writeHNOCString("ENAM", mEnchant); + } void Book::blank() { diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 17ecdf3ae5..5f49b5e709 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -10,17 +10,42 @@ namespace ESM void Clothing::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "CTDT", 12); - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); - - mParts.load(esm); - - - mEnchant = esm.getHNOString("ENAM"); + mParts.mParts.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'C','T','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEnchant = esm.getHString(); + break; + case ESM::FourCC<'I','N','D','X'>::value: + mParts.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing CTDT subrecord"); } void Clothing::save(ESMWriter &esm) const diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index 51a385f069..f48f069306 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -7,14 +7,19 @@ namespace ESM { +void InventoryList::add(ESMReader &esm) +{ + ContItem ci; + esm.getHT(ci, 36); + mList.push_back(ci); +} + void InventoryList::load(ESMReader &esm) { mList.clear(); - ContItem ci; while (esm.isNextSub("NPCO")) { - esm.getHT(ci, 36); - mList.push_back(ci); + add(esm); } } diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index 2808b67b56..93db94759d 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -26,6 +26,10 @@ struct InventoryList { std::vector mList; + /// Load one item, assumes subrecord name is already read + void add(ESMReader &esm); + + /// TODO: remove this method, the ESM format doesn't guarantee that all ContItems follow one another void load(ESMReader &esm); void save(ESMWriter &esm) const; }; diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp index c56b063379..f446eed611 100644 --- a/components/esm/loaddoor.cpp +++ b/components/esm/loaddoor.cpp @@ -8,23 +8,43 @@ namespace ESM { unsigned int Door::sRecordId = REC_DOOR; -void Door::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); - mOpenSound = esm.getHNOString("SNAM"); - mCloseSound = esm.getHNOString("ANAM"); -} + void Door::load(ESMReader &esm) + { + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'S','N','A','M'>::value: + mOpenSound = esm.getHString(); + break; + case ESM::FourCC<'A','N','A','M'>::value: + mCloseSound = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + } -void Door::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("SNAM", mOpenSound); - esm.writeHNOCString("ANAM", mCloseSound); -} + void Door::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("SNAM", mOpenSound); + esm.writeHNOCString("ANAM", mCloseSound); + } void Door::blank() { diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index cbdca3e317..3ec07a2a91 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -191,33 +191,64 @@ namespace ESM void MagicEffect::load(ESMReader &esm) { - esm.getHNT(mIndex, "INDX"); + esm.getHNT(mIndex, "INDX"); mId = indexToId (mIndex); - esm.getHNT(mData, "MEDT", 36); - if (esm.getFormat() == 0) - { - // don't allow mods to change fixed flags in the legacy format - mData.mFlags &= (AllowSpellmaking | AllowEnchanting | NegativeLight); - if (mIndex>=0 && mIndex=0 && mIndex::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'P','T','E','X'>::value: + mParticle = esm.getHString(); + break; + case ESM::FourCC<'B','S','N','D'>::value: + mBoltSound = esm.getHString(); + break; + case ESM::FourCC<'C','S','N','D'>::value: + mCastSound = esm.getHString(); + break; + case ESM::FourCC<'H','S','N','D'>::value: + mHitSound = esm.getHString(); + break; + case ESM::FourCC<'A','S','N','D'>::value: + mAreaSound = esm.getHString(); + break; + case ESM::FourCC<'C','V','F','X'>::value: + mCasting = esm.getHString(); + break; + case ESM::FourCC<'B','V','F','X'>::value: + mBolt = esm.getHString(); + break; + case ESM::FourCC<'H','V','F','X'>::value: + mHit = esm.getHString(); + break; + case ESM::FourCC<'A','V','F','X'>::value: + mArea = esm.getHString(); + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord " + esm.retSubName().toString()); + } + } } void MagicEffect::save(ESMWriter &esm) const { diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp index 2ca09e8aec..81c094f2bc 100644 --- a/components/esm/loadmisc.cpp +++ b/components/esm/loadmisc.cpp @@ -8,22 +8,45 @@ namespace ESM { unsigned int Miscellaneous::sRecordId = REC_MISC; -void Miscellaneous::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "MCDT", 12); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); -} -void Miscellaneous::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("MCDT", mData, 12); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + void Miscellaneous::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'M','C','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + } + } + if (!hasData) + esm.fail("Missing MCDT subrecord"); + } + + void Miscellaneous::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("MCDT", mData, 12); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Miscellaneous::blank() { diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 6ca070cf37..3d617241b6 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -8,93 +8,137 @@ namespace ESM { unsigned int NPC::sRecordId = REC_NPC_; -void NPC::load(ESMReader &esm) -{ - mPersistent = esm.getRecordFlags() & 0x0400; - - mModel = esm.getHNOString("MODL"); - mName = esm.getHNOString("FNAM"); - - mRace = esm.getHNString("RNAM"); - mClass = esm.getHNString("CNAM"); - mFaction = esm.getHNString("ANAM"); - mHead = esm.getHNString("BNAM"); - mHair = esm.getHNString("KNAM"); - - mScript = esm.getHNOString("SCRI"); - - esm.getSubNameIs("NPDT"); - esm.getSubHeader(); - if (esm.getSubSize() == 52) + void NPC::load(ESMReader &esm) { - mNpdtType = NPC_DEFAULT; - esm.getExact(&mNpdt52, 52); - } - else if (esm.getSubSize() == 12) - { - mNpdtType = NPC_WITH_AUTOCALCULATED_STATS; - esm.getExact(&mNpdt12, 12); - } - else - esm.fail("NPC_NPDT must be 12 or 52 bytes long"); + mPersistent = esm.getRecordFlags() & 0x0400; - esm.getHNT(mFlags, "FLAG"); + mSpells.mList.clear(); + mInventory.mList.clear(); + mTransport.clear(); + mAiPackage.mList.clear(); - mInventory.load(esm); - mSpells.load(esm); - - if (esm.isNextSub("AIDT")) - { - esm.getHExact(&mAiData, sizeof(mAiData)); - mHasAI= true; - } - else + bool hasNpdt = false; + bool hasFlags = false; mHasAI = false; - - mTransport.clear(); - while (esm.isNextSub("DODT") || esm.isNextSub("DNAM")) { - if (esm.retSubName() == 0x54444f44) { // DODT struct - Dest dodt; - esm.getHExact(&dodt.mPos, 24); - mTransport.push_back(dodt); - } else if (esm.retSubName() == 0x4d414e44) { // DNAM struct - mTransport.back().mCellName = esm.getHString(); + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','N','A','M'>::value: + mRace = esm.getHString(); + break; + case ESM::FourCC<'C','N','A','M'>::value: + mClass = esm.getHString(); + break; + case ESM::FourCC<'A','N','A','M'>::value: + mFaction = esm.getHString(); + break; + case ESM::FourCC<'B','N','A','M'>::value: + mHead = esm.getHString(); + break; + case ESM::FourCC<'K','N','A','M'>::value: + mHair = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'N','P','D','T'>::value: + hasNpdt = true; + esm.getSubHeader(); + if (esm.getSubSize() == 52) + { + mNpdtType = NPC_DEFAULT; + esm.getExact(&mNpdt52, 52); + } + else if (esm.getSubSize() == 12) + { + mNpdtType = NPC_WITH_AUTOCALCULATED_STATS; + esm.getExact(&mNpdt12, 12); + } + else + esm.fail("NPC_NPDT must be 12 or 52 bytes long"); + break; + case ESM::FourCC<'F','L','A','G'>::value: + hasFlags = true; + esm.getHT(mFlags); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mSpells.add(esm); + break; + case ESM::FourCC<'N','P','C','O'>::value: + mInventory.add(esm); + break; + case ESM::FourCC<'A','I','D','T'>::value: + esm.getHExact(&mAiData, sizeof(mAiData)); + mHasAI= true; + break; + case ESM::FourCC<'D','O','D','T'>::value: + { + Dest dodt; + esm.getHExact(&dodt.mPos, 24); + mTransport.push_back(dodt); + break; + } + case ESM::FourCC<'D','N','A','M'>::value: + mTransport.back().mCellName = esm.getHString(); + break; + case AI_Wander: + case AI_Activate: + case AI_Escort: + case AI_Follow: + case AI_Travel: + case AI_CNDT: + mAiPackage.add(esm); + break; + default: + esm.fail("Unknown subrecord " + esm.retSubName().toString()); + } } + if (!hasNpdt) + esm.fail("Missing NPDT subrecord"); + if (!hasFlags) + esm.fail("Missing FLAG subrecord"); } - mAiPackage.load(esm); -} -void NPC::save(ESMWriter &esm) const -{ - esm.writeHNOCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNCString("RNAM", mRace); - esm.writeHNCString("CNAM", mClass); - esm.writeHNCString("ANAM", mFaction); - esm.writeHNCString("BNAM", mHead); - esm.writeHNCString("KNAM", mHair); - esm.writeHNOCString("SCRI", mScript); + void NPC::save(ESMWriter &esm) const + { + esm.writeHNOCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNCString("RNAM", mRace); + esm.writeHNCString("CNAM", mClass); + esm.writeHNCString("ANAM", mFaction); + esm.writeHNCString("BNAM", mHead); + esm.writeHNCString("KNAM", mHair); + esm.writeHNOCString("SCRI", mScript); - if (mNpdtType == NPC_DEFAULT) - esm.writeHNT("NPDT", mNpdt52, 52); - else if (mNpdtType == NPC_WITH_AUTOCALCULATED_STATS) - esm.writeHNT("NPDT", mNpdt12, 12); + if (mNpdtType == NPC_DEFAULT) + esm.writeHNT("NPDT", mNpdt52, 52); + else if (mNpdtType == NPC_WITH_AUTOCALCULATED_STATS) + esm.writeHNT("NPDT", mNpdt12, 12); - esm.writeHNT("FLAG", mFlags); + esm.writeHNT("FLAG", mFlags); - mInventory.save(esm); - mSpells.save(esm); - if (mHasAI) { - esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); + mInventory.save(esm); + mSpells.save(esm); + if (mHasAI) { + esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); + } + + typedef std::vector::const_iterator DestIter; + for (DestIter it = mTransport.begin(); it != mTransport.end(); ++it) { + esm.writeHNT("DODT", it->mPos, sizeof(it->mPos)); + esm.writeHNOCString("DNAM", it->mCellName); + } + mAiPackage.save(esm); } - typedef std::vector::const_iterator DestIter; - for (DestIter it = mTransport.begin(); it != mTransport.end(); ++it) { - esm.writeHNT("DODT", it->mPos, sizeof(it->mPos)); - esm.writeHNOCString("DNAM", it->mCellName); - } - mAiPackage.save(esm); -} - bool NPC::isMale() const { return (mFlags & Female) == 0; } diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 17f2e02679..211fd5ffb3 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -20,10 +20,34 @@ namespace ESM void Race::load(ESMReader &esm) { - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "RADT", 140); - mPowers.load(esm); - mDescription = esm.getHNOString("DESC"); + mPowers.mList.clear(); + + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','A','D','T'>::value: + esm.getHT(mData, 140); + hasData = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mPowers.add(esm); + break; + default: + esm.fail("Unknown subrecord " + esm.retSubName().toString()); + } + } + if (!hasData) + esm.fail("Missing RADT subrecord"); } void Race::save(ESMWriter &esm) const { diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index 2c98d796d3..716f47e715 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -10,9 +10,30 @@ namespace ESM void Spell::load(ESMReader &esm) { - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "SPDT", 12); - mEffects.load(esm); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t val = esm.retSubName().val; + + switch (val) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','P','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + ENAMstruct s; + esm.getHT(s, 24); + mEffects.mList.push_back(s); + break; + } + } + if (!hasData) + esm.fail("Missing SPDT subrecord"); } void Spell::save(ESMWriter &esm) const diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp index 1d0b149df1..981a5815a2 100644 --- a/components/esm/loadweap.cpp +++ b/components/esm/loadweap.cpp @@ -8,24 +8,50 @@ namespace ESM { unsigned int Weapon::sRecordId = REC_WEAP; -void Weapon::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "WPDT", 32); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); - mEnchant = esm.getHNOString("ENAM"); -} -void Weapon::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("WPDT", mData, 32); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); - esm.writeHNOCString("ENAM", mEnchant); -} + void Weapon::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'W','P','D','T'>::value: + esm.getHT(mData, 32); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEnchant = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing WPDT subrecord"); + } + void Weapon::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("WPDT", mData, 32); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + esm.writeHNOCString("ENAM", mEnchant); + } void Weapon::blank() { diff --git a/components/esm/spelllist.cpp b/components/esm/spelllist.cpp index 8ec386db40..98bd53ae6a 100644 --- a/components/esm/spelllist.cpp +++ b/components/esm/spelllist.cpp @@ -9,10 +9,15 @@ void SpellList::load(ESMReader &esm) { mList.clear(); while (esm.isNextSub("NPCS")) { - mList.push_back(esm.getHString()); + add(esm); } } +void SpellList::add(ESMReader &esm) +{ + mList.push_back(esm.getHString()); +} + void SpellList::save(ESMWriter &esm) const { for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) { diff --git a/components/esm/spelllist.hpp b/components/esm/spelllist.hpp index bcd6ba7984..9493199a80 100644 --- a/components/esm/spelllist.hpp +++ b/components/esm/spelllist.hpp @@ -19,6 +19,11 @@ namespace ESM /// Is this spell ID in mList? bool exists(const std::string& spell) const; + /// Load one spell, assumes the subrecord name was already read + void add(ESMReader &esm); + + /// Load all spells + /// TODO: remove this method, the ESM format doesn't guarantee that all spell subrecords follow one another void load(ESMReader &esm); void save(ESMWriter &esm) const; }; From 6b0ca73352efc386507ae7115ad3ed3ed6f0cf73 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Wed, 11 Feb 2015 10:04:00 +0200 Subject: [PATCH 152/214] CI: use Qt from our homebrew tap --- CI/before_install.osx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_install.osx.sh b/CI/before_install.osx.sh index 165763efa6..8bfe2b70f3 100755 --- a/CI/before_install.osx.sh +++ b/CI/before_install.osx.sh @@ -6,4 +6,4 @@ export CC=clang brew tap openmw/openmw brew update brew unlink boost -brew install openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg qt unshield +brew install openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg openmw/openmw/qt unshield From ca53ca89261b46a907fc7d08391ee1e2e4b8cd6c Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Wed, 11 Feb 2015 10:08:29 +0200 Subject: [PATCH 153/214] CI: perform `make package` on OS X --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index f9c917bbbf..042d4b8f1a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,7 @@ before_script: script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -j4; 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 notifications: From dfaab1188f86c62d23f360ffebaa1f4a0c821900 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Feb 2015 12:10:46 +0100 Subject: [PATCH 154/214] Fix for broken levelled creature spawning (Fixes #2365) --- apps/openmw/mwclass/creaturelevlist.cpp | 2 +- apps/openmw/mwclass/creaturelevlist.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index b1e27c3450..dbc4b6af7b 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -52,7 +52,7 @@ namespace MWClass registerClass (typeid (ESM::CreatureLevList).name(), instance); } - void CreatureLevList::insertObjectRendering(const MWWorld::Ptr &ptr, MWRender::RenderingInterface &renderingInterface) const + void CreatureLevList::insertObjectRendering(const MWWorld::Ptr &ptr, const std::string& model, MWRender::RenderingInterface &renderingInterface) const { ensureCustomData(ptr); diff --git a/apps/openmw/mwclass/creaturelevlist.hpp b/apps/openmw/mwclass/creaturelevlist.hpp index 7016524eb9..177aa72359 100644 --- a/apps/openmw/mwclass/creaturelevlist.hpp +++ b/apps/openmw/mwclass/creaturelevlist.hpp @@ -20,7 +20,7 @@ namespace MWClass static void registerSelf(); - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) From cfe81bafe82a5a396ad7d82c16e3dc229bae2999 Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 11 Feb 2015 21:46:00 -0600 Subject: [PATCH 155/214] Remove setting CMAKE_BUILD_TYPE to Debug Setting was causing single-target configurations (ninja, make) to incorrectly link vs debug runtimes on Windows. --- apps/opencs/CMakeLists.txt | 2 -- components/CMakeLists.txt | 1 - 2 files changed, 3 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0b83feb450..b65aee4cfa 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -4,8 +4,6 @@ set (OPENCS_SRC main.cpp opencs_units (. editor) -set (CMAKE_BUILD_TYPE DEBUG) - opencs_units (model/doc document operation saving documentmanager loader runner ) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6f8352ddbb..a49e54dd3e 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -1,5 +1,4 @@ project (Components) -set (CMAKE_BUILD_TYPE DEBUG) # Version file set (VERSION_HPP_IN ${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp.cmake) From 49d912e5b6b1d728bf10c92d0b803dfda7596b89 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Feb 2015 04:56:05 +0100 Subject: [PATCH 156/214] Don't rely on subrecord order part 2 Nice side effects: - Subrecord name comparison now uses magic number instead of string (faster) - Improves the error message for unknown subrecords: will print the record in question instead of failing to read the next record with a strange error --- components/esm/aipackage.cpp | 23 ------ components/esm/aipackage.hpp | 3 - components/esm/effectlist.cpp | 11 ++- components/esm/effectlist.hpp | 6 +- components/esm/loadacti.cpp | 40 +++++++---- components/esm/loadalch.cpp | 63 +++++++++++----- components/esm/loadappa.cpp | 40 +++++++---- components/esm/loadbody.cpp | 27 ++++++- components/esm/loadbsgn.cpp | 28 ++++++-- components/esm/loadclas.cpp | 70 +++++++++++------- components/esm/loadcont.cpp | 105 ++++++++++++++++----------- components/esm/loadcont.hpp | 3 +- components/esm/loadcrea.cpp | 127 +++++++++++++++++++++------------ components/esm/loadench.cpp | 24 ++++++- components/esm/loadfact.cpp | 53 +++++++++----- components/esm/loadingr.cpp | 88 +++++++++++++++-------- components/esm/loadlevlist.cpp | 77 ++++++++++---------- components/esm/loadligh.cpp | 63 +++++++++++----- components/esm/loadlock.cpp | 58 ++++++++++----- components/esm/loadmgef.cpp | 2 +- components/esm/loadmgef.hpp | 4 +- components/esm/loadnpc.cpp | 2 +- components/esm/loadprob.cpp | 58 ++++++++++----- components/esm/loadrace.cpp | 2 +- components/esm/loadrepa.cpp | 36 ++++++++-- components/esm/loadscpt.cpp | 112 +++++++++++++++-------------- components/esm/loadscpt.hpp | 3 + components/esm/loadskil.cpp | 54 ++++++++++---- components/esm/loadsndg.cpp | 45 ++++++++---- components/esm/loadsoun.cpp | 45 +++++++----- components/esm/loadspel.cpp | 62 ++++++++-------- components/esm/loadsscr.cpp | 42 ++++++++--- components/esm/loadstat.cpp | 19 ++--- components/esm/loadtes3.hpp | 4 +- components/esm/spelllist.cpp | 8 --- components/esm/spelllist.hpp | 4 +- 36 files changed, 896 insertions(+), 515 deletions(-) diff --git a/components/esm/aipackage.cpp b/components/esm/aipackage.cpp index 8ad64b7975..efcd6651ea 100644 --- a/components/esm/aipackage.cpp +++ b/components/esm/aipackage.cpp @@ -41,29 +41,6 @@ namespace ESM } - void AIPackageList::load(ESMReader &esm) - { - mList.clear(); - while (esm.hasMoreSubs()) { - // initialize every iteration - esm.getSubName(); - switch (esm.retSubName().val) - { - case AI_Wander: - case AI_Activate: - case AI_Escort: - case AI_Follow: - case AI_Travel: - case AI_CNDT: - - add(esm); - break; - default: - return; - } - } - } - void AIPackageList::save(ESMWriter &esm) const { typedef std::vector::const_iterator PackageIter; diff --git a/components/esm/aipackage.hpp b/components/esm/aipackage.hpp index 30bd2ce04c..5e08806c8b 100644 --- a/components/esm/aipackage.hpp +++ b/components/esm/aipackage.hpp @@ -94,9 +94,6 @@ namespace ESM /// Add a single AIPackage, assumes subrecord name was already read void add(ESMReader &esm); - /// TODO: remove this method. The ESM format does not guarantee that all AI packages follow one another - void load(ESMReader &esm); - void save(ESMWriter &esm) const; }; } diff --git a/components/esm/effectlist.cpp b/components/esm/effectlist.cpp index fc9acccf20..f6d5a6e071 100644 --- a/components/esm/effectlist.cpp +++ b/components/esm/effectlist.cpp @@ -8,13 +8,18 @@ namespace ESM { void EffectList::load(ESMReader &esm) { mList.clear(); - ENAMstruct s; while (esm.isNextSub("ENAM")) { - esm.getHT(s, 24); - mList.push_back(s); + add(esm); } } +void EffectList::add(ESMReader &esm) +{ + ENAMstruct s; + esm.getHT(s, 24); + mList.push_back(s); +} + void EffectList::save(ESMWriter &esm) const { for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) { diff --git a/components/esm/effectlist.hpp b/components/esm/effectlist.hpp index 04adcc5cd8..d581f83371 100644 --- a/components/esm/effectlist.hpp +++ b/components/esm/effectlist.hpp @@ -29,11 +29,15 @@ namespace ESM }; #pragma pack(pop) + /// EffectList, ENAM subrecord struct EffectList { - std::vector mList; + /// Load one effect, assumes subrecord name was already read + void add(ESMReader &esm); + + /// Load all effects void load(ESMReader &esm); void save(ESMWriter &esm) const; }; diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index 8efea3302a..b5adce5509 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -8,18 +8,34 @@ namespace ESM { unsigned int Activator::sRecordId = REC_ACTI; -void Activator::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); -} -void Activator::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); -} + void Activator::load(ESMReader &esm) + { + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + } + void Activator::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + } void Activator::blank() { diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index aac88482ff..18db512c0c 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -8,24 +8,51 @@ namespace ESM { unsigned int Potion::sRecordId = REC_ALCH; -void Potion::load(ESMReader &esm) -{ - mModel = esm.getHNOString("MODL"); - mIcon = esm.getHNOString("TEXT"); // not ITEX here for some reason - mScript = esm.getHNOString("SCRI"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "ALDT", 12); - mEffects.load(esm); -} -void Potion::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("TEXT", mIcon); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("ALDT", mData, 12); - mEffects.save(esm); -} + void Potion::load(ESMReader &esm) + { + mEffects.mList.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'T','E','X','T'>::value: // not ITEX here for some reason + mIcon = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'A','L','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEffects.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing ALDT"); + } + void Potion::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("TEXT", mIcon); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("ALDT", mData, 12); + mEffects.save(esm); + } void Potion::blank() { diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index 29ea78acc0..f2c82aacfb 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -10,25 +10,35 @@ namespace ESM void Apparatus::load(ESMReader &esm) { - // we will not treat duplicated subrecords as errors here + bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - NAME subName = esm.retSubName(); - - if (subName == "MODL") - mModel = esm.getHString(); - else if (subName == "FNAM") - mName = esm.getHString(); - else if (subName == "AADT") - esm.getHT(mData); - else if (subName == "SCRI") - mScript = esm.getHString(); - else if (subName == "ITEX") - mIcon = esm.getHString(); - else - esm.fail("wrong subrecord type " + subName.toString() + " for APPA record"); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'A','A','D','T'>::value: + esm.getHT(mData); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } } + if (!hasData) + esm.fail("Missing AADT"); } void Apparatus::save(ESMWriter &esm) const diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index 9a1164d041..ed24ded57b 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -11,9 +11,30 @@ namespace ESM void BodyPart::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mRace = esm.getHNOString("FNAM"); - esm.getHNT(mData, "BYDT", 4); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mRace = esm.getHString(); + break; + case ESM::FourCC<'B','Y','D','T'>::value: + esm.getHT(mData, 4); + hasData = true; + break; + default: + esm.fail("Unknown subrecord"); + } + } + + if (!hasData) + esm.fail("Missing BYDT subrecord"); } void BodyPart::save(ESMWriter &esm) const { diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index db1a72a368..e0cd83ea07 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -10,11 +10,29 @@ namespace ESM void BirthSign::load(ESMReader &esm) { - mName = esm.getHNOString("FNAM"); - mTexture = esm.getHNOString("TNAM"); - mDescription = esm.getHNOString("DESC"); - - mPowers.load(esm); + mPowers.mList.clear(); + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'T','N','A','M'>::value: + mTexture = esm.getHString(); + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mPowers.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } } void BirthSign::save(ESMWriter &esm) const diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index ec339bd15e..66acaea721 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -10,17 +10,17 @@ namespace ESM { unsigned int Class::sRecordId = REC_CLAS; -const Class::Specialization Class::sSpecializationIds[3] = { - Class::Combat, - Class::Magic, - Class::Stealth -}; + const Class::Specialization Class::sSpecializationIds[3] = { + Class::Combat, + Class::Magic, + Class::Stealth + }; -const char *Class::sGmstSpecializationIds[3] = { - "sSpecializationCombat", - "sSpecializationMagic", - "sSpecializationStealth" -}; + const char *Class::sGmstSpecializationIds[3] = { + "sSpecializationCombat", + "sSpecializationMagic", + "sSpecializationStealth" + }; int& Class::CLDTstruct::getSkill (int index, bool major) @@ -39,22 +39,40 @@ const char *Class::sGmstSpecializationIds[3] = { return mSkills[index][major ? 1 : 0]; } -void Class::load(ESMReader &esm) -{ - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "CLDT", 60); - - if (mData.mIsPlayable > 1) - esm.fail("Unknown bool value"); - - mDescription = esm.getHNOString("DESC"); -} -void Class::save(ESMWriter &esm) const -{ - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("CLDT", mData, 60); - esm.writeHNOString("DESC", mDescription); -} + void Class::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'C','L','D','T'>::value: + esm.getHT(mData, 60); + if (mData.mIsPlayable > 1) + esm.fail("Unknown bool value"); + hasData = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing CLDT subrecord"); + } + void Class::save(ESMWriter &esm) const + { + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("CLDT", mData, 60); + esm.writeHNOString("DESC", mDescription); + } void Class::blank() { diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index f48f069306..999c3f92a1 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -7,60 +7,79 @@ namespace ESM { -void InventoryList::add(ESMReader &esm) -{ - ContItem ci; - esm.getHT(ci, 36); - mList.push_back(ci); -} - -void InventoryList::load(ESMReader &esm) -{ - mList.clear(); - while (esm.isNextSub("NPCO")) + void InventoryList::add(ESMReader &esm) { - add(esm); + ContItem ci; + esm.getHT(ci, 36); + mList.push_back(ci); } -} -void InventoryList::save(ESMWriter &esm) const -{ - for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + void InventoryList::save(ESMWriter &esm) const { - esm.writeHNT("NPCO", *it, 36); + for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + { + esm.writeHNT("NPCO", *it, 36); + } } -} unsigned int Container::sRecordId = REC_CONT; -void Container::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mWeight, "CNDT", 4); - esm.getHNT(mFlags, "FLAG", 4); + void Container::load(ESMReader &esm) + { + mInventory.mList.clear(); + bool hasWeight = false; + bool hasFlags = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'C','N','D','T'>::value: + esm.getHT(mWeight, 4); + hasWeight = true; + break; + case ESM::FourCC<'F','L','A','G'>::value: + esm.getHT(mFlags, 4); + if (mFlags & 0xf4) + esm.fail("Unknown flags"); + if (!(mFlags & 0x8)) + esm.fail("Flag 8 not set"); + hasFlags = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','O'>::value: + mInventory.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasWeight) + esm.fail("Missing CNDT subrecord"); + if (!hasFlags) + esm.fail("Missing FLAG subrecord"); + } - if (mFlags & 0xf4) - esm.fail("Unknown flags"); - if (!(mFlags & 0x8)) - esm.fail("Flag 8 not set"); + void Container::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("CNDT", mWeight, 4); + esm.writeHNT("FLAG", mFlags, 4); - mScript = esm.getHNOString("SCRI"); + esm.writeHNOCString("SCRI", mScript); - mInventory.load(esm); -} - -void Container::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("CNDT", mWeight, 4); - esm.writeHNT("FLAG", mFlags, 4); - - esm.writeHNOCString("SCRI", mScript); - - mInventory.save(esm); -} + mInventory.save(esm); + } void Container::blank() { diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index 93db94759d..76c522d748 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -22,6 +22,7 @@ struct ContItem NAME32 mItem; }; +/// InventoryList, NPCO subrecord struct InventoryList { std::vector mList; @@ -29,8 +30,6 @@ struct InventoryList /// Load one item, assumes subrecord name is already read void add(ESMReader &esm); - /// TODO: remove this method, the ESM format doesn't guarantee that all ContItems follow one another - void load(ESMReader &esm); void save(ESMWriter &esm) const; }; diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 650de08011..2e9f924b7c 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -8,55 +8,94 @@ namespace ESM { unsigned int Creature::sRecordId = REC_CREA; -void Creature::load(ESMReader &esm) -{ - mPersistent = esm.getRecordFlags() & 0x0400; - - mModel = esm.getHNString("MODL"); - mOriginal = esm.getHNOString("CNAM"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); - - esm.getHNT(mData, "NPDT", 96); - - esm.getHNT(mFlags, "FLAG"); - mScale = 1.0; - esm.getHNOT(mScale, "XSCL"); - - mInventory.load(esm); - mSpells.load(esm); - - if (esm.isNextSub("AIDT")) + void Creature::load(ESMReader &esm) { - esm.getHExact(&mAiData, sizeof(mAiData)); - mHasAI = true; - } - else + mPersistent = esm.getRecordFlags() & 0x0400; + + mAiPackage.mList.clear(); + mInventory.mList.clear(); + mSpells.mList.clear(); + + mScale = 1.f; mHasAI = false; - - mAiPackage.load(esm); - esm.skipRecord(); -} - -void Creature::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("CNAM", mOriginal); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNT("NPDT", mData, 96); - esm.writeHNT("FLAG", mFlags); - if (mScale != 1.0) { - esm.writeHNT("XSCL", mScale); + bool hasNpdt = false; + bool hasFlags = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'C','N','A','M'>::value: + mOriginal = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'N','P','D','T'>::value: + esm.getHT(mData, 96); + hasNpdt = true; + break; + case ESM::FourCC<'F','L','A','G'>::value: + esm.getHT(mFlags); + hasFlags = true; + break; + case ESM::FourCC<'X','S','C','L'>::value: + esm.getHT(mScale); + break; + case ESM::FourCC<'N','P','C','O'>::value: + mInventory.add(esm); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mSpells.add(esm); + break; + case ESM::FourCC<'A','I','D','T'>::value: + esm.getHExact(&mAiData, sizeof(mAiData)); + mHasAI = true; + break; + case AI_Wander: + case AI_Activate: + case AI_Escort: + case AI_Follow: + case AI_Travel: + case AI_CNDT: + mAiPackage.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasNpdt) + esm.fail("Missing NPDT subrecord"); + if (!hasFlags) + esm.fail("Missing FLAG subrecord"); } - mInventory.save(esm); - mSpells.save(esm); - if (mHasAI) { - esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); + void Creature::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("CNAM", mOriginal); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNT("NPDT", mData, 96); + esm.writeHNT("FLAG", mFlags); + if (mScale != 1.0) { + esm.writeHNT("XSCL", mScale); + } + + mInventory.save(esm); + mSpells.save(esm); + if (mHasAI) { + esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); + } + mAiPackage.save(esm); } - mAiPackage.save(esm); -} void Creature::blank() { diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp index 2438038337..54690d9a0b 100644 --- a/components/esm/loadench.cpp +++ b/components/esm/loadench.cpp @@ -10,8 +10,28 @@ namespace ESM void Enchantment::load(ESMReader &esm) { - esm.getHNT(mData, "ENDT", 16); - mEffects.load(esm); + mEffects.mList.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'E','N','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEffects.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + break; + } + } + if (!hasData) + esm.fail("Missing ENDT subrecord"); } void Enchantment::save(ESMWriter &esm) const diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index db7e5b7b44..006ca0ce00 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -28,27 +28,46 @@ namespace ESM void Faction::load(ESMReader &esm) { - mName = esm.getHNOString("FNAM"); + mReactions.clear(); + for (int i=0;i<10;++i) + mRanks[i].clear(); - // Read rank names. These are optional. - int i = 0; - while (esm.isNextSub("RNAM") && i < 10) - mRanks[i++] = esm.getHString(); - - // Main data struct - esm.getHNT(mData, "FADT", 240); - - if (mData.mIsHidden > 1) - esm.fail("Unknown flag!"); - - // Read faction response values + int rankCounter=0; + bool hasData = false; while (esm.hasMoreSubs()) { - std::string faction = esm.getHNString("ANAM"); - int reaction; - esm.getHNT(reaction, "INTV"); - mReactions[faction] = reaction; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','N','A','M'>::value: + if (rankCounter >= 10) + esm.fail("Rank out of range"); + mRanks[rankCounter++] = esm.getHString(); + break; + case ESM::FourCC<'F','A','D','T'>::value: + esm.getHT(mData, 240); + if (mData.mIsHidden > 1) + esm.fail("Unknown flag!"); + hasData = true; + break; + case ESM::FourCC<'A','N','A','M'>::value: + { + std::string faction = esm.getHString(); + int reaction; + esm.getHNT(reaction, "INTV"); + mReactions[faction] = reaction; + break; + } + default: + esm.fail("Unknown subrecord"); + } } + if (!hasData) + esm.fail("Missing FADT subrecord"); } void Faction::save(ESMWriter &esm) const { diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index 5c98cb8b97..7e0cc3168d 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -8,45 +8,71 @@ namespace ESM { unsigned int Ingredient::sRecordId = REC_INGR; -void Ingredient::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "IRDT", 56); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); - // horrible hack to fix broken data in records - for (int i=0; i<4; ++i) + void Ingredient::load(ESMReader &esm) { - if (mData.mEffectID[i] != 85 && - mData.mEffectID[i] != 22 && - mData.mEffectID[i] != 17 && - mData.mEffectID[i] != 79 && - mData.mEffectID[i] != 74) + bool hasData = false; + while (esm.hasMoreSubs()) { - mData.mAttributes[i] = -1; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'I','R','D','T'>::value: + esm.getHT(mData, 56); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } } - // is this relevant in cycle from 0 to 4? - if (mData.mEffectID[i] != 89 && - mData.mEffectID[i] != 26 && - mData.mEffectID[i] != 21 && - mData.mEffectID[i] != 83 && - mData.mEffectID[i] != 78) + if (!hasData) + esm.fail("Missing IRDT subrecord"); + + // horrible hack to fix broken data in records + for (int i=0; i<4; ++i) { - mData.mSkills[i] = -1; + if (mData.mEffectID[i] != 85 && + mData.mEffectID[i] != 22 && + mData.mEffectID[i] != 17 && + mData.mEffectID[i] != 79 && + mData.mEffectID[i] != 74) + { + mData.mAttributes[i] = -1; + } + + // is this relevant in cycle from 0 to 4? + if (mData.mEffectID[i] != 89 && + mData.mEffectID[i] != 26 && + mData.mEffectID[i] != 21 && + mData.mEffectID[i] != 83 && + mData.mEffectID[i] != 78) + { + mData.mSkills[i] = -1; + } } } -} -void Ingredient::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("IRDT", mData, 56); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + void Ingredient::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("IRDT", mData, 56); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Ingredient::blank() { diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 2cbfac0b40..6080d1e1ab 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -7,49 +7,50 @@ namespace ESM { -void LevelledListBase::load(ESMReader &esm) -{ - esm.getHNT(mFlags, "DATA"); - esm.getHNT(mChanceNone, "NNAM"); - - if (esm.isNextSub("INDX")) + void LevelledListBase::load(ESMReader &esm) { - int len; - esm.getHT(len); - mList.resize(len); - } - else - { - esm.skipRecord(); - return; - } + esm.getHNT(mFlags, "DATA"); + esm.getHNT(mChanceNone, "NNAM"); - // If this levelled list was already loaded by a previous content file, - // we overwrite the list. Merging lists should probably be left to external tools, - // with the limited amount of information there is in the records, all merging methods - // will be flawed in some way. For a proper fix the ESM format would have to be changed - // to actually track list changes instead of including the whole list for every file - // that does something with that list. + if (esm.isNextSub("INDX")) + { + int len; + esm.getHT(len); + mList.resize(len); + } + else + { + // Original engine ignores rest of the record, even if there are items following + esm.skipRecord(); + return; + } - for (size_t i = 0; i < mList.size(); i++) - { - LevelItem &li = mList[i]; - li.mId = esm.getHNString(mRecName); - esm.getHNT(li.mLevel, "INTV"); - } -} -void LevelledListBase::save(ESMWriter &esm) const -{ - esm.writeHNT("DATA", mFlags); - esm.writeHNT("NNAM", mChanceNone); - esm.writeHNT("INDX", mList.size()); + // If this levelled list was already loaded by a previous content file, + // we overwrite the list. Merging lists should probably be left to external tools, + // with the limited amount of information there is in the records, all merging methods + // will be flawed in some way. For a proper fix the ESM format would have to be changed + // to actually track list changes instead of including the whole list for every file + // that does something with that list. - for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) - { - esm.writeHNCString(mRecName, it->mId); - esm.writeHNT("INTV", it->mLevel); + for (size_t i = 0; i < mList.size(); i++) + { + LevelItem &li = mList[i]; + li.mId = esm.getHNString(mRecName); + esm.getHNT(li.mLevel, "INTV"); + } + } + void LevelledListBase::save(ESMWriter &esm) const + { + esm.writeHNT("DATA", mFlags); + esm.writeHNT("NNAM", mChanceNone); + esm.writeHNT("INDX", mList.size()); + + for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + { + esm.writeHNCString(mRecName, it->mId); + esm.writeHNT("INTV", it->mLevel); + } } -} void LevelledListBase::blank() { diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index f88ff09d6f..26d70d964a 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -8,25 +8,50 @@ namespace ESM { unsigned int Light::sRecordId = REC_LIGH; -void Light::load(ESMReader &esm) -{ - mModel = esm.getHNOString("MODL"); - mName = esm.getHNOString("FNAM"); - mIcon = esm.getHNOString("ITEX"); - assert(sizeof(mData) == 24); - esm.getHNT(mData, "LHDT", 24); - mScript = esm.getHNOString("SCRI"); - mSound = esm.getHNOString("SNAM"); -} -void Light::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("ITEX", mIcon); - esm.writeHNT("LHDT", mData, 24); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("SNAM", mSound); -} + void Light::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'L','H','D','T'>::value: + esm.getHT(mData, 24); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'S','N','A','M'>::value: + mSound = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing LHDT subrecord"); + } + void Light::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("ITEX", mIcon); + esm.writeHNT("LHDT", mData, 24); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("SNAM", mSound); + } void Light::blank() { diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp index 42677a22bf..2747a6f787 100644 --- a/components/esm/loadlock.cpp +++ b/components/esm/loadlock.cpp @@ -8,26 +8,48 @@ namespace ESM { unsigned int Lockpick::sRecordId = REC_LOCK; -void Lockpick::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); + void Lockpick::load(ESMReader &esm) + { + bool hasData = true; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'L','K','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing LKDT subrecord"); + } - esm.getHNT(mData, "LKDT", 16); + void Lockpick::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); -} - -void Lockpick::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - - esm.writeHNT("LKDT", mData, 16); - esm.writeHNOString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + esm.writeHNT("LKDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Lockpick::blank() { diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index 3ec07a2a91..6f859ab3cd 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -246,7 +246,7 @@ void MagicEffect::load(ESMReader &esm) mDescription = esm.getHString(); break; default: - esm.fail("Unknown subrecord " + esm.retSubName().toString()); + esm.fail("Unknown subrecord"); } } } diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp index 4c7ac938a0..e66322832f 100644 --- a/components/esm/loadmgef.hpp +++ b/components/esm/loadmgef.hpp @@ -57,9 +57,9 @@ struct MagicEffect // Glow color for enchanted items with this effect int mRed, mGreen, mBlue; - float mUnknown1; + float mUnknown1; // Called "Size X" in CS float mSpeed; // Speed of fired projectile - float mUnknown2; + float mUnknown2; // Called "Size Cap" in CS }; // 36 bytes static const std::map sNames; diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 3d617241b6..d90b4816dd 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -99,7 +99,7 @@ namespace ESM mAiPackage.add(esm); break; default: - esm.fail("Unknown subrecord " + esm.retSubName().toString()); + esm.fail("Unknown subrecord"); } } if (!hasNpdt) diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp index b736bb64b5..c5f80c5844 100644 --- a/components/esm/loadprob.cpp +++ b/components/esm/loadprob.cpp @@ -8,26 +8,48 @@ namespace ESM { unsigned int Probe::sRecordId = REC_PROB; -void Probe::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); + void Probe::load(ESMReader &esm) + { + bool hasData = true; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'P','B','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing PBDT subrecord"); + } - esm.getHNT(mData, "PBDT", 16); + void Probe::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); -} - -void Probe::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - - esm.writeHNT("PBDT", mData, 16); - esm.writeHNOString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + esm.writeHNT("PBDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Probe::blank() { diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 211fd5ffb3..967c0d0d73 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -43,7 +43,7 @@ void Race::load(ESMReader &esm) mPowers.add(esm); break; default: - esm.fail("Unknown subrecord " + esm.retSubName().toString()); + esm.fail("Unknown subrecord"); } } if (!hasData) diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp index 4e6cd7794f..f90f9e39dc 100644 --- a/components/esm/loadrepa.cpp +++ b/components/esm/loadrepa.cpp @@ -10,13 +10,35 @@ namespace ESM void Repair::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - - esm.getHNT(mData, "RIDT", 16); - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); + bool hasData = true; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','I','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing RIDT subrecord"); } void Repair::save(ESMWriter &esm) const diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 2df8e66cee..0c2bdd42ff 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -9,17 +9,7 @@ namespace ESM unsigned int Script::sRecordId = REC_SCPT; -void Script::load(ESMReader &esm) -{ - SCHD data; - esm.getHNT(data, "SCHD", 52); - mData = data.mData; - mId = data.mName.toString(); - - mVarNames.clear(); - - // List of local variables - if (esm.isNextSub("SCVR")) + void Script::loadSCVR(ESMReader &esm) { int s = mData.mStringTableSize; @@ -66,58 +56,70 @@ void Script::load(ESMReader &esm) } } - // Script mData - if (esm.isNextSub("SCDT")) + void Script::load(ESMReader &esm) { - mScriptData.resize(mData.mScriptDataSize); - esm.getHExact(&mScriptData[0], mScriptData.size()); - } + SCHD data; + esm.getHNT(data, "SCHD", 52); + mData = data.mData; + mId = data.mName.toString(); - // Script text - mScriptText = esm.getHNOString("SCTX"); + mVarNames.clear(); - // NOTE: A minor hack/workaround... - // - // MAO_Containers.esp from Morrowind Acoustic Overhaul has SCVR records - // at the end (see Bug #1849). Since OpenMW does not use SCVR subrecords - // for variable names just skip these as a quick fix. An alternative - // solution would be to decode and validate SCVR subrecords even if they - // appear here. - if (esm.isNextSub("SCVR")) { - esm.skipHSub(); - } -} -void Script::save(ESMWriter &esm) const -{ - std::string varNameString; - if (!mVarNames.empty()) - for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) - varNameString.append(*it); - - SCHD data; - memset(&data, 0, sizeof(data)); - - data.mData = mData; - memcpy(data.mName.name, mId.c_str(), mId.size()); - - esm.writeHNT("SCHD", data, 52); - - if (!mVarNames.empty()) - { - esm.startSubRecord("SCVR"); - for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) + while (esm.hasMoreSubs()) { - esm.writeHCString(*it); + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'S','C','V','R'>::value: + // list of local variables + loadSCVR(esm); + break; + case ESM::FourCC<'S','C','D','T'>::value: + // compiled script + mScriptData.resize(mData.mScriptDataSize); + esm.getHExact(&mScriptData[0], mScriptData.size()); + break; + case ESM::FourCC<'S','C','T','X'>::value: + mScriptText = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } } - esm.endRecord("SCVR"); } - esm.startSubRecord("SCDT"); - esm.write(reinterpret_cast(&mScriptData[0]), mData.mScriptDataSize); - esm.endRecord("SCDT"); + void Script::save(ESMWriter &esm) const + { + std::string varNameString; + if (!mVarNames.empty()) + for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) + varNameString.append(*it); - esm.writeHNOString("SCTX", mScriptText); -} + SCHD data; + memset(&data, 0, sizeof(data)); + + data.mData = mData; + memcpy(data.mName.name, mId.c_str(), mId.size()); + + esm.writeHNT("SCHD", data, 52); + + if (!mVarNames.empty()) + { + esm.startSubRecord("SCVR"); + for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) + { + esm.writeHCString(*it); + } + esm.endRecord("SCVR"); + } + + esm.startSubRecord("SCDT"); + esm.write(reinterpret_cast(&mScriptData[0]), mData.mScriptDataSize); + esm.endRecord("SCDT"); + + esm.writeHNOString("SCTX", mScriptText); + } void Script::blank() { diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index d5b87b5dc2..deb71de6af 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -53,6 +53,9 @@ public: void blank(); ///< Set record to default state (does not touch the ID/index). + +private: + void loadSCVR(ESMReader &esm); }; } #endif diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index b6724e9381..7883b8a1a9 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -129,23 +129,47 @@ namespace ESM unsigned int Skill::sRecordId = REC_SKIL; -void Skill::load(ESMReader &esm) -{ - esm.getHNT(mIndex, "INDX"); - esm.getHNT(mData, "SKDT", 24); - mDescription = esm.getHNOString("DESC"); + void Skill::load(ESMReader &esm) + { + bool hasIndex = false; + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'I','N','D','X'>::value: + esm.getHT(mIndex); + hasIndex = true; + break; + case ESM::FourCC<'S','K','D','T'>::value: + esm.getHT(mData, 24); + hasData = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasIndex) + esm.fail("Missing INDX"); + if (!hasData) + esm.fail("Missing SKDT"); - // create an ID from the index and the name (only used in the editor and likely to change in the - // future) - mId = indexToId (mIndex); -} + // create an ID from the index and the name (only used in the editor and likely to change in the + // future) + mId = indexToId (mIndex); + } -void Skill::save(ESMWriter &esm) const -{ - esm.writeHNT("INDX", mIndex); - esm.writeHNT("SKDT", mData, 24); - esm.writeHNOString("DESC", mDescription); -} + void Skill::save(ESMWriter &esm) const + { + esm.writeHNT("INDX", mIndex); + esm.writeHNT("SKDT", mData, 24); + esm.writeHNOString("DESC", mDescription); + } void Skill::blank() { diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp index 9ab061ec25..5ee6f5245c 100644 --- a/components/esm/loadsndg.cpp +++ b/components/esm/loadsndg.cpp @@ -8,19 +8,38 @@ namespace ESM { unsigned int SoundGenerator::sRecordId = REC_SNDG; -void SoundGenerator::load(ESMReader &esm) -{ - esm.getHNT(mType, "DATA", 4); - - mCreature = esm.getHNOString("CNAM"); - mSound = esm.getHNOString("SNAM"); -} -void SoundGenerator::save(ESMWriter &esm) const -{ - esm.writeHNT("DATA", mType, 4); - esm.writeHNOCString("CNAM", mCreature); - esm.writeHNOCString("SNAM", mSound); -} + void SoundGenerator::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mType, 4); + hasData = true; + break; + case ESM::FourCC<'C','N','A','M'>::value: + mCreature = esm.getHString(); + break; + case ESM::FourCC<'S','N','A','M'>::value: + mSound = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing DATA"); + } + void SoundGenerator::save(ESMWriter &esm) const + { + esm.writeHNT("DATA", mType, 4); + esm.writeHNOCString("CNAM", mCreature); + esm.writeHNOCString("SNAM", mSound); + } void SoundGenerator::blank() { diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 28e4d7d9c5..690c1b4484 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -8,22 +8,35 @@ namespace ESM { unsigned int Sound::sRecordId = REC_SOUN; -void Sound::load(ESMReader &esm) -{ - mSound = esm.getHNOString("FNAM"); - esm.getHNT(mData, "DATA", 3); - /* - cout << "vol=" << (int)data.volume - << " min=" << (int)data.minRange - << " max=" << (int)data.maxRange - << endl; - */ -} -void Sound::save(ESMWriter &esm) const -{ - esm.writeHNOCString("FNAM", mSound); - esm.writeHNT("DATA", mData, 3); -} + void Sound::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mSound = esm.getHString(); + break; + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mData, 3); + hasData = true; + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing DATA"); + } + + void Sound::save(ESMWriter &esm) const + { + esm.writeHNOCString("FNAM", mSound); + esm.writeHNT("DATA", mData, 3); + } void Sound::blank() { diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index 716f47e715..cd630d6ab9 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -8,40 +8,40 @@ namespace ESM { unsigned int Spell::sRecordId = REC_SPEL; -void Spell::load(ESMReader &esm) -{ - bool hasData = false; - while (esm.hasMoreSubs()) + void Spell::load(ESMReader &esm) { - esm.getSubName(); - uint32_t val = esm.retSubName().val; - - switch (val) + bool hasData = false; + while (esm.hasMoreSubs()) { - case ESM::FourCC<'F','N','A','M'>::value: - mName = esm.getHString(); - break; - case ESM::FourCC<'S','P','D','T'>::value: - esm.getHT(mData, 12); - hasData = true; - break; - case ESM::FourCC<'E','N','A','M'>::value: - ENAMstruct s; - esm.getHT(s, 24); - mEffects.mList.push_back(s); - break; - } - } - if (!hasData) - esm.fail("Missing SPDT subrecord"); -} + esm.getSubName(); + uint32_t val = esm.retSubName().val; -void Spell::save(ESMWriter &esm) const -{ - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("SPDT", mData, 12); - mEffects.save(esm); -} + switch (val) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','P','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + ENAMstruct s; + esm.getHT(s, 24); + mEffects.mList.push_back(s); + break; + } + } + if (!hasData) + esm.fail("Missing SPDT subrecord"); + } + + void Spell::save(ESMWriter &esm) const + { + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("SPDT", mData, 12); + mEffects.save(esm); + } void Spell::blank() { diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp index 69b04bb237..816075b7e3 100644 --- a/components/esm/loadsscr.cpp +++ b/components/esm/loadsscr.cpp @@ -8,15 +8,37 @@ namespace ESM { unsigned int StartScript::sRecordId = REC_SSCR; -void StartScript::load(ESMReader &esm) -{ - mData = esm.getHNString("DATA"); - mScript = esm.getHNString("NAME"); -} -void StartScript::save(ESMWriter &esm) const -{ - esm.writeHNString("DATA", mData); - esm.writeHNString("NAME", mScript); -} + void StartScript::load(ESMReader &esm) + { + bool hasData = false; + bool hasName = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'D','A','T','A'>::value: + mData = esm.getHString(); + hasData = true; + break; + case ESM::FourCC<'N','A','M','E'>::value: + mScript = esm.getHString(); + hasName = true; + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing DATA"); + if (!hasName) + esm.fail("Missing NAME"); + } + void StartScript::save(ESMWriter &esm) const + { + esm.writeHNString("DATA", mData); + esm.writeHNString("NAME", mScript); + } } diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index 53d1b4bb59..2bb817332d 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -8,15 +8,16 @@ namespace ESM { unsigned int Static::sRecordId = REC_STAT; -void Static::load(ESMReader &esm) -{ - mPersistent = esm.getRecordFlags() & 0x0400; - mModel = esm.getHNString("MODL"); -} -void Static::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); -} + void Static::load(ESMReader &esm) + { + mPersistent = esm.getRecordFlags() & 0x0400; + + mModel = esm.getHNString("MODL"); + } + void Static::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + } void Static::blank() { diff --git a/components/esm/loadtes3.hpp b/components/esm/loadtes3.hpp index 2c63e36917..f2dde4d1f0 100644 --- a/components/esm/loadtes3.hpp +++ b/components/esm/loadtes3.hpp @@ -50,8 +50,8 @@ namespace ESM NAME32 mPlayerName; }; GMDT mGameData; // Used in .ess savegames only - std::vector mSCRD; // Used in .ess savegames only, screenshot? - std::vector mSCRS; // Used in .ess savegames only, screenshot? + std::vector mSCRD; // Used in .ess savegames only, unknown + std::vector mSCRS; // Used in .ess savegames only, screenshot Data mData; int mFormat; diff --git a/components/esm/spelllist.cpp b/components/esm/spelllist.cpp index 98bd53ae6a..71c7b340d2 100644 --- a/components/esm/spelllist.cpp +++ b/components/esm/spelllist.cpp @@ -5,14 +5,6 @@ namespace ESM { -void SpellList::load(ESMReader &esm) -{ - mList.clear(); - while (esm.isNextSub("NPCS")) { - add(esm); - } -} - void SpellList::add(ESMReader &esm) { mList.push_back(esm.getHString()); diff --git a/components/esm/spelllist.hpp b/components/esm/spelllist.hpp index 9493199a80..6fb0980659 100644 --- a/components/esm/spelllist.hpp +++ b/components/esm/spelllist.hpp @@ -11,6 +11,7 @@ namespace ESM /** A list of references to spells and spell effects. This is shared between the records BSGN, NPC and RACE. + NPCS subrecord. */ struct SpellList { @@ -22,9 +23,6 @@ namespace ESM /// Load one spell, assumes the subrecord name was already read void add(ESMReader &esm); - /// Load all spells - /// TODO: remove this method, the ESM format doesn't guarantee that all spell subrecords follow one another - void load(ESMReader &esm); void save(ESMWriter &esm) const; }; } From e1314d62117a31d3bd77912c6c70f67b26262a6f Mon Sep 17 00:00:00 2001 From: Kamil Bar Date: Fri, 13 Feb 2015 04:11:36 +0100 Subject: [PATCH 157/214] Implement OpenCS reference validation (Feature #831) --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/referencecheck.cpp | 103 +++++++++++++++++++++ apps/opencs/model/tools/referencecheck.hpp | 28 ++++++ apps/opencs/model/tools/tools.cpp | 3 + 4 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/referencecheck.cpp create mode 100644 apps/opencs/model/tools/referencecheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0b83feb450..d295462081 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 referenceablecheck scriptcheck bodypartcheck + birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck ) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp new file mode 100644 index 0000000000..eb97645ebe --- /dev/null +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -0,0 +1,103 @@ +#include "referencecheck.hpp" + +#include + +CSMTools::ReferenceCheckStage::ReferenceCheckStage( + const CSMWorld::RefCollection& references, + const CSMWorld::RefIdCollection& referencables, + const CSMWorld::IdCollection& cells, + const CSMWorld::IdCollection& factions) + : + mReferences(references), + mReferencables(referencables), + mCells(cells), + mFactions(factions) +{ +} + +void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &messages) +{ + const CSMWorld::Record& record = mReferences.getRecord(stage); + + if (record.isDeleted()) + return; + + const CSMWorld::CellRef& cellRef = record.get(); + const CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Reference, cellRef.mId); + + // Check for empty reference id + if (cellRef.mRefID.empty()) + messages.push_back(std::make_pair(id, " is an empty reference")); + + // Check for non existing referenced object + if (mReferencables.searchId(cellRef.mRefID) == -1) + messages.push_back(std::make_pair(id, " is referencing non existing object " + cellRef.mRefID)); + + // Check if referenced object is in valid cell + if (mCells.searchId(cellRef.mCell) == -1) + messages.push_back(std::make_pair(id, " is referencing object from non existing cell " + cellRef.mCell)); + + // If object have owner, check if that owner reference is valid + if (!cellRef.mOwner.empty() and mReferencables.searchId(cellRef.mOwner) == -1) + messages.push_back(std::make_pair(id, " has non existing owner " + cellRef.mOwner)); + + // If object have creature soul trapped, check if that creature reference is valid + if (!cellRef.mSoul.empty()) + if (mReferencables.searchId(cellRef.mSoul) == -1) + messages.push_back(std::make_pair(id, " has non existing trapped soul " + cellRef.mSoul)); + + bool hasFaction = !cellRef.mFaction.empty(); + + // If object have faction, check if that faction reference is valid + if (hasFaction) + if (mFactions.searchId(cellRef.mFaction) == -1) + messages.push_back(std::make_pair(id, " has non existing faction " + cellRef.mFaction)); + + // Check item's faction rank + if (hasFaction && cellRef.mFactionRank < -1) + messages.push_back(std::make_pair(id, " has faction set but has invalid faction rank " + cellRef.mFactionRank)); + else if (!hasFaction && cellRef.mFactionRank != -2) + messages.push_back(std::make_pair(id, " has invalid faction rank " + cellRef.mFactionRank)); + + // If door have destination cell, check if that reference is valid + if (!cellRef.mDestCell.empty()) + if (mCells.searchId(cellRef.mDestCell) == -1) + messages.push_back(std::make_pair(id, " has non existing destination cell " + cellRef.mDestCell)); + + // Check if scale isn't negative + if (cellRef.mScale < 0) + { + std::string str = " has negative scale "; + str += boost::lexical_cast(cellRef.mScale); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + + // Check if charge isn't negative + if (cellRef.mChargeFloat < 0) + { + std::string str = " has negative charges "; + str += boost::lexical_cast(cellRef.mChargeFloat); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + + // Check if enchantement points aren't negative or are at full (-1) + if (cellRef.mEnchantmentCharge < 0 && cellRef.mEnchantmentCharge != -1) + { + std::string str = " has negative enchantment points "; + str += boost::lexical_cast(cellRef.mEnchantmentCharge); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + + // Check if gold value isn't negative + if (cellRef.mGoldValue < 0) + { + std::string str = " has negative gold value "; + str += cellRef.mGoldValue; + messages.push_back(std::make_pair(id, id.getId() + str)); + } +} + +int CSMTools::ReferenceCheckStage::setup() +{ + return mReferences.getSize(); +} \ No newline at end of file diff --git a/apps/opencs/model/tools/referencecheck.hpp b/apps/opencs/model/tools/referencecheck.hpp new file mode 100644 index 0000000000..d1eacb5b54 --- /dev/null +++ b/apps/opencs/model/tools/referencecheck.hpp @@ -0,0 +1,28 @@ +#ifndef CSM_TOOLS_REFERENCECHECK_H +#define CSM_TOOLS_REFERENCECHECK_H + +#include "../doc/state.hpp" +#include "../doc/document.hpp" + +namespace CSMTools +{ + class ReferenceCheckStage : public CSMDoc::Stage + { + public: + ReferenceCheckStage (const CSMWorld::RefCollection& references, + const CSMWorld::RefIdCollection& referencables, + const CSMWorld::IdCollection& cells, + const CSMWorld::IdCollection& factions); + + virtual void perform(int stage, CSMDoc::Messages& messages); + virtual int setup(); + + private: + const CSMWorld::RefCollection& mReferences; + const CSMWorld::RefIdCollection& mReferencables; + const CSMWorld::IdCollection& mCells; + const CSMWorld::IdCollection& mFactions; + }; +} + +#endif // CSM_TOOLS_REFERENCECHECK_H \ No newline at end of file diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 6e157f664f..0c20bd17b4 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -23,6 +23,7 @@ #include "referenceablecheck.hpp" #include "scriptcheck.hpp" #include "bodypartcheck.hpp" +#include "referencecheck.hpp" CSMDoc::Operation *CSMTools::Tools::get (int type) { @@ -82,6 +83,8 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions())); + mVerifier->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions())); + mVerifier->appendStage (new ScriptCheckStage (mDocument)); mVerifier->appendStage( From 1d18d3ff4cb5a6f28b7f0d7ca03f076a5794a447 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Thu, 12 Feb 2015 22:27:47 -0600 Subject: [PATCH 158/214] Add a full search to findInteriorPositionInWorldSpace. Part of OMW Bug #1533 Implement a search for one of the 'nearest' exterior cells. In this case, 'nearest' means the fewest number of cells away via door markers. This causes the world map position to update immediately after teleporting, unless the new cell has no connecting path to an exterior. Intervention spells and Jail travel will be much closer to vanialla Morrowind, except for in Mournhold. --- apps/openmw/mwworld/worldimp.cpp | 49 +++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 188f3cdad3..23cef1596b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2784,18 +2784,45 @@ namespace MWWorld { if (cell->isExterior()) return false; - MWWorld::CellRefList& doors = cell->get(); - CellRefList::List& refList = doors.mList; - // Check if any door in the cell leads to an exterior directly - for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) - { - MWWorld::LiveCellRef& ref = *it; - if (ref.mRef.getTeleport() && ref.mRef.getDestCell().empty()) - { - ESM::Position pos = ref.mRef.getDoorDest(); - result = Ogre::Vector3(pos.pos); - return true; + // Search for a 'nearest' exterior, counting each cell between the starting + // cell and the exterior as a distance of 1. Will fail for isolated interiors. + std::set< std::string >checkedCells; + std::set< std::string >currentCells; + std::set< std::string >nextCells; + nextCells.insert( cell->getCell()->mName ); + + while ( !nextCells.empty() ) { + currentCells = nextCells; + nextCells.clear(); + for( std::set< std::string >::const_iterator i = currentCells.begin(); i != currentCells.end(); ++i ) { + MWWorld::CellStore *next = getInterior( *i ); + if ( !next ) continue; + + MWWorld::CellRefList& doors = next->get(); + CellRefList::List& refList = doors.mList; + + // Check if any door in the cell leads to an exterior directly + for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) + { + MWWorld::LiveCellRef& ref = *it; + if (!ref.mRef.getTeleport()) continue; + + if (ref.mRef.getDestCell().empty()) + { + ESM::Position pos = ref.mRef.getDoorDest(); + result = Ogre::Vector3(pos.pos); + return true; + } + else + { + std::string dest = ref.mRef.getDestCell(); + if ( !checkedCells.count(dest) && !currentCells.count(dest) ) + nextCells.insert(dest); + } + } + + checkedCells.insert( *i ); } } From 52a064afc39a205eb0b893862b76d331dc6063cf Mon Sep 17 00:00:00 2001 From: Kamil Bar Date: Fri, 13 Feb 2015 12:13:40 +0100 Subject: [PATCH 159/214] Fixed charges checking --- apps/opencs/model/tools/referencecheck.cpp | 40 +++++++++++++++------- apps/opencs/model/tools/referencecheck.hpp | 1 + 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index eb97645ebe..f1d092be58 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -10,6 +10,7 @@ CSMTools::ReferenceCheckStage::ReferenceCheckStage( : mReferences(references), mReferencables(referencables), + mDataSet(referencables.getDataSet()), mCells(cells), mFactions(factions) { @@ -26,12 +27,33 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message const CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Reference, cellRef.mId); // Check for empty reference id - if (cellRef.mRefID.empty()) + if (cellRef.mRefID.empty()) { messages.push_back(std::make_pair(id, " is an empty reference")); - - // Check for non existing referenced object - if (mReferencables.searchId(cellRef.mRefID) == -1) - messages.push_back(std::make_pair(id, " is referencing non existing object " + cellRef.mRefID)); + } else { + // Check for non existing referenced object + if (mReferencables.searchId(cellRef.mRefID) == -1) { + messages.push_back(std::make_pair(id, " is referencing non existing object " + cellRef.mRefID)); + } else { + // Check if reference charge isn't negative if it's proper type + CSMWorld::RefIdData::LocalIndex localIndex = mDataSet.searchId(cellRef.mRefID); + if (localIndex.second == CSMWorld::UniversalId::Type_Armor || + localIndex.second == CSMWorld::UniversalId::Type_Weapon) { + if (cellRef.mChargeFloat < 0) { + std::string str = " has negative durability "; + str += boost::lexical_cast(cellRef.mChargeFloat); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + } else if (localIndex.second == CSMWorld::UniversalId::Type_Lockpick || + localIndex.second == CSMWorld::UniversalId::Type_Probe || + localIndex.second == CSMWorld::UniversalId::Type_Repair) { + if (cellRef.mChargeInt < -1) { + std::string str = " has invalid charges "; + str += boost::lexical_cast(cellRef.mChargeFloat); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + } + } + } // Check if referenced object is in valid cell if (mCells.searchId(cellRef.mCell) == -1) @@ -72,14 +94,6 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message messages.push_back(std::make_pair(id, id.getId() + str)); } - // Check if charge isn't negative - if (cellRef.mChargeFloat < 0) - { - std::string str = " has negative charges "; - str += boost::lexical_cast(cellRef.mChargeFloat); - messages.push_back(std::make_pair(id, id.getId() + str)); - } - // Check if enchantement points aren't negative or are at full (-1) if (cellRef.mEnchantmentCharge < 0 && cellRef.mEnchantmentCharge != -1) { diff --git a/apps/opencs/model/tools/referencecheck.hpp b/apps/opencs/model/tools/referencecheck.hpp index d1eacb5b54..9cf685b3ad 100644 --- a/apps/opencs/model/tools/referencecheck.hpp +++ b/apps/opencs/model/tools/referencecheck.hpp @@ -20,6 +20,7 @@ namespace CSMTools private: const CSMWorld::RefCollection& mReferences; const CSMWorld::RefIdCollection& mReferencables; + const CSMWorld::RefIdData& mDataSet; const CSMWorld::IdCollection& mCells; const CSMWorld::IdCollection& mFactions; }; From 9628415e21aca4cc7649f2f32fab3fb2b52ad209 Mon Sep 17 00:00:00 2001 From: Kamil Bar Date: Fri, 13 Feb 2015 12:16:46 +0100 Subject: [PATCH 160/214] Missing change & changed comments to represent actual code --- apps/opencs/model/tools/referencecheck.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index f1d092be58..d8e056a76b 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -34,7 +34,7 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message if (mReferencables.searchId(cellRef.mRefID) == -1) { messages.push_back(std::make_pair(id, " is referencing non existing object " + cellRef.mRefID)); } else { - // Check if reference charge isn't negative if it's proper type + // Check if reference charge is valid for it's proper referenced type CSMWorld::RefIdData::LocalIndex localIndex = mDataSet.searchId(cellRef.mRefID); if (localIndex.second == CSMWorld::UniversalId::Type_Armor || localIndex.second == CSMWorld::UniversalId::Type_Weapon) { @@ -48,7 +48,7 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message localIndex.second == CSMWorld::UniversalId::Type_Repair) { if (cellRef.mChargeInt < -1) { std::string str = " has invalid charges "; - str += boost::lexical_cast(cellRef.mChargeFloat); + str += boost::lexical_cast(cellRef.mChargeInt); messages.push_back(std::make_pair(id, id.getId() + str)); } } From 3b7a23aa725935cb69ebd23ded4bfe36510e8333 Mon Sep 17 00:00:00 2001 From: Kamil Bar Date: Fri, 13 Feb 2015 13:11:10 +0100 Subject: [PATCH 161/214] Fixed charge checks for light and other objects, corrected CellRef charge union comments --- apps/opencs/model/tools/referencecheck.cpp | 19 ++++++------------- components/esm/cellref.hpp | 6 ++++-- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index d8e056a76b..aae83bd5ea 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -36,21 +36,14 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message } else { // Check if reference charge is valid for it's proper referenced type CSMWorld::RefIdData::LocalIndex localIndex = mDataSet.searchId(cellRef.mRefID); - if (localIndex.second == CSMWorld::UniversalId::Type_Armor || - localIndex.second == CSMWorld::UniversalId::Type_Weapon) { - if (cellRef.mChargeFloat < 0) { - std::string str = " has negative durability "; + bool isLight = localIndex.second == CSMWorld::UniversalId::Type_Light; + if ((isLight && cellRef.mChargeFloat < -1) || (!isLight && cellRef.mChargeInt < -1)) { + std::string str = " has invalid charge "; + if (localIndex.second == CSMWorld::UniversalId::Type_Light) str += boost::lexical_cast(cellRef.mChargeFloat); - messages.push_back(std::make_pair(id, id.getId() + str)); - } - } else if (localIndex.second == CSMWorld::UniversalId::Type_Lockpick || - localIndex.second == CSMWorld::UniversalId::Type_Probe || - localIndex.second == CSMWorld::UniversalId::Type_Repair) { - if (cellRef.mChargeInt < -1) { - std::string str = " has invalid charges "; + else str += boost::lexical_cast(cellRef.mChargeInt); - messages.push_back(std::make_pair(id, id.getId() + str)); - } + messages.push_back(std::make_pair(id, id.getId() + str)); } } } diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 56932aa4db..01b6a8473d 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -59,10 +59,12 @@ namespace ESM // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. + // For lights it is remaining time. + // This could be -1 if the charge was not touched yet (i.e. full). union { - int mChargeInt; - float mChargeFloat; + int mChargeInt; // Used by everything except lights + float mChargeFloat; // Used only by lights }; // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). From a139e4efb08c102edf7afeb4d46cdafed8f2d98f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Feb 2015 16:51:34 +0100 Subject: [PATCH 162/214] Grey out completed quests in journal quests list --- apps/openmw/mwgui/journalviewmodel.cpp | 4 ++-- apps/openmw/mwgui/journalviewmodel.hpp | 4 ++-- apps/openmw/mwgui/journalwindow.cpp | 22 +++++++++++++++++++++- components/widgets/list.cpp | 4 ++-- components/widgets/list.hpp | 2 +- files/mygui/openmw_journal.skin.xml | 6 +++--- 6 files changed, 31 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 3a86613f61..9a47070c2f 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -199,7 +199,7 @@ struct JournalViewModelImpl : JournalViewModel }; - void visitQuestNames (bool active_only, boost::function visitor) const + void visitQuestNames (bool active_only, boost::function visitor) const { MWBase::Journal * journal = MWBase::Environment::get ().getJournal (); @@ -231,7 +231,7 @@ struct JournalViewModelImpl : JournalViewModel if (visitedQuests.find(quest.getName()) != visitedQuests.end()) continue; - visitor (quest.getName()); + visitor (quest.getName(), isFinished); visitedQuests.insert(quest.getName()); } diff --git a/apps/openmw/mwgui/journalviewmodel.hpp b/apps/openmw/mwgui/journalviewmodel.hpp index 5f0189b590..b3c6b0183c 100644 --- a/apps/openmw/mwgui/journalviewmodel.hpp +++ b/apps/openmw/mwgui/journalviewmodel.hpp @@ -67,8 +67,8 @@ namespace MWGui /// returns true if their are no journal entries to display virtual bool isEmpty () const = 0; - /// walks the active and optionally completed, quests providing the name - virtual void visitQuestNames (bool active_only, boost::function visitor) const = 0; + /// walks the active and optionally completed, quests providing the name and completed status + virtual void visitQuestNames (bool active_only, boost::function visitor) const = 0; /// walks over the journal entries related to all quests with the given name /// If \a questName is empty, simply visits all journal entries diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index d7e27a2776..4cfcc80641 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -428,11 +429,24 @@ namespace AddNamesToList(Gui::MWList* list) : mList(list) {} Gui::MWList* mList; - void operator () (const std::string& name) + void operator () (const std::string& name, bool finished=false) { mList->addItem(name); } }; + struct SetNamesInactive + { + SetNamesInactive(Gui::MWList* list) : mList(list) {} + + Gui::MWList* mList; + void operator () (const std::string& name, bool finished) + { + if (finished) + { + mList->getItemWidget(name)->setStateSelected(true); + } + } + }; void notifyQuests(MyGUI::Widget* _sender) { @@ -453,6 +467,12 @@ namespace mModel->visitQuestNames(!mAllQuests, add); list->adjustSize(); + + if (mAllQuests) + { + SetNamesInactive setInactive(list); + mModel->visitQuestNames(!mAllQuests, setInactive); + } } void notifyShowAll(MyGUI::Widget* _sender) diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index 28271e87df..f3d3a2c288 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -152,9 +152,9 @@ namespace Gui eventWidgetSelected(_sender); } - MyGUI::Widget* MWList::getItemWidget(const std::string& name) + MyGUI::Button *MWList::getItemWidget(const std::string& name) { - return mScrollView->findWidget (getName() + "_item_" + name); + return mScrollView->findWidget (getName() + "_item_" + name)->castType(); } } diff --git a/components/widgets/list.hpp b/components/widgets/list.hpp index 093cd8c186..72c8a733c1 100644 --- a/components/widgets/list.hpp +++ b/components/widgets/list.hpp @@ -43,7 +43,7 @@ namespace Gui std::string getItemNameAt(unsigned int at); ///< \attention if there are separators, this method will return "" at the place where the separator is void clear(); - MyGUI::Widget* getItemWidget(const std::string& name); + MyGUI::Button* getItemWidget(const std::string& name); ///< get widget for an item name, useful to set up tooltip virtual void setPropertyOverride(const std::string& _key, const std::string& _value); diff --git a/files/mygui/openmw_journal.skin.xml b/files/mygui/openmw_journal.skin.xml index 942c9a4d40..42be2bb629 100644 --- a/files/mygui/openmw_journal.skin.xml +++ b/files/mygui/openmw_journal.skin.xml @@ -28,9 +28,9 @@ - - - + + +
From 8b417c06db7fcfd0c44e88a07b5e4f2b2ea4c868 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Feb 2015 17:26:33 +0100 Subject: [PATCH 163/214] Fix missing clear in ESM::Spell::load (Fixes #2368) --- components/esm/loadspel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index cd630d6ab9..96c048e0a9 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -10,6 +10,7 @@ namespace ESM void Spell::load(ESMReader &esm) { + mEffects.mList.clear(); bool hasData = false; while (esm.hasMoreSubs()) { From 96a295c44f33926756d6bff35cc7982919561cc6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Feb 2015 17:37:56 +0100 Subject: [PATCH 164/214] Fix for deleting all items in a levelled list --- components/esm/loadlevlist.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 6080d1e1ab..ca5c5d74d8 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -21,6 +21,7 @@ namespace ESM else { // Original engine ignores rest of the record, even if there are items following + mList.clear(); esm.skipRecord(); return; } From 74232b90fcf928ad6f07a92886245bf6937f07b2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 13 Feb 2015 18:26:36 +0100 Subject: [PATCH 165/214] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 59aa427218..540c0ede5a 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -78,6 +78,7 @@ Programmers naclander Narmo Nathan Jeffords (blunted2night) + NeveHanter Nikolay Kasyanov (corristo) nobrakal Nolan Poe (nopoe) From a1ee26922e2aca1c975e9095de93f56a10d9e6ce Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Feb 2015 12:00:16 +0100 Subject: [PATCH 166/214] ESSImport: note location of corpse clear countdown --- apps/essimporter/importacdt.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 47055092de..eacb2edf1a 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -43,13 +43,17 @@ namespace ESSImport float mMagicEffects[27]; // Effect attributes: https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attributes unsigned char mUnknown4[4]; unsigned int mGoldPool; - unsigned char mUnknown5[4]; + unsigned char mCountDown; // seen the same value as in ACSC.mCorpseClearCountdown, maybe + // this one is for respawning? + unsigned char mUnknown5[3]; }; struct ACSC { unsigned char mUnknown1[17]; unsigned char mFlags; // ACSCFlags - unsigned char mUnknown2[94]; + unsigned char mUnknown2[22]; + unsigned char mCorpseClearCountdown; // hours? + unsigned char mUnknown3[71]; }; #pragma pack(pop) From 0e88fb3dca206ce61d938db7d70f96bfb26b1a2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Feb 2015 12:25:52 +0100 Subject: [PATCH 167/214] ESSImport: read AiPackages --- apps/essimporter/importcrec.cpp | 4 ++-- apps/essimporter/importcrec.hpp | 2 ++ apps/essimporter/importnpcc.cpp | 3 +-- apps/essimporter/importnpcc.hpp | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/essimporter/importcrec.cpp b/apps/essimporter/importcrec.cpp index 7a8a3eb00d..64879f2afc 100644 --- a/apps/essimporter/importcrec.cpp +++ b/apps/essimporter/importcrec.cpp @@ -14,10 +14,10 @@ namespace ESSImport float scale; esm.getHNOT(scale, "XSCL"); - // FIXME: use AiPackageList, need to fix getSubName() + while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F") || esm.isNextSub("AI_A")) - esm.skipHSub(); + mAiPackages.add(esm); mInventory.load(esm); } diff --git a/apps/essimporter/importcrec.hpp b/apps/essimporter/importcrec.hpp index 16b7528070..5110fbc689 100644 --- a/apps/essimporter/importcrec.hpp +++ b/apps/essimporter/importcrec.hpp @@ -2,6 +2,7 @@ #define OPENMW_ESSIMPORT_CREC_H #include "importinventory.hpp" +#include namespace ESM { @@ -17,6 +18,7 @@ namespace ESSImport int mIndex; Inventory mInventory; + ESM::AIPackageList mAiPackages; void load(ESM::ESMReader& esm); }; diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp index 547b014413..3cbd749ce8 100644 --- a/apps/essimporter/importnpcc.cpp +++ b/apps/essimporter/importnpcc.cpp @@ -9,10 +9,9 @@ namespace ESSImport { esm.getHNT(mNPDT, "NPDT"); - // FIXME: use AiPackageList, need to fix getSubName() while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F") || esm.isNextSub("AI_A")) - esm.skipHSub(); + mAiPackages.add(esm); mInventory.load(esm); } diff --git a/apps/essimporter/importnpcc.hpp b/apps/essimporter/importnpcc.hpp index c69fa3e035..a23ab1e50b 100644 --- a/apps/essimporter/importnpcc.hpp +++ b/apps/essimporter/importnpcc.hpp @@ -27,6 +27,7 @@ namespace ESSImport } mNPDT; Inventory mInventory; + ESM::AIPackageList mAiPackages; void load(ESM::ESMReader &esm); }; From 93ffdb427c3d4faafb59f0317a112baba680fada Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Feb 2015 15:53:01 +0100 Subject: [PATCH 168/214] Small tweak to ripples --- apps/openmw/mwrender/ripplesimulation.cpp | 1 - files/materials/ripples.particle | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 84794162f3..dcafcb79fe 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -113,7 +113,6 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) position.z = 0; // Z is set by the Scene Node rotSpeed = mRippleRotSpeed; rotation = Ogre::Radian(Ogre::Math::RangeRandom(-Ogre::Math::PI, Ogre::Math::PI)); - created->setDimensions(50,50); } } diff --git a/files/materials/ripples.particle b/files/materials/ripples.particle index e8402b6914..58045f6d73 100644 --- a/files/materials/ripples.particle +++ b/files/materials/ripples.particle @@ -1,8 +1,8 @@ particle_system openmw/Ripples { material openmw/Ripple - particle_width 50 - particle_height 50 + particle_width 30 + particle_height 30 // To make the particles move with the scene node when the waterlevel changes local_space true quota 300 @@ -17,7 +17,7 @@ particle_system openmw/Ripples affector Scaler { - rate 100 + rate 120 } affector Rotator From 37a85e31d6681141e341bb62fc072328c35e1a2c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Feb 2015 16:51:47 +0100 Subject: [PATCH 169/214] Ripples fix --- apps/openmw/mwrender/ripplesimulation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index dcafcb79fe..bb1bccc0a3 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -113,6 +113,7 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) position.z = 0; // Z is set by the Scene Node rotSpeed = mRippleRotSpeed; rotation = Ogre::Radian(Ogre::Math::RangeRandom(-Ogre::Math::PI, Ogre::Math::PI)); + created->setDimensions(mParticleSystem->getDefaultWidth(), mParticleSystem->getDefaultHeight()); } } From 81925645a34b4591d6be7ccf0b8ce13d6efa536b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Feb 2015 16:51:54 +0100 Subject: [PATCH 170/214] Unreachable enemies combat AI fix (Fixes #2271) --- apps/openmw/mwmechanics/aicombat.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index f2b125add6..fd4fd293d6 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -207,16 +207,6 @@ namespace MWMechanics const MWWorld::Class& actorClass = actor.getClass(); MWBase::World* world = MWBase::Environment::get().getWorld(); - // can't fight if attacker can't go where target is. E.g. A fish can't attack person on land. - if (!actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) - { - actorClass.getCreatureStats(actor).setAttackingOrSpell(false); - return true; - } - - - - //Update every frame bool& combatMove = storage.mCombatMove; @@ -476,6 +466,19 @@ namespace MWMechanics // 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)) + { + // TODO: start fleeing? + movement.mPosition[0] = 0; + movement.mPosition[1] = 0; + movement.mPosition[2] = 0; + readyToAttack = false; + actorClass.getCreatureStats(actor).setAttackingOrSpell(false); + return false; + } + // (within attack dist) || (not quite attack dist while following) if(inLOS && (distToTarget < rangeAttack || (distToTarget <= rangeFollow && followTarget && !isStuck))) { From 5ef78903dc28554ad58784ac13f9aba1a135c5ad Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sat, 14 Feb 2015 15:43:09 -0600 Subject: [PATCH 171/214] Teleportation: Support markers in Mournhold. OMW Bug #1533 Note: the 'stolen goods' search is not yet correct for Mournhald. --- apps/openmw/mwworld/worldimp.cpp | 106 +++++++++++++++++++++++++------ apps/openmw/mwworld/worldimp.hpp | 2 + 2 files changed, 88 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 23cef1596b..fda73238a6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2830,33 +2830,99 @@ namespace MWWorld return false; } + MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) + { + // Search for a 'nearest' marker, counting each cell between the starting + // cell and the exterior as a distance of 1. If an exterior is found, jump + // to the nearest exterior marker, without further interior searching. + std::set< std::string >checkedCells; + std::set< std::string >currentCells; + std::set< std::string >nextCells; + nextCells.insert( ptr.getCell()->getCell()->mName ); + while ( !nextCells.empty() ) { + currentCells = nextCells; + nextCells.clear(); + for( std::set< std::string >::const_iterator i = currentCells.begin(); i != currentCells.end(); ++i ) { + MWWorld::CellStore *next = getInterior( *i ); + checkedCells.insert( *i ); + if ( !next ) continue; + + MWWorld::CellRefList& statics = next->get(); + CellRefList::List& staticList = statics.mList; + for (CellRefList::List::iterator it = staticList.begin(); it != staticList.end(); ++it) + { + MWWorld::LiveCellRef& ref = *it; + if ( id == ref.mRef.getRefId() ) { + return MWWorld::Ptr( &ref, next ); + } + } + + MWWorld::CellRefList& doors = next->get(); + CellRefList::List& doorList = doors.mList; + + // Check if any door in the cell leads to an exterior directly + for (CellRefList::List::iterator it = doorList.begin(); it != doorList.end(); ++it) + { + MWWorld::LiveCellRef& ref = *it; + + if ( id == ref.mRef.getRefId() ) { + return MWWorld::Ptr( &ref, next ); + } + + if (!ref.mRef.getTeleport()) continue; + + if (ref.mRef.getDestCell().empty()) + { + Ogre::Vector3 worldPos = Ogre::Vector3(ref.mRef.getDoorDest().pos); + float closestDistance = FLT_MAX; + + MWWorld::Ptr closestMarker; + std::vector markers; + mCells.getExteriorPtrs(id, markers); + for (std::vector::iterator it2 = markers.begin(); it2 != markers.end(); ++it2) + { + ESM::Position pos = it2->getRefData().getPosition(); + Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos); + float distance = worldPos.squaredDistance(markerPos); + if (distance < closestDistance) + { + closestDistance = distance; + closestMarker = *it2; + } + + } + + return closestMarker; + } + else + { + std::string dest = ref.mRef.getDestCell(); + if ( !checkedCells.count(dest) && !currentCells.count(dest) ) + nextCells.insert(dest); + } + } + } + } + + return MWWorld::Ptr(); + } + void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, const std::string& id) { - Ogre::Vector3 worldPos; - if (!findInteriorPositionInWorldSpace(ptr.getCell(), worldPos)) - worldPos = mPlayer->getLastKnownExteriorPosition(); + MWWorld::Ptr closestMarker = getClosestMarker( ptr, id ); - MWWorld::Ptr closestMarker; - float closestDistance = FLT_MAX; - - std::vector markers; - mCells.getExteriorPtrs(id, markers); - - for (std::vector::iterator it = markers.begin(); it != markers.end(); ++it) + if ( closestMarker.isEmpty() ) { - ESM::Position pos = it->getRefData().getPosition(); - Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos); - float distance = worldPos.squaredDistance(markerPos); - if (distance < closestDistance) - { - closestDistance = distance; - closestMarker = *it; - } - + std::cerr << "Failed to teleport: no closest marker found" << std::endl; + return; } - MWWorld::ActionTeleport action("", closestMarker.getRefData().getPosition()); + std::string cellName; + if ( !closestMarker.mCell->isExterior() ) + cellName = closestMarker.mCell->getCell()->mName; + + MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition()); action.execute(ptr); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9980f6f906..7a3505fd4d 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -151,6 +151,8 @@ namespace MWWorld float feetToGameUnits(float feet); + MWWorld::Ptr getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ); + public: World (OEngine::Render::OgreRenderer& renderer, From 6d1aec6970ef753e08e687c06eb80cdfd403cc9a Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sat, 14 Feb 2015 16:09:17 -0600 Subject: [PATCH 172/214] Confiscate stolen goods: Support Mournhold prisons. OMW Bug #1533 --- apps/openmw/mwworld/worldimp.cpp | 37 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fda73238a6..54385cf83f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3071,28 +3071,29 @@ namespace MWWorld void World::confiscateStolenItems(const Ptr &ptr) { - Ogre::Vector3 playerPos; - if (!findInteriorPositionInWorldSpace(ptr.getCell(), playerPos)) - playerPos = mPlayer->getLastKnownExteriorPosition(); + MWWorld::Ptr prisonMarker = getClosestMarker( ptr, "prisonmarker" ); + std::string prisonName = prisonMarker.mRef->mRef.getDestCell(); + if ( prisonName.empty() ) + { + std::cerr << "Failed to confiscate items: prison marker not linked to prison interior" << std::endl; + return; + } + MWWorld::CellStore *prison = getInterior( prisonName ); + if ( !prison ) + { + std::cerr << "Failed to confiscate items: failed to load cell " << prisonName << std::endl; + return; + } MWWorld::Ptr closestChest; - float closestDistance = FLT_MAX; - //Find closest stolen_goods chest - std::vector chests; - mCells.getInteriorPtrs("stolen_goods", chests); - - Ogre::Vector3 chestPos; - for (std::vector::iterator it = chests.begin(); it != chests.end(); ++it) + MWWorld::CellRefList& containers = prison->get(); + CellRefList::List& refList = containers.mList; + for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) { - if (!findInteriorPositionInWorldSpace(it->getCell(), chestPos)) - continue; - - float distance = playerPos.squaredDistance(chestPos); - if (distance < closestDistance) - { - closestDistance = distance; - closestChest = *it; + MWWorld::LiveCellRef& ref = *it; + if ( ref.mRef.getRefId() == "stolen_goods" ) { + closestChest = MWWorld::Ptr( &ref, prison ); } } From a61019dfa804fc2d1a6d54ec7e6600cacda22116 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 15 Feb 2015 04:47:25 +0100 Subject: [PATCH 173/214] Update referencecheck.cpp MSVC does not allow for the usage of 'and' or 'or' literals --- apps/opencs/model/tools/referencecheck.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index aae83bd5ea..0c1d7d38f3 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -53,7 +53,7 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message messages.push_back(std::make_pair(id, " is referencing object from non existing cell " + cellRef.mCell)); // If object have owner, check if that owner reference is valid - if (!cellRef.mOwner.empty() and mReferencables.searchId(cellRef.mOwner) == -1) + if (!cellRef.mOwner.empty() && mReferencables.searchId(cellRef.mOwner) == -1) messages.push_back(std::make_pair(id, " has non existing owner " + cellRef.mOwner)); // If object have creature soul trapped, check if that creature reference is valid @@ -107,4 +107,4 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message int CSMTools::ReferenceCheckStage::setup() { return mReferences.getSize(); -} \ No newline at end of file +} From f1fd27aeaf2585348b46b526e0267fb36443e8f3 Mon Sep 17 00:00:00 2001 From: slothlife Date: Sat, 14 Feb 2015 23:34:43 -0600 Subject: [PATCH 174/214] Select CMAKE_BUILD_TYPE if not specified A suggestion by kcat to ensure CMake selects a reasonable default for the build type if users don't set it themselves. --- CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 37f8552cdd..c8682dace6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,12 @@ project(OpenMW) +# If the user doesn't supply a CMAKE_BUILD_TYPE via command line, choose one for them. +IF(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING + "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." + FORCE) +ENDIF() + if (APPLE) set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app") From 0e955124003b29f1fc201cc946bdf4763d13cb9f Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sun, 15 Feb 2015 16:02:49 +0200 Subject: [PATCH 175/214] CI: fix `make package` condition by adding missing spaces --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 042d4b8f1a..1be8aa59cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ before_script: script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -j4; fi - - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "osx"]; then make package; 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 notifications: From a9b74671a6c7a8aea6f575313e9696886c2b3574 Mon Sep 17 00:00:00 2001 From: slothlife Date: Sun, 15 Feb 2015 20:10:21 -0600 Subject: [PATCH 176/214] Fix various MSVC warnings --- CMakeLists.txt | 13 ++++++++++--- apps/openmw/mwmechanics/magiceffects.hpp | 2 ++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a117d42d3..0c3d7c3783 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -672,6 +672,7 @@ if (WIN32) 4193 # #pragma warning(pop) : no matching '#pragma warning(push)' 4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY' 4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY' + 4315 # undocumented, 'this' pointer for member might not be aligned (OgreMemoryStlAllocator.h) # caused by boost 4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off) @@ -679,6 +680,7 @@ if (WIN32) # OpenMW specific warnings 4099 # Type mismatch, declared class or struct is defined with other type 4100 # Unreferenced formal parameter (-Wunused-parameter) + 4101 # Unreferenced local variable (-Wunused-variable) 4127 # Conditional expression is constant 4242 # Storing value in a variable of a smaller type, possible loss of data 4244 # Storing value of one type in variable of another (size_t in int, for example) @@ -700,14 +702,16 @@ if (WIN32) # boost::wave has a few issues with signed / unsigned conversions, so we suppress those here set(SHINY_WARNINGS "${WARNINGS} /wd4245") set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}") - # there's an unreferenced local variable in the ogre platform, suppress it - set(SHINY_OGRE_WARNINGS "${WARNINGS} /wd4101") - set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS "${SHINY_OGRE_WARNINGS} ${MT_BUILD}") + set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") # oics uses tinyxml, which has an initialized but unused variable set(OICS_WARNINGS "${WARNINGS} /wd4189") set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}") set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + set_target_properties(ogre-ffmpeg-videoplayer PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + if (BUILD_MYGUI_PLUGIN) + set_target_properties(Plugin_MyGUI_OpenMW_Resources PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif (BUILD_MYGUI_PLUGIN) if (BUILD_LAUNCHER) set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") endif (BUILD_LAUNCHER) @@ -726,6 +730,9 @@ if (WIN32) set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435") set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS}) endif (BUILD_OPENCS) + if (BUILD_ESSIMPORTER) + set_target_properties(openmw-essimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + endif (BUILD_ESSIMPORTER) if (BUILD_MWINIIMPORTER) set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") endif (BUILD_MWINIIMPORTER) diff --git a/apps/openmw/mwmechanics/magiceffects.hpp b/apps/openmw/mwmechanics/magiceffects.hpp index c384d0857f..86f5a1804a 100644 --- a/apps/openmw/mwmechanics/magiceffects.hpp +++ b/apps/openmw/mwmechanics/magiceffects.hpp @@ -72,6 +72,8 @@ namespace MWMechanics // Used by effect management classes (ActiveSpells, InventoryStore, Spells) to list active effect sources for GUI display struct EffectSourceVisitor { + virtual ~EffectSourceVisitor() { } + virtual void visit (MWMechanics::EffectKey key, const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1) = 0; From e5c1c316480c3d5f7daa1ca3010004a7a21a37ef Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 16 Feb 2015 14:27:25 +1100 Subject: [PATCH 177/214] Ignore case when detecting legacy extensions (.esm or .exp). Should resolve bug #2227. --- apps/opencs/view/doc/adjusterwidget.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 09e58690fc..6571ad7c81 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -72,8 +73,11 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) { boost::filesystem::path path (name.toUtf8().data()); - bool isLegacyPath = (path.extension() == ".esm" || - path.extension() == ".esp"); + std::string extension = path.extension().string(); + boost::algorithm::to_lower(extension); + + bool isLegacyPath = (extension == ".esm" || + extension == ".esp"); bool isFilePathChanged = (path.parent_path().string() != mLocalData.string()); From efdee1947765bb796bda5182e6cd193c03d90377 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 16 Feb 2015 16:41:53 +1100 Subject: [PATCH 178/214] Suppress warning about the lack of virtual destructor. --- apps/openmw/mwmechanics/summoning.cpp | 4 ++++ apps/openmw/mwmechanics/summoning.hpp | 1 + 2 files changed, 5 insertions(+) diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index ec9bd0ea01..668031141c 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -51,6 +51,10 @@ namespace MWMechanics } + UpdateSummonedCreatures::~UpdateSummonedCreatures() + { + } + void UpdateSummonedCreatures::visit(EffectKey key, const std::string &sourceName, const std::string &sourceId, int casterActorId, float magnitude, float remainingTime, float totalTime) { if (isSummoningEffect(key.mId) && magnitude > 0) diff --git a/apps/openmw/mwmechanics/summoning.hpp b/apps/openmw/mwmechanics/summoning.hpp index b8fe377838..8e418cdeb4 100644 --- a/apps/openmw/mwmechanics/summoning.hpp +++ b/apps/openmw/mwmechanics/summoning.hpp @@ -14,6 +14,7 @@ namespace MWMechanics struct UpdateSummonedCreatures : public EffectSourceVisitor { UpdateSummonedCreatures(const MWWorld::Ptr& actor); + virtual ~UpdateSummonedCreatures(); virtual void visit (MWMechanics::EffectKey key, const std::string& sourceName, const std::string& sourceId, int casterActorId, From 8d7de7d1ece744356fee88f7e8613089725fcd67 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 17 Feb 2015 22:14:25 +1300 Subject: [PATCH 179/214] Telekinesis allows safe opening of traps (Fixes #1916) When trap activated at beyond normal activation distance, assume telekinesis used and detonate trap at trapped object's location. Also some minor code refactoring of spellcasting. 1. Corrected parameter passed to explodeSpell(). 2. For loop now correctly does an early exit. 3. Removed duplicated tests. --- apps/openmw/mwbase/world.hpp | 4 +++- apps/openmw/mwmechanics/spellcasting.cpp | 16 ++++++------- apps/openmw/mwworld/actiontrap.cpp | 29 +++++++++++++++++++++--- apps/openmw/mwworld/worldimp.cpp | 4 ++-- apps/openmw/mwworld/worldimp.hpp | 2 +- 5 files changed, 39 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f58ef08095..f719754337 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -269,6 +269,8 @@ namespace MWBase virtual MWWorld::Ptr getFacedObject() = 0; ///< Return pointer to the object the player is looking at, if it is within activation range + virtual float getMaxActivationDistance() = 0; + /// Returns a pointer to the object the provided object would hit (if within the /// specified distance), and the point where the hit occurs. This will attempt to /// use the "Head" node, or alternatively the "Bip01 Head" node as a basis. @@ -548,7 +550,7 @@ namespace MWBase virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos) = 0; virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName) = 0; + const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0; virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 49887e560f..4ce3fcaf5a 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -309,9 +309,11 @@ namespace MWMechanics for (std::vector::const_iterator iter (effects.mList.begin()); iter!=effects.mList.end(); ++iter) { - if (iter->mRange != range) - continue; - found = true; + if (iter->mRange == range) + { + found = true; + break; + } } if (!found) return; @@ -766,8 +768,7 @@ namespace MWMechanics if (!mTarget.isEmpty()) { - if (!mTarget.getClass().isActor() || !mTarget.getClass().getCreatureStats(mTarget).isDead()) - inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch); + inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch); } std::string projectileModel; @@ -851,10 +852,7 @@ namespace MWMechanics if (!mTarget.isEmpty()) { - if (!mTarget.getClass().isActor() || !mTarget.getClass().getCreatureStats(mTarget).isDead()) - { - inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch); - } + inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch); } diff --git a/apps/openmw/mwworld/actiontrap.cpp b/apps/openmw/mwworld/actiontrap.cpp index 1472afc087..d153b7e618 100644 --- a/apps/openmw/mwworld/actiontrap.cpp +++ b/apps/openmw/mwworld/actiontrap.cpp @@ -1,16 +1,39 @@ #include "actiontrap.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" namespace MWWorld { void ActionTrap::executeImp(const Ptr &actor) { - MWMechanics::CastSpell cast(mTrapSource, actor); - cast.mHitPosition = Ogre::Vector3(actor.getRefData().getPosition().pos); - cast.cast(mSpellId); + Ogre::Vector3 actorPosition(actor.getRefData().getPosition().pos); + Ogre::Vector3 trapPosition(mTrapSource.getRefData().getPosition().pos); + float activationDistance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); + // GUI calcs if object in activation distance include object and player geometry + const float fudgeFactor = 1.25f; + + // Hack: if actor is beyond activation range, then assume actor is using telekinesis + // to open door/container. + // Note, can't just detonate the trap at the trapped object's location and use the blast + // radius, because for most trap spells this is 1 foot, much less than the activation distance. + if (trapPosition.distance(actorPosition) < (activationDistance * fudgeFactor)) + { + // assume actor touched trap + MWMechanics::CastSpell cast(mTrapSource, actor); + cast.mHitPosition = actorPosition; + cast.cast(mSpellId); + } + else + { + // assume telekinesis used + MWMechanics::CastSpell cast(mTrapSource, mTrapSource); + cast.mHitPosition = trapPosition; + cast.cast(mSpellId); + } mTrapSource.getCellRef().setTrap(""); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8bcfcb4211..333f172b91 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3128,7 +3128,7 @@ namespace MWWorld mRendering->spawnEffect(model, textureOverride, worldPos); } - void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, int rangeType, + void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) { std::map > toApply; @@ -3187,7 +3187,7 @@ namespace MWWorld cast.mStack = false; ESM::EffectList effects; effects.mList = apply->second; - cast.inflict(apply->first, caster, effects, (ESM::RangeType)rangeType, false, true); + cast.inflict(apply->first, caster, effects, rangeType, false, true); } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9834015ac6..84da984f85 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -627,7 +627,7 @@ namespace MWWorld virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos); virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName); + const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName); virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor); From 6e2d6a028200df830b2ca90c95987f873e7c5199 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 17 Feb 2015 22:51:30 +1300 Subject: [PATCH 180/214] Minor correction, MWWorld::getMaxActivationDistance() is now public. --- apps/openmw/mwworld/worldimp.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 84da984f85..1636980cb6 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -114,7 +114,6 @@ namespace MWWorld void performUpdateSceneQueries (); void getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer=true); - float getMaxActivationDistance (); float getNpcActivationDistance (); float getObjectActivationDistance (); @@ -361,6 +360,8 @@ namespace MWWorld virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos); ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. + virtual float getMaxActivationDistance(); + virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) const; ///< Convert cell numbers to position. From 6d62aa754445931fad3d7e5bc7389f8b6e6ccc36 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Feb 2015 19:06:36 +0100 Subject: [PATCH 181/214] Don't prompt for spell deletion when using cycling keys (Fixes #2382) --- apps/openmw/mwgui/spellwindow.cpp | 71 +++++++++++++++++-------------- apps/openmw/mwgui/spellwindow.hpp | 1 + 2 files changed, 39 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 69365c1081..cc032691e2 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -102,6 +102,31 @@ namespace MWGui updateSpells(); } + void SpellWindow::askDeleteSpell(const std::string &spellId) + { + // delete spell, if allowed + const ESM::Spell* spell = + MWBase::Environment::get().getWorld()->getStore().get().find(spellId); + + if (spell->mData.mFlags & ESM::Spell::F_Always + || spell->mData.mType == ESM::Spell::ST_Power) + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}"); + } + else + { + // ask for confirmation + mSpellToDelete = spellId; + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); + std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); + question = boost::str(boost::format(question) % spell->mName); + dialog->open(question); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept); + dialog->eventCancelClicked.clear(); + } + } + void SpellWindow::onModelIndexSelected(SpellModel::ModelIndex index) { const Spell& spell = mSpellView->getModel()->getItem(index); @@ -111,43 +136,19 @@ namespace MWGui } else { - onSpellSelected(spell.mId); + if (MyGUI::InputManager::getInstance().isShiftPressed()) + askDeleteSpell(spell.mId); + else + onSpellSelected(spell.mId); } } void SpellWindow::onSpellSelected(const std::string& spellId) { - if (MyGUI::InputManager::getInstance().isShiftPressed()) - { - // delete spell, if allowed - const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - - if (spell->mData.mFlags & ESM::Spell::F_Always - || spell->mData.mType == ESM::Spell::ST_Power) - { - MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}"); - } - else - { - // ask for confirmation - mSpellToDelete = spellId; - ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); - question = boost::str(boost::format(question) % spell->mName); - dialog->open(question); - dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept); - dialog->eventCancelClicked.clear(); - } - } - else - { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); - store.setSelectedEnchantItem(store.end()); - MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); - } + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); + store.setSelectedEnchantItem(store.end()); + MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); updateSpells(); } @@ -184,6 +185,10 @@ namespace MWGui return; selected = (selected + itemcount) % itemcount; - onModelIndexSelected(selected); + const Spell& spell = mSpellView->getModel()->getItem(selected); + if (spell.mType == Spell::Type_EnchantedItem) + onEnchantedItemSelected(spell.mItem, spell.mActive); + else + onSpellSelected(spell.mId); } } diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index 650218d307..8b5474f58c 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -33,6 +33,7 @@ namespace MWGui void onSpellSelected(const std::string& spellId); void onModelIndexSelected(SpellModel::ModelIndex index); void onDeleteSpellAccept(); + void askDeleteSpell(const std::string& spellId); virtual void onPinToggled(); virtual void onTitleDoubleClicked(); From a5847afdac83fb28e0c22fa3388ca49b077adaf9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 20 Feb 2015 00:00:13 +0100 Subject: [PATCH 182/214] Fix ignored clicks on HUD mini-map (Fixes #2388) --- apps/openmw/mwgui/hud.cpp | 10 ++++++++++ apps/openmw/mwgui/hud.hpp | 4 ++++ files/mygui/openmw_hud.layout | 3 ++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 1f7ead6f56..a4e67e9b14 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -671,4 +671,14 @@ namespace MWGui mEnemyHealthTimer = -1; } + void HUD::customMarkerCreated(MyGUI::Widget *marker) + { + marker->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); + } + + void HUD::doorMarkerCreated(MyGUI::Widget *marker) + { + marker->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); + } + } diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 41a535a089..263c087740 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -119,6 +119,10 @@ namespace MWGui void onMagicClicked(MyGUI::Widget* _sender); void onMapClicked(MyGUI::Widget* _sender); + // LocalMapBase + virtual void customMarkerCreated(MyGUI::Widget* marker); + virtual void doorMarkerCreated(MyGUI::Widget* marker); + void updateEnemyHealthBar(); void updatePositions(); diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 84fd9d247b..8334e34b96 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -112,7 +112,8 @@
- + + From accc078e0efa55538eb1dad341acdff4843498c0 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 22 Feb 2015 08:46:12 +1300 Subject: [PATCH 183/214] Morrowind.ini import progress bar. (Fixes #2344) 1. Show a "bouncing ball" Progress bar when importing from morrowind.ini. 2. Removed dialog that asks for content list name when import game files from morrowind.ini. Instead, name is time stamp. 3. Removed commented out code. 4. Additional bugfix. No longer create a empty content list when OpenMW.cfg has no content files. --- apps/launcher/maindialog.cpp | 18 +-------- apps/launcher/settingspage.cpp | 55 ++++++++++++++------------ apps/launcher/settingspage.hpp | 4 +- components/config/launchersettings.cpp | 6 +++ files/ui/settingspage.ui | 7 ++++ 5 files changed, 47 insertions(+), 43 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index b93d55c176..e4aa3e526a 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -238,24 +238,8 @@ void Launcher::MainDialog::changePage(QListWidgetItem *current, QListWidgetItem current = previous; int currentIndex = iconWidget->row(current); -// int previousIndex = iconWidget->row(previous); - pagesWidget->setCurrentIndex(currentIndex); - - // DataFilesPage *previousPage = dynamic_cast(pagesWidget->widget(previousIndex)); - // DataFilesPage *currentPage = dynamic_cast(pagesWidget->widget(currentIndex)); - - // //special call to update/save data files page list view when it's displayed/hidden. - // if (previousPage) - // { - // if (previousPage->objectName() == "DataFilesPage") - // previousPage->saveSettings(); - // } - // else if (currentPage) - // { - // if (currentPage->objectName() == "DataFilesPage") - // currentPage->loadSettings(); - // } + mSettingsPage->resetProgressBar(); } bool Launcher::MainDialog::setupLauncherSettings() diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index c172a31210..a1f6fb0c2a 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -39,6 +40,7 @@ Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager &cfg, mWizardInvoker = new ProcessInvoker(); mImporterInvoker = new ProcessInvoker(); + resetProgressBar(); connect(mWizardInvoker->getProcess(), SIGNAL(started()), this, SLOT(wizardStarted())); @@ -141,8 +143,13 @@ void Launcher::SettingsPage::on_importerButton_clicked() qDebug() << "arguments " << arguments; + // start the progress bar as a "bouncing ball" + progressBar->setMaximum(0); + progressBar->setValue(0); if (!mImporterInvoker->startProcess(QLatin1String("openmw-iniimporter"), arguments, false)) - return; + { + resetProgressBar(); + } } void Launcher::SettingsPage::on_browseButton_clicked() @@ -197,38 +204,36 @@ void Launcher::SettingsPage::importerStarted() void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus exitStatus) { if (exitCode != 0 || exitStatus == QProcess::CrashExit) - return; - - // Importer may have changed settings, so refresh - mMain->reloadSettings(); - - // Import selected data files from openmw.cfg - if (addonsCheckBox->isChecked()) { - // Because we've reloaded settings, the current content list matches content in OpenMW.cfg - QString oldContentListName = mLauncherSettings.getCurrentContentListName(); - if (mProfileDialog->exec() == QDialog::Accepted) - { - // remove the current content list to prevent duplication - //... except, not allowed to delete the Default content list - if (oldContentListName.compare(DataFilesPage::mDefaultContentListName) != 0) - { - mLauncherSettings.removeContentList(oldContentListName); - } + resetProgressBar(); - const QString newContentListName(mProfileDialog->lineEdit()->text()); - const QStringList files(mGameSettings.getContentList()); - mLauncherSettings.setCurrentContentListName(newContentListName); - mLauncherSettings.setContentList(newContentListName, files); + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Importer finished")); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setText(tr("Failed to import settings from INI file.")); + msgBox.exec(); + } + else + { + // indicate progress finished + progressBar->setMaximum(1); + progressBar->setValue(1); - // Make DataFiles Page load the new content list. - mMain->reloadSettings(); - } + // Importer may have changed settings, so refresh + mMain->reloadSettings(); } importerButton->setEnabled(true); } +void Launcher::SettingsPage::resetProgressBar() +{ + // set progress bar to 0 % + progressBar->setMaximum(1); + progressBar->setValue(0); +} + void Launcher::SettingsPage::updateOkButton(const QString &text) { // We do this here because we need to access the profiles diff --git a/apps/launcher/settingspage.hpp b/apps/launcher/settingspage.hpp index 124c806009..ccc2061dd7 100644 --- a/apps/launcher/settingspage.hpp +++ b/apps/launcher/settingspage.hpp @@ -29,6 +29,9 @@ namespace Launcher void saveSettings(); bool loadSettings(); + + /// set progress bar on page to 0% + void resetProgressBar(); private slots: @@ -57,7 +60,6 @@ namespace Launcher MainDialog *mMain; TextInputDialog *mProfileDialog; - }; } diff --git a/components/config/launchersettings.cpp b/components/config/launchersettings.cpp index 66f05f691c..1d4b428c91 100644 --- a/components/config/launchersettings.cpp +++ b/components/config/launchersettings.cpp @@ -105,6 +105,12 @@ void Config::LauncherSettings::setContentList(const GameSettings& gameSettings) // obtain content list from game settings (if present) const QStringList files(gameSettings.getContentList()); + // if openmw.cfg has no content, exit so we don't create an empty content list. + if (files.isEmpty()) + { + return; + } + // if any existing profile in launcher matches the content list, make that profile the default foreach(const QString &listName, getContentLists()) { diff --git a/files/ui/settingspage.ui b/files/ui/settingspage.ui index 6c873ea926..7f5e4a7de8 100644 --- a/files/ui/settingspage.ui +++ b/files/ui/settingspage.ui @@ -131,6 +131,13 @@
+ + + + 4 + + + From 9708e8529fd4253bf34ee3243a68e562efd39368 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 22 Feb 2015 08:58:17 +1300 Subject: [PATCH 184/214] Removed unneeded include. --- apps/launcher/settingspage.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index a1f6fb0c2a..5b26b01b9a 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include From 514fba5f733f296d995fb6fd6004addd7c20fedc Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 22 Feb 2015 10:02:25 +1300 Subject: [PATCH 185/214] On Windows content list imported from morrowind.ini is sorted by file modified time stamps. --- apps/mwiniimporter/importer.cpp | 42 +++++++++++++++++++++++++-------- apps/mwiniimporter/importer.hpp | 12 +++++++--- apps/mwiniimporter/main.cpp | 6 ++--- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 80f186b1f4..6b8424da6f 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include namespace bfs = boost::filesystem; @@ -660,7 +660,7 @@ std::string MwIniImporter::numberToString(int n) { return str.str(); } -MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filename) const { +MwIniImporter::multistrmap MwIniImporter::loadIniFile(const boost::filesystem::path& filename) const { std::cout << "load ini file: " << filename << std::endl; std::string section(""); @@ -719,7 +719,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam return map; } -MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::string& filename) { +MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const boost::filesystem::path& filename) { std::cout << "load cfg file: " << filename << std::endl; MwIniImporter::multistrmap map; @@ -825,10 +825,14 @@ void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) con } } -void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) const { - std::vector contentFiles; +void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, const boost::filesystem::path& iniFilename) const { + std::vector > contentFiles; std::string baseGameFile("Game Files:GameFile"); std::string gameFile(""); + std::time_t defaultTime = 0; + + // assume the Game Files are all in a "Data Files" directory under the directory holding Morrowind.ini + const boost::filesystem::path gameFilesDir(iniFilename.parent_path() /= "Data Files"); multistrmap::const_iterator it = ini.begin(); for(int i=0; it != ini.end(); i++) { @@ -845,18 +849,20 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) co Misc::StringUtils::toLower(filetype); if(filetype.compare("esm") == 0 || filetype.compare("esp") == 0) { - contentFiles.push_back(*entry); + boost::filesystem::path filepath(gameFilesDir); + filepath /= *entry; + contentFiles.push_back(std::make_pair(lastWriteTime(filepath, defaultTime), *entry)); } } - - gameFile = ""; } cfg.erase("content"); cfg.insert( std::make_pair("content", std::vector() ) ); - for(std::vector::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) { - cfg["content"].push_back(*it); + // this will sort files by time order first, then alphabetical (maybe), I suspect non ASCII filenames will be stuffed. + sort(contentFiles.begin(), contentFiles.end()); + for(std::vector >::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) { + cfg["content"].push_back(it->second); } } @@ -873,3 +879,19 @@ void MwIniImporter::setInputEncoding(const ToUTF8::FromType &encoding) { mEncoding = encoding; } + +std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime) +{ + std::time_t writeTime(defaultTime); + if (boost::filesystem::exists(filename)) + { + writeTime = boost::filesystem::last_write_time(filename); + std::cout << "content file: " << filename << " timestamp = (" << writeTime << + ") " << asctime(localtime(&writeTime)) << std::endl; + } + else + { + std::cout << "content file: " << filename << " not found" << std::endl; + } + return writeTime; +} \ No newline at end of file diff --git a/apps/mwiniimporter/importer.hpp b/apps/mwiniimporter/importer.hpp index 72b14ba75f..c73cc65b5e 100644 --- a/apps/mwiniimporter/importer.hpp +++ b/apps/mwiniimporter/importer.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -17,17 +18,22 @@ class MwIniImporter { MwIniImporter(); void setInputEncoding(const ToUTF8::FromType& encoding); void setVerbose(bool verbose); - multistrmap loadIniFile(const std::string& filename) const; - static multistrmap loadCfgFile(const std::string& filename); + multistrmap loadIniFile(const boost::filesystem::path& filename) const; + static multistrmap loadCfgFile(const boost::filesystem::path& filename); void merge(multistrmap &cfg, const multistrmap &ini) const; void mergeFallback(multistrmap &cfg, const multistrmap &ini) const; - void importGameFiles(multistrmap &cfg, const multistrmap &ini) const; + void importGameFiles(multistrmap &cfg, const multistrmap &ini, + const boost::filesystem::path& iniFilename) const; void importArchives(multistrmap &cfg, const multistrmap &ini) const; static void writeToFile(std::ostream &out, const multistrmap &cfg); private: static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value); static std::string numberToString(int n); + + /// \return file's "last modified time", used in original MW to determine plug-in load order + static std::time_t lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime); + bool mVerbose; strmap mMergeMap; std::vector mMergeFallback; diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index f108678f3f..3c48fedc9a 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -93,8 +93,8 @@ int wmain(int argc, wchar_t *wargv[]) { bpo::notify(vm); - std::string iniFile = vm["ini"].as(); - std::string cfgFile = vm["cfg"].as(); + boost::filesystem::path iniFile(vm["ini"].as()); + boost::filesystem::path cfgFile(vm["cfg"].as()); // if no output is given, write back to cfg file std::string outputFile(vm["output"].as()); @@ -123,7 +123,7 @@ int wmain(int argc, wchar_t *wargv[]) { importer.mergeFallback(cfg, ini); if(vm.count("game-files")) { - importer.importGameFiles(cfg, ini); + importer.importGameFiles(cfg, ini, iniFile); } if(!vm.count("no-archives")) { From 5eadffd0c49c045eb5bca39a02f4bce311420833 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Feb 2015 00:13:03 +0100 Subject: [PATCH 186/214] Make launcher's version label selectable so it can be copy-pasted into issue reports --- apps/launcher/maindialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index b93d55c176..64cd034cb4 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -61,6 +61,7 @@ Launcher::MainDialog::MainDialog(QWidget *parent) QString revision(OPENMW_VERSION_COMMITHASH); QString tag(OPENMW_VERSION_TAGHASH); + versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); if (!revision.isEmpty() && !tag.isEmpty()) { if (revision == tag) { From c21b59ecff764b774a3db95778c6434c04e0f8d5 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sat, 21 Feb 2015 15:55:22 -0600 Subject: [PATCH 187/214] Teleportation: Avoid marking searched cells as changed. OMW Bug #1533 Only mark cells with the target marker / evidence chest as 'changed'. --- apps/openmw/mwworld/cellstore.hpp | 11 +++++++++++ apps/openmw/mwworld/worldimp.cpp | 33 ++++++++----------------------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index f6f2a3b489..1d4e995322 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -184,6 +184,11 @@ namespace MWWorld throw std::runtime_error ("Storage for this type not exist in cells"); } + template + CellRefList& getReadOnly() { + throw std::runtime_error ("Read Only access not available for this type"); + } + bool isPointConnected(const int start, const int end) const; std::list aStarSearch(const int start, const int end) const; @@ -357,6 +362,12 @@ namespace MWWorld return mWeapons; } + template<> + inline CellRefList& CellStore::getReadOnly() + { + return mDoors; + } + bool operator== (const CellStore& left, const CellStore& right); bool operator!= (const CellStore& left, const CellStore& right); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 54385cf83f..dd730b32ad 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2799,7 +2799,7 @@ namespace MWWorld MWWorld::CellStore *next = getInterior( *i ); if ( !next ) continue; - MWWorld::CellRefList& doors = next->get(); + MWWorld::CellRefList& doors = next->getReadOnly(); CellRefList::List& refList = doors.mList; // Check if any door in the cell leads to an exterior directly @@ -2838,6 +2838,8 @@ namespace MWWorld std::set< std::string >checkedCells; std::set< std::string >currentCells; std::set< std::string >nextCells; + MWWorld::Ptr closestMarker; + nextCells.insert( ptr.getCell()->getCell()->mName ); while ( !nextCells.empty() ) { currentCells = nextCells; @@ -2847,17 +2849,13 @@ namespace MWWorld checkedCells.insert( *i ); if ( !next ) continue; - MWWorld::CellRefList& statics = next->get(); - CellRefList::List& staticList = statics.mList; - for (CellRefList::List::iterator it = staticList.begin(); it != staticList.end(); ++it) + closestMarker = next->search( id ); + if ( !closestMarker.isEmpty() ) { - MWWorld::LiveCellRef& ref = *it; - if ( id == ref.mRef.getRefId() ) { - return MWWorld::Ptr( &ref, next ); - } + return closestMarker; } - MWWorld::CellRefList& doors = next->get(); + MWWorld::CellRefList& doors = next->getReadOnly(); CellRefList::List& doorList = doors.mList; // Check if any door in the cell leads to an exterior directly @@ -2865,10 +2863,6 @@ namespace MWWorld { MWWorld::LiveCellRef& ref = *it; - if ( id == ref.mRef.getRefId() ) { - return MWWorld::Ptr( &ref, next ); - } - if (!ref.mRef.getTeleport()) continue; if (ref.mRef.getDestCell().empty()) @@ -3085,18 +3079,7 @@ namespace MWWorld return; } - MWWorld::Ptr closestChest; - - MWWorld::CellRefList& containers = prison->get(); - CellRefList::List& refList = containers.mList; - for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) - { - MWWorld::LiveCellRef& ref = *it; - if ( ref.mRef.getRefId() == "stolen_goods" ) { - closestChest = MWWorld::Ptr( &ref, prison ); - } - } - + MWWorld::Ptr closestChest = prison->search( "stolen_goods" ); if (!closestChest.isEmpty()) //Found a close chest { MWBase::Environment::get().getMechanicsManager()->confiscateStolenItems(ptr, closestChest); From f6128a85b2531806e2ef01b6d0c6f5ffd68ec6f5 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 22 Feb 2015 13:48:44 +1300 Subject: [PATCH 188/214] resolve symlinks when searching for file's last modified time. --- apps/mwiniimporter/importer.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 6b8424da6f..b71ebd2b8e 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -883,15 +883,16 @@ void MwIniImporter::setInputEncoding(const ToUTF8::FromType &encoding) std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime) { std::time_t writeTime(defaultTime); - if (boost::filesystem::exists(filename)) + boost::filesystem::path resolved = boost::filesystem::canonical(filename); + if (boost::filesystem::exists(resolved)) { - writeTime = boost::filesystem::last_write_time(filename); - std::cout << "content file: " << filename << " timestamp = (" << writeTime << + writeTime = boost::filesystem::last_write_time(resolved); + std::cout << "content file: " << resolved << " timestamp = (" << writeTime << ") " << asctime(localtime(&writeTime)) << std::endl; } else { - std::cout << "content file: " << filename << " not found" << std::endl; + std::cout << "content file: " << resolved << " not found" << std::endl; } return writeTime; } \ No newline at end of file From 387969bf4250f95c9cffd5d5ccd8ae8a5b5a55bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Feb 2015 18:05:46 +0100 Subject: [PATCH 189/214] Remove an old .gitignore --- components/nif/.gitignore | 1 - 1 file changed, 1 deletion(-) delete mode 100644 components/nif/.gitignore diff --git a/components/nif/.gitignore b/components/nif/.gitignore deleted file mode 100644 index 731498d9a1..0000000000 --- a/components/nif/.gitignore +++ /dev/null @@ -1 +0,0 @@ -old_d From 399259a95cb1632ec1f183602c4dc77564786308 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sun, 22 Feb 2015 12:12:54 -0600 Subject: [PATCH 190/214] Improve CellStore exception messages. --- apps/openmw/mwworld/cellstore.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 1d4e995322..cd7af5ad64 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include "livecellref.hpp" @@ -181,12 +183,12 @@ namespace MWWorld template CellRefList& get() { - throw std::runtime_error ("Storage for this type not exist in cells"); + throw std::runtime_error ("Storage for type " + std::string(typeid(T).name())+ " does not exist in cells"); } template CellRefList& getReadOnly() { - throw std::runtime_error ("Read Only access not available for this type"); + throw std::runtime_error ("Read Only CellRefList access not available for type " + std::string(typeid(T).name()) ); } bool isPointConnected(const int start, const int end) const; From 5edafc2a4cf50afb0ef083df70ae245779219697 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Sun, 22 Feb 2015 12:25:10 -0600 Subject: [PATCH 191/214] Cleanup: Add const to read-only CellRefList access. OMW Bug #1533 --- apps/openmw/mwworld/cellstore.hpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index cd7af5ad64..d7036d6b19 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -187,7 +187,7 @@ namespace MWWorld } template - CellRefList& getReadOnly() { + const CellRefList& getReadOnly() { throw std::runtime_error ("Read Only CellRefList access not available for type " + std::string(typeid(T).name()) ); } @@ -365,7 +365,7 @@ namespace MWWorld } template<> - inline CellRefList& CellStore::getReadOnly() + inline const CellRefList& CellStore::getReadOnly() { return mDoors; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index dd730b32ad..5f42a53798 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2799,13 +2799,13 @@ namespace MWWorld MWWorld::CellStore *next = getInterior( *i ); if ( !next ) continue; - MWWorld::CellRefList& doors = next->getReadOnly(); - CellRefList::List& refList = doors.mList; + const MWWorld::CellRefList& doors = next->getReadOnly(); + const CellRefList::List& refList = doors.mList; // Check if any door in the cell leads to an exterior directly - for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) + for (CellRefList::List::const_iterator it = refList.begin(); it != refList.end(); ++it) { - MWWorld::LiveCellRef& ref = *it; + const MWWorld::LiveCellRef& ref = *it; if (!ref.mRef.getTeleport()) continue; if (ref.mRef.getDestCell().empty()) @@ -2855,13 +2855,13 @@ namespace MWWorld return closestMarker; } - MWWorld::CellRefList& doors = next->getReadOnly(); - CellRefList::List& doorList = doors.mList; + const MWWorld::CellRefList& doors = next->getReadOnly(); + const CellRefList::List& doorList = doors.mList; // Check if any door in the cell leads to an exterior directly - for (CellRefList::List::iterator it = doorList.begin(); it != doorList.end(); ++it) + for (CellRefList::List::const_iterator it = doorList.begin(); it != doorList.end(); ++it) { - MWWorld::LiveCellRef& ref = *it; + const MWWorld::LiveCellRef& ref = *it; if (!ref.mRef.getTeleport()) continue; From 68f89318e755d55e8e51bc3bdf079682cf2283fa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 22 Feb 2015 20:56:47 +0100 Subject: [PATCH 192/214] Fix canvas align in skill view --- files/mygui/openmw_stats_window.layout | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/files/mygui/openmw_stats_window.layout b/files/mygui/openmw_stats_window.layout index 11119c4044..1d9b75b9be 100644 --- a/files/mygui/openmw_stats_window.layout +++ b/files/mygui/openmw_stats_window.layout @@ -235,7 +235,9 @@ - + + + From 47c053444f2ed3011372cdd385601020975d6475 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Mon, 23 Feb 2015 00:23:09 +0100 Subject: [PATCH 193/214] Make the jail progress last one second --- apps/openmw/mwgui/jailscreen.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 548b1b604c..58873c5660 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -17,7 +17,7 @@ namespace MWGui { JailScreen::JailScreen() : WindowBase("openmw_jail_screen.layout"), - mTimeAdvancer(0.0125), + mTimeAdvancer(0.01), mDays(1), mFadeTimeRemaining(0) { @@ -39,7 +39,7 @@ namespace MWGui mFadeTimeRemaining = 0.5; setVisible(false); - mProgressBar->setScrollRange(days*24+1); + mProgressBar->setScrollRange(100+1); mProgressBar->setScrollPosition(0); mProgressBar->setTrackSize(0); } @@ -59,7 +59,7 @@ namespace MWGui MWBase::Environment::get().getWorld()->teleportToClosestMarker(player, "prisonmarker"); setVisible(true); - mTimeAdvancer.run(mDays*24); + mTimeAdvancer.run(100); } } From 84762c4eb8f49bddbb5947a54cb2321cde86f421 Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 23 Feb 2015 19:30:46 +1300 Subject: [PATCH 194/214] Progress bar at 0% shows no text. --- apps/launcher/settingspage.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 5b26b01b9a..c228aba500 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -229,8 +229,7 @@ void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus void Launcher::SettingsPage::resetProgressBar() { // set progress bar to 0 % - progressBar->setMaximum(1); - progressBar->setValue(0); + progressBar->reset(); } void Launcher::SettingsPage::updateOkButton(const QString &text) From 6dc202cba337416e68a54100ee76931abbbca60e Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 23 Feb 2015 19:41:41 +1300 Subject: [PATCH 195/214] Removed unneeded parameter from ContentModel::setContentList() --- components/contentselector/model/contentmodel.cpp | 4 ++-- components/contentselector/model/contentmodel.hpp | 2 +- components/contentselector/view/contentselector.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index ec1fcc21e4..02a2600228 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -536,13 +536,13 @@ bool ContentSelectorModel::ContentModel::isLoadOrderError(const EsmFile *file) c return mPluginsWithLoadOrderError.contains(file->filePath()); } -void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList, bool isChecked) +void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList) { mPluginsWithLoadOrderError.clear(); int previousPosition = -1; foreach (const QString &filepath, fileList) { - if (setCheckState(filepath, isChecked)) + if (setCheckState(filepath, true)) { // as necessary, move plug-ins in visible list to match sequence of supplied filelist const EsmFile* file = item(filepath); diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 6af5425c77..3d8229aeb4 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -51,7 +51,7 @@ namespace ContentSelectorModel bool isEnabled (QModelIndex index) const; bool isChecked(const QString &filepath) const; bool setCheckState(const QString &filepath, bool isChecked); - void setContentList(const QStringList &fileList, bool isChecked); + void setContentList(const QStringList &fileList); ContentFileList checkedItems() const; void uncheckAll(); diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index ad023e5b22..3aa5ddf80a 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -113,7 +113,7 @@ void ContentSelectorView::ContentSelector::setContentList(const QStringList &lis slotCurrentGameFileIndexChanged (ui.gameFileView->currentIndex()); } else - mContentModel->setContentList(list, true); + mContentModel->setContentList(list); } ContentSelectorModel::ContentFileList From 63af9d848a5ca9dba169ff2cd4c957cdd0957cdd Mon Sep 17 00:00:00 2001 From: dteviot Date: Mon, 23 Feb 2015 19:58:31 +1300 Subject: [PATCH 196/214] Add constraint: Bloodmoon.esm requires Tribunal.esm. --- components/contentselector/model/contentmodel.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 02a2600228..a4fbdcf066 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -467,6 +467,14 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) file->setFilePath (info.absoluteFilePath()); file->setDescription(QString::fromUtf8(fileReader.getDesc().c_str())); + // HACK + // Bloodmoon.esm requires Tribunal.esm, but this requirement is missing + // from the file supplied by Bethesda, so we have to add it ourselves + if (file->fileName().compare("Bloodmoon.esm", Qt::CaseInsensitive) == 0) + { + file->addGameFile(QString::fromUtf8("Tribunal.esm")); + } + // Put the file in the table addFile(file); From 77bb77b367a39bae791449500c212dd39493d227 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 23 Feb 2015 19:07:12 +0100 Subject: [PATCH 197/214] Fix for instant restore effects (Fixes #2392) --- 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 4ce3fcaf5a..105fa58664 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -594,6 +594,7 @@ namespace MWMechanics value.restore(magnitude); target.getClass().getCreatureStats(target).setAttribute(attribute, value); } + // TODO: refactor the effect tick functions in Actors so they can be reused here else if (effectId == ESM::MagicEffect::DamageHealth) { applyDynamicStatsEffect(0, target, magnitude * -1); @@ -683,7 +684,7 @@ namespace MWMechanics void CastSpell::applyDynamicStatsEffect(int attribute, const MWWorld::Ptr& target, float magnitude) { DynamicStat value = target.getClass().getCreatureStats(target).getDynamic(attribute); - value.modify(magnitude); + value.setCurrent(value.getCurrent()+magnitude, attribute == 2); target.getClass().getCreatureStats(target).setDynamic(attribute, value); } From 6878e317a7c9c64ac9916ade1e9864dca5db6815 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 24 Feb 2015 20:06:06 +1300 Subject: [PATCH 198/214] launcher: decouple Combo Box model from Plug-ins model. fixes bug reported by scrawl 1. openmw.cfg had content files in order 'Bloodmoon.esm, Tribunal.esm, Morrowind.esm' 2. Blank_ESM_2.0.esm is in the Data Files directory 3. Do an ini file import. 4. Imported profile will have Blank_ESM_2.0.esm as the game file. Should be Morrowind.esm. Root cause: Game File combo box and Plugins Grid shared same data model, so changing plug-in file order also changed order of Game File combo box. --- .../contentselector/model/contentmodel.cpp | 15 ++++++- .../contentselector/model/contentmodel.hpp | 1 + .../contentselector/view/contentselector.cpp | 42 +++++++++++-------- .../contentselector/view/contentselector.hpp | 2 +- 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index a4fbdcf066..485510df43 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -489,6 +489,19 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) sortFiles(); } +QStringList ContentSelectorModel::ContentModel::gameFiles() const +{ + QStringList gameFiles; + foreach(const ContentSelectorModel::EsmFile *file, mFiles) + { + if (file->isGameFile()) + { + gameFiles.append(file->fileName()); + } + } + return gameFiles; +} + void ContentSelectorModel::ContentModel::sortFiles() { //first, sort the model such that all dependencies are ordered upstream (gamefile) first. @@ -589,7 +602,7 @@ void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() QList ContentSelectorModel::ContentModel::checkForLoadOrderErrors(const EsmFile *file, int row) const { QList errors = QList(); - foreach(QString dependentfileName, file->gameFiles()) + foreach(const QString &dependentfileName, file->gameFiles()) { const EsmFile* dependentFile = item(dependentfileName); diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 3d8229aeb4..6585558520 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -47,6 +47,7 @@ namespace ContentSelectorModel QModelIndex indexFromItem(const EsmFile *item) const; const EsmFile *item(const QString &name) const; + QStringList gameFiles() const; bool isEnabled (QModelIndex index) const; bool isChecked(const QString &filepath) const; diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 3aa5ddf80a..2363ae477a 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) : @@ -33,13 +34,7 @@ void ContentSelectorView::ContentSelector::buildGameFileView() { ui.gameFileView->setVisible (true); - mGameFileProxyModel = new QSortFilterProxyModel(this); - mGameFileProxyModel->setFilterRegExp(QString::number((int)ContentSelectorModel::ContentType_GameFile)); - mGameFileProxyModel->setFilterRole (Qt::UserRole); - mGameFileProxyModel->setSourceModel (mContentModel); - ui.gameFileView->setPlaceholderText(QString("Select a game file...")); - ui.gameFileView->setModel(mGameFileProxyModel); connect (ui.gameFileView, SIGNAL (currentIndexChanged(int)), this, SLOT (slotCurrentGameFileIndexChanged(int))); @@ -129,6 +124,15 @@ void ContentSelectorView::ContentSelector::addFiles(const QString &path) { mContentModel->addFiles(path); + // add any game files to the combo box + foreach(const QString gameFileName, mContentModel->gameFiles()) + { + if (ui.gameFileView->findText(gameFileName) == -1) + { + ui.gameFileView->addItem(gameFileName); + } + } + if (ui.gameFileView->currentIndex() != -1) ui.gameFileView->setCurrentIndex(-1); @@ -150,29 +154,33 @@ void ContentSelectorView::ContentSelector::slotCurrentGameFileIndexChanged(int i { static int oldIndex = -1; - QAbstractItemModel *const model = ui.gameFileView->model(); - QSortFilterProxyModel *proxy = dynamic_cast(model); - - if (proxy) - proxy->setDynamicSortFilter(false); - if (index != oldIndex) { if (oldIndex > -1) - model->setData(model->index(oldIndex, 0), false, Qt::UserRole + 1); + { + setGameFileSelected(oldIndex, false); + } oldIndex = index; - model->setData(model->index(index, 0), true, Qt::UserRole + 1); + setGameFileSelected(index, true); mContentModel->checkForLoadOrderErrors(); } - if (proxy) - proxy->setDynamicSortFilter(true); - emit signalCurrentGamefileIndexChanged (index); } +void ContentSelectorView::ContentSelector::setGameFileSelected(int index, bool selected) +{ + QString fileName = ui.gameFileView->itemText(index); + const ContentSelectorModel::EsmFile* file = mContentModel->item(fileName); + if (file != NULL) + { + QModelIndex index(mContentModel->indexFromItem(file)); + mContentModel->setData(index, selected, Qt::UserRole + 1); + } +} + void ContentSelectorView::ContentSelector::slotAddonTableItemActivated(const QModelIndex &index) { QModelIndex sourceIndex = mAddonProxyModel->mapToSource (index); diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index 8651dac2ef..2507cf6adb 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -19,7 +19,6 @@ namespace ContentSelectorView protected: ContentSelectorModel::ContentModel *mContentModel; - QSortFilterProxyModel *mGameFileProxyModel; QSortFilterProxyModel *mAddonProxyModel; public: @@ -52,6 +51,7 @@ namespace ContentSelectorView void buildContentModel(); void buildGameFileView(); void buildAddonView(); + void setGameFileSelected(int index, bool selected); signals: void signalCurrentGamefileIndexChanged (int); From cc815c63f18407de5ffc684e3282a53479ecf348 Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 24 Feb 2015 20:14:18 +1300 Subject: [PATCH 199/214] Fix: no longer loose changes when run install wizard or iniimport. --- apps/launcher/settingspage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index c228aba500..34b4b41a9e 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -95,7 +95,7 @@ Launcher::SettingsPage::~SettingsPage() void Launcher::SettingsPage::on_wizardButton_clicked() { - saveSettings(); + mMain->writeSettings(); if (!mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false)) return; @@ -103,7 +103,7 @@ void Launcher::SettingsPage::on_wizardButton_clicked() void Launcher::SettingsPage::on_importerButton_clicked() { - saveSettings(); + mMain->writeSettings(); // Create the file if it doesn't already exist, else the importer will fail QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); From e1032620959de5c4d04c87d92cd420000774d084 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 24 Feb 2015 18:15:41 +0100 Subject: [PATCH 200/214] updated credits file --- AUTHORS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index 540c0ede5a..90c543adae 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -39,6 +39,7 @@ Programmers Eli2 Emanuel Guével (potatoesmaster) eroen + Evgeniy Mineev (sandstranger) Fil Krynicki (filkry) Gašper Sedej gugus/gus @@ -91,7 +92,6 @@ Programmers Rohit Nirmal Roman Melnik (Kromgart) Roman Proskuryakov (humbug) - sandstranger Sandy Carter (bwrsandman) Scott Howard Sebastian Wick (swick) From 24de6ba27e06a381a56abdc7913586b75634569e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 24 Feb 2015 17:09:49 +0100 Subject: [PATCH 201/214] Fix crash for LAND records without data --- 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 72d475f169..f03f65b36e 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -230,7 +230,7 @@ namespace MWWorld cell->getCell()->getGridX(), cell->getCell()->getGridY() ); - if (land) { + if (land && land->mDataTypes&ESM::Land::DATA_VHGT) { // 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; From 5672c86924fe8aa9c104e9d0d23714ac1230640a Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 24 Feb 2015 23:37:53 +0100 Subject: [PATCH 202/214] Rename window title for OpenMW-CS --- apps/opencs/view/doc/startup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/startup.cpp b/apps/opencs/view/doc/startup.cpp index 799a07e14b..58a46c603b 100644 --- a/apps/opencs/view/doc/startup.cpp +++ b/apps/opencs/view/doc/startup.cpp @@ -96,7 +96,7 @@ QWidget *CSVDoc::StartupDialogue::createTools() CSVDoc::StartupDialogue::StartupDialogue() : mWidth (0), mColumn (2) { - setWindowTitle ("Open CS"); + setWindowTitle ("OpenMW-CS"); QVBoxLayout *layout = new QVBoxLayout (this); From 691ebd237215e502f8e096a8f5f5b8253fb9275c Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Tue, 24 Feb 2015 20:51:57 -0600 Subject: [PATCH 203/214] Correction to teleportation changes. OMW Bug #2400 Related to OMW Bug #1533 Don't crash when finding the closest marker to an exterior position. --- apps/openmw/mwworld/worldimp.cpp | 47 +++++++++++++++++++------------- apps/openmw/mwworld/worldimp.hpp | 1 + 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6462629f4d..4cafab41d9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2832,6 +2832,10 @@ namespace MWWorld MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) { + if ( ptr.getCell()->isExterior() ) { + return getClosestMarkerFromExteriorPosition(mPlayer->getLastKnownExteriorPosition(), id); + } + // Search for a 'nearest' marker, counting each cell between the starting // cell and the exterior as a distance of 1. If an exterior is found, jump // to the nearest exterior marker, without further interior searching. @@ -2868,25 +2872,7 @@ namespace MWWorld if (ref.mRef.getDestCell().empty()) { Ogre::Vector3 worldPos = Ogre::Vector3(ref.mRef.getDoorDest().pos); - float closestDistance = FLT_MAX; - - MWWorld::Ptr closestMarker; - std::vector markers; - mCells.getExteriorPtrs(id, markers); - for (std::vector::iterator it2 = markers.begin(); it2 != markers.end(); ++it2) - { - ESM::Position pos = it2->getRefData().getPosition(); - Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos); - float distance = worldPos.squaredDistance(markerPos); - if (distance < closestDistance) - { - closestDistance = distance; - closestMarker = *it2; - } - - } - - return closestMarker; + return getClosestMarkerFromExteriorPosition(worldPos, id); } else { @@ -2901,6 +2887,29 @@ namespace MWWorld return MWWorld::Ptr(); } + MWWorld::Ptr World::getClosestMarkerFromExteriorPosition( const Ogre::Vector3 worldPos, const std::string &id ) { + MWWorld::Ptr closestMarker; + float closestDistance = FLT_MAX; + + std::vector markers; + mCells.getExteriorPtrs(id, markers); + for (std::vector::iterator it2 = markers.begin(); it2 != markers.end(); ++it2) + { + ESM::Position pos = it2->getRefData().getPosition(); + Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos); + float distance = worldPos.squaredDistance(markerPos); + if (distance < closestDistance) + { + closestDistance = distance; + closestMarker = *it2; + } + + } + + return closestMarker; + } + + void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, const std::string& id) { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 22509f801f..1db86f7383 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -151,6 +151,7 @@ namespace MWWorld float feetToGameUnits(float feet); MWWorld::Ptr getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ); + MWWorld::Ptr getClosestMarkerFromExteriorPosition( const Ogre::Vector3 worldPos, const std::string &id ); public: From 659a8ba279e1affc6ef954c4cbae9ba76eea92cb Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Tue, 24 Feb 2015 21:10:01 -0600 Subject: [PATCH 204/214] Correction to teleportation changes. OMW Bug #2400 Related to OMW Bug #1533 Don't crash on confiscating items if a prison marker cannot be found. --- apps/openmw/mwworld/worldimp.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4cafab41d9..fe56fc3bb8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3075,6 +3075,11 @@ namespace MWWorld void World::confiscateStolenItems(const Ptr &ptr) { MWWorld::Ptr prisonMarker = getClosestMarker( ptr, "prisonmarker" ); + if ( prisonMarker.isEmpty() ) + { + std::cerr << "Failed to confiscate items: no closest prison marker found." << std::endl; + return; + } std::string prisonName = prisonMarker.mRef->mRef.getDestCell(); if ( prisonName.empty() ) { From 9d61457956e35b56dfbf24e9cab8a532cad61591 Mon Sep 17 00:00:00 2001 From: dteviot Date: Wed, 25 Feb 2015 20:54:52 +1300 Subject: [PATCH 205/214] AddOn files can be checked if game file is checked, but dependencies do not exist. --- .../contentselector/model/contentmodel.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 485510df43..cd0c67ee72 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -110,15 +110,14 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index if (!file) return Qt::NoItemFlags; - //game files can always be checked + //game files are not shown if (file->isGameFile()) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; + return Qt::NoItemFlags; Qt::ItemFlags returnFlags; - bool allDependenciesFound = true; bool gamefileChecked = false; - //addon can be checked if its gamefile is and all other dependencies exist + // addon can be checked if its gamefile is foreach (const QString &fileName, file->gameFiles()) { bool depFound = false; @@ -144,16 +143,11 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index if (gamefileChecked || !(dependency->isGameFile())) break; } - - allDependenciesFound = allDependenciesFound && depFound; } if (gamefileChecked) { - if (allDependenciesFound) - returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled; - else - returnFlags = Qt::ItemIsSelectable; + returnFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled; } return returnFlags; @@ -468,7 +462,7 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) file->setDescription(QString::fromUtf8(fileReader.getDesc().c_str())); // HACK - // Bloodmoon.esm requires Tribunal.esm, but this requirement is missing + // Load order constraint of Bloodmoon.esm needing Tribunal.esm is missing // from the file supplied by Bethesda, so we have to add it ourselves if (file->fileName().compare("Bloodmoon.esm", Qt::CaseInsensitive) == 0) { From 931c95d0b130e07a4f9e8fb2f41c99235607cc41 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 26 Feb 2015 06:17:29 +1300 Subject: [PATCH 206/214] workaround for not building on Linux version of Travis. --- apps/mwiniimporter/importer.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index b71ebd2b8e..00774d7982 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -883,16 +883,23 @@ void MwIniImporter::setInputEncoding(const ToUTF8::FromType &encoding) std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime) { std::time_t writeTime(defaultTime); - boost::filesystem::path resolved = boost::filesystem::canonical(filename); - if (boost::filesystem::exists(resolved)) + if (boost::filesystem::exists(filename)) { + // FixMe: remove #if when Boost on Travis Linux updated + // Travis seems to be using older version of boost for Linux + // This should allow things to build until fixed +#if BOOST_FILESYSTEM_VERSION == 3 + boost::filesystem::path resolved = boost::filesystem::canonical(filename); +#else + boost::filesystem::path resolved = filename; +#endif writeTime = boost::filesystem::last_write_time(resolved); std::cout << "content file: " << resolved << " timestamp = (" << writeTime << ") " << asctime(localtime(&writeTime)) << std::endl; } else { - std::cout << "content file: " << resolved << " not found" << std::endl; + std::cout << "content file: " << filename << " not found" << std::endl; } return writeTime; } \ No newline at end of file From 3158d34abb3da8f6a22a4ea7bbf962eb0ccb51f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Feb 2015 20:25:41 +0100 Subject: [PATCH 207/214] Fix for incorrect OpenCS verifier warning: pcvampire and pcwerewolf are not required, pcyear does not exist at all. --- apps/opencs/model/tools/tools.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 0c20bd17b4..e78758bb67 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -58,9 +58,6 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() mandatoryIds.push_back ("GameHour"); mandatoryIds.push_back ("Month"); mandatoryIds.push_back ("PCRace"); - mandatoryIds.push_back ("PCVampire"); - mandatoryIds.push_back ("PCWerewolf"); - mandatoryIds.push_back ("PCYear"); mVerifier->appendStage (new MandatoryIdStage (mData.getGlobals(), CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds)); From e7989a197d8e3b2d81d7aea63012f575a373ee4c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Feb 2015 20:32:11 +0100 Subject: [PATCH 208/214] Add defaults for some required globals (Fixes #2397) --- apps/openmw/mwworld/worldimp.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6462629f4d..f78323be6b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -423,6 +423,19 @@ namespace MWWorld globals["werewolfclawmult"] = ESM::Variant(25.f); globals["pcknownwerewolf"] = ESM::Variant(0); + // following should exist in all versions of MW, but not necessarily in TCs + globals["gamehour"] = ESM::Variant(0.f); + globals["timescale"] = ESM::Variant(30.f); + globals["day"] = ESM::Variant(1); + globals["month"] = ESM::Variant(1); + globals["year"] = ESM::Variant(1); + globals["pcrace"] = ESM::Variant(0); + globals["pchascrimegold"] = ESM::Variant(0); + globals["pchasgolddiscount"] = ESM::Variant(0); + globals["crimegolddiscount"] = ESM::Variant(0); + globals["crimegoldturnin"] = ESM::Variant(0); + globals["pchasturnin"] = ESM::Variant(0); + for (std::map::iterator it = gmst.begin(); it != gmst.end(); ++it) { if (!mStore.get().search(it->first)) From 72e94380be20aab94e23d6503a2983f76d74e174 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 26 Feb 2015 20:07:23 +1300 Subject: [PATCH 209/214] fix: boost::filesystem::canonical() available from version 1.48. --- apps/mwiniimporter/importer.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 00774d7982..efebe5a4d0 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -885,10 +886,10 @@ std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename std::time_t writeTime(defaultTime); if (boost::filesystem::exists(filename)) { - // FixMe: remove #if when Boost on Travis Linux updated - // Travis seems to be using older version of boost for Linux - // This should allow things to build until fixed -#if BOOST_FILESYSTEM_VERSION == 3 + // FixMe: remove #if when Boost dependency for Linux builds updated + // This allows Linux to build until then +#if (BOOST_VERSION >= 104800) + // need to resolve any symlinks so that we get time of file, not symlink boost::filesystem::path resolved = boost::filesystem::canonical(filename); #else boost::filesystem::path resolved = filename; From 1bb29f610fe25dff6ae26fba0310dfab407c2da7 Mon Sep 17 00:00:00 2001 From: sylar Date: Thu, 26 Feb 2015 18:29:38 +0400 Subject: [PATCH 210/214] enable mipmapping for Android again --- apps/openmw/mwrender/renderingmanager.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b83a078ba7..05b43d54f5 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -120,14 +120,12 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b // Set default texture filtering options TextureFilterOptions tfo; std::string filter = Settings::Manager::getString("texture filtering", "General"); -#ifndef ANDROID + if (filter == "anisotropic") tfo = TFO_ANISOTROPIC; else if (filter == "trilinear") tfo = TFO_TRILINEAR; else if (filter == "bilinear") tfo = TFO_BILINEAR; else /*if (filter == "none")*/ tfo = TFO_NONE; -#else - tfo = TFO_NONE; -#endif + MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 ); From 70398e2f9f2a9a0701c0c401e0d3c43f187f9267 Mon Sep 17 00:00:00 2001 From: sylar Date: Thu, 26 Feb 2015 18:30:14 +0400 Subject: [PATCH 211/214] change Jni name method --- components/files/androidpath.cpp | 2 +- components/files/androidpath.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/files/androidpath.cpp b/components/files/androidpath.cpp index 1176260952..009bd98a2c 100644 --- a/components/files/androidpath.cpp +++ b/components/files/androidpath.cpp @@ -27,7 +27,7 @@ char const * Buffer::getData() } -JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt) +JNIEXPORT void JNICALL Java_ui_activity_GameActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt) { jboolean iscopy; Buffer::setData((env)->GetStringUTFChars(prompt, &iscopy)); diff --git a/components/files/androidpath.h b/components/files/androidpath.h index 3157c067f5..a93a160e0f 100644 --- a/components/files/androidpath.h +++ b/components/files/androidpath.h @@ -1,8 +1,8 @@ /* DO NOT EDIT THIS FILE - it is machine generated */ #include -#ifndef _Included_org_libsdl_app_SDLActivity_getPathToJni -#define _Included_org_libsdl_app_SDLActivity_getPathToJni +#ifndef _Included_ui_activity_GameActivity_getPathToJni +#define _Included_ui_activity_GameActivity_getPathToJni #ifdef __cplusplus extern "C" { #endif @@ -11,7 +11,7 @@ extern "C" { * Method: getPathToJni * Signature: (I)I */ -JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt); +JNIEXPORT void JNICALL Java_ui_activity_GameActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt); #ifdef __cplusplus } From cda3782cf2d8185896c8139df015d1c76ddb0efb Mon Sep 17 00:00:00 2001 From: sylar Date: Thu, 26 Feb 2015 18:30:38 +0400 Subject: [PATCH 212/214] fix crash game on Android after start loading --- apps/openmw/mwworld/refdata.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index da7986ba03..e90b44f9c9 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -33,11 +33,11 @@ namespace MWWorld 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. + bool mDeleted; // separate delete flag used for deletion by a content file bool mHasLocals; bool mEnabled; int mCount; // 0: deleted - bool mDeleted; // separate delete flag used for deletion by a content file ESM::Position mPosition; From cef725012c03f921b0dce68d15953cf4b050be15 Mon Sep 17 00:00:00 2001 From: sylar Date: Fri, 27 Feb 2015 08:56:20 +0400 Subject: [PATCH 213/214] fix transpose error fo gles2 --- files/materials/objects.shader | 17 ++++++++++++++--- files/materials/terrain.shader | 15 +++++++++++++-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 2368d99616..ab693eb398 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -243,7 +243,9 @@ } #else - +#if NORMAL_MAP && SH_GLSLES + mat3 transpose( mat3 m); +#endif // ----------------------------------- FRAGMENT ------------------------------------------ #if UNDERWATER @@ -376,13 +378,13 @@ float3 binormal = cross(tangentPassthrough.xyz, normal.xyz); float3x3 tbn = float3x3(tangentPassthrough.xyz, binormal, normal.xyz); - #if SH_GLSL + #if SH_GLSL || SH_GLSLES tbn = transpose(tbn); #endif float4 normalTex = shSample(normalMap, UV.xy); - normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2 - 1 )); + normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - float (1.0,1.0,1.0) )); #endif #if ENV_MAP || SPECULAR || PARALLAX @@ -576,5 +578,14 @@ // prevent negative colour output (for example with negative lights) shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0.0,0.0,0.0)); } +#if NORMAL_MAP && SH_GLSLES + mat3 transpose(mat3 m){ + return mat3( + m[0][0],m[1][0],m[2][0], + m[0][1],m[1][1],m[2][1], + m[0][2],m[1][2],m[2][2] + ); + } +#endif #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index a4ca10fcc3..9bb5d247da 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -221,6 +221,9 @@ #if UNDERWATER #include "underwater.h" #endif +#if NORMAL_MAP && SH_GLSLES + mat3 transpose(mat3 m); +#endif SH_BEGIN_PROGRAM @@ -319,7 +322,7 @@ shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position) // derive final matrix float3x3 tbn = float3x3(tangent, binormal, normal); - #if SH_GLSL + #if SH_GLSL || SH_GLSLES tbn = transpose(tbn); #endif #endif @@ -492,5 +495,13 @@ albedo = shLerp(albedo, diffuseTex, blendValues@shPropertyString(blendmap_compon shOutputColour(0).a = 1.0-previousAlpha; #endif } - +#if NORMAL_MAP && SH_GLSLES + mat3 transpose(mat3 m){ + return mat3( + m[0][0],m[1][0],m[2][0], + m[0][1],m[1][1],m[2][1], + m[0][2],m[1][2],m[2][2] + ); + } +#endif #endif From edd3f9f95c8256710f8063afcb10eb7f1f610043 Mon Sep 17 00:00:00 2001 From: sylar Date: Fri, 27 Feb 2015 08:58:00 +0400 Subject: [PATCH 214/214] small fix for float --- files/materials/objects.shader | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index ab693eb398..828674cc72 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -384,7 +384,7 @@ float4 normalTex = shSample(normalMap, UV.xy); - normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - float (1.0,1.0,1.0) )); + normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - float3 (1.0,1.0,1.0) )); #endif #if ENV_MAP || SPECULAR || PARALLAX