diff --git a/CHANGELOG.md b/CHANGELOG.md index 53b8284f1..216547668 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ Bug #3812: Wrong multiline tooltips width when word-wrapping is enabled Bug #3894: Hostile spell effects not detected/present on first frame of OnPCHitMe Bug #3977: Non-ASCII characters in object ID's are not supported + Bug #4009: Launcher does not show data files on the first run after installing Bug #4077: Enchanted items are not recharged if they are not in the player's inventory Bug #4202: Open .omwaddon files without needing toopen openmw-cs first Bug #4240: Ash storm origin coordinates and hand shielding animation behavior are incorrect @@ -62,6 +63,7 @@ Bug #4787: Sneaking makes 1st person walking/bobbing animation super-slow Bug #4797: Player sneaking and running stances are not accounted for when in air Bug #4800: Standing collisions are not updated immediately when an object is teleported without a cell change + Bug #4802: You can rest before taking falling damage from landing from a jump Bug #4803: Stray special characters before begin statement break script compilation Bug #4804: Particle system with the "Has Sizes = false" causes an exception Bug #4805: NPC movement speed calculations do not take race Weight into account @@ -179,6 +181,10 @@ Bug #5213: SameFaction script function is broken Bug #5218: Crash when disabling ToggleBorders Bug #5220: GetLOS crashes when actor isn't loaded + Bug #5222: Empty cell name subrecords are not saved + Bug #5223: Bow replacement during attack animation removes attached arrow + Bug #5226: Reputation should be capped + Bug #5229: Crash if mesh controller node has no data node Feature #1774: Handle AvoidNode Feature #2229: Improve pathfinding AI Feature #3025: Analogue gamepad movement controls @@ -229,6 +235,7 @@ Feature #5147: Show spell magicka cost in spell buying window Feature #5170: Editor: Land shape editing, land selection Feature #5193: Weapon sheathing + Feature #5224: Handle NiKeyframeController for NiTriShape Task #4686: Upgrade media decoder to a more current FFmpeg API Task #4695: Optimize Distant Terrain memory consumption Task #4789: Optimize cell transitions diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index e8f444489..b7cbd8f65 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -1032,14 +1032,6 @@ void Record::print() std::cout << " Reputation: " << (int)mData.mNpdt.mReputation << std::endl; std::cout << " Disposition: " << (int)mData.mNpdt.mDisposition << std::endl; std::cout << " Rank: " << (int)mData.mNpdt.mRank << std::endl; - //Why do we want to print these fields? They are padding in the struct and contain - // nothing of real value. Now we don't deal with NPDTstruct12 in runtime either... - //std::cout << " Unknown1: " - // << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown1) << std::endl; - //std::cout << " Unknown2: " - // << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown2) << std::endl; - //std::cout << " Unknown3: " - // << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown3) << std::endl; std::cout << " Gold: " << mData.mNpdt.mGold << std::endl; } else { @@ -1047,7 +1039,6 @@ void Record::print() std::cout << " Reputation: " << (int)mData.mNpdt.mReputation << std::endl; std::cout << " Disposition: " << (int)mData.mNpdt.mDisposition << std::endl; std::cout << " Rank: " << (int)mData.mNpdt.mRank << std::endl; - std::cout << " FactionID: " << (int)mData.mNpdt.mFactionID << std::endl; std::cout << " Attributes:" << std::endl; std::cout << " Strength: " << (int)mData.mNpdt.mStrength << std::endl; @@ -1067,7 +1058,6 @@ void Record::print() std::cout << " Health: " << mData.mNpdt.mHealth << std::endl; std::cout << " Magicka: " << mData.mNpdt.mMana << std::endl; std::cout << " Fatigue: " << mData.mNpdt.mFatigue << std::endl; - std::cout << " Unknown: " << (int)mData.mNpdt.mUnknown << std::endl; std::cout << " Gold: " << mData.mNpdt.mGold << std::endl; } diff --git a/apps/essimporter/convertscpt.cpp b/apps/essimporter/convertscpt.cpp index 484a2782a..ca81ebbbf 100644 --- a/apps/essimporter/convertscpt.cpp +++ b/apps/essimporter/convertscpt.cpp @@ -9,7 +9,7 @@ namespace ESSImport void convertSCPT(const SCPT &scpt, ESM::GlobalScript &out) { - out.mId = Misc::StringUtils::lowerCase(scpt.mSCHD.mName); + out.mId = Misc::StringUtils::lowerCase(scpt.mSCHD.mName.toString()); out.mRunning = scpt.mRunning; convertSCRI(scpt.mSCRI, out.mLocals); } diff --git a/apps/essimporter/importinventory.cpp b/apps/essimporter/importinventory.cpp index 177213a13..cff114acb 100644 --- a/apps/essimporter/importinventory.cpp +++ b/apps/essimporter/importinventory.cpp @@ -13,11 +13,11 @@ namespace ESSImport { while (esm.isNextSub("NPCO")) { - ESM::ContItem contItem; + ContItem contItem; esm.getHT(contItem); InventoryItem item; - item.mId = contItem.mItem; + item.mId = contItem.mItem.toString(); item.mCount = contItem.mCount; item.mRelativeEquipmentSlot = -1; item.mLockLevel = 0; diff --git a/apps/essimporter/importinventory.hpp b/apps/essimporter/importinventory.hpp index 0b5405d96..a1324a696 100644 --- a/apps/essimporter/importinventory.hpp +++ b/apps/essimporter/importinventory.hpp @@ -5,6 +5,8 @@ #include #include +#include + #include "importscri.hpp" namespace ESM @@ -15,6 +17,12 @@ namespace ESM namespace ESSImport { + struct ContItem + { + int mCount; + ESM::NAME32 mItem; + }; + struct Inventory { struct InventoryItem : public ESM::CellRef diff --git a/apps/essimporter/importscpt.hpp b/apps/essimporter/importscpt.hpp index ce54c3a73..6bfd2603a 100644 --- a/apps/essimporter/importscpt.hpp +++ b/apps/essimporter/importscpt.hpp @@ -13,10 +13,16 @@ namespace ESM namespace ESSImport { + struct SCHD + { + ESM::NAME32 mName; + ESM::Script::SCHDstruct mData; + }; + // A running global script struct SCPT { - ESM::Script::SCHD mSCHD; + SCHD mSCHD; // values of local variables SCRI mSCRI; diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 4ba164698..6bc22bad6 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -5,6 +5,10 @@ #include #include +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) +#include +#endif + #ifdef MAC_OS_X_VERSION_MIN_REQUIRED #undef MAC_OS_X_VERSION_MIN_REQUIRED // We need to do this because of Qt: https://bugreports.qt-project.org/browse/QTBUG-22154 @@ -311,6 +315,17 @@ QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen) QRect Launcher::GraphicsPage::getMaximumResolution() { QRect max; + +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + for (QScreen* screen : QGuiApplication::screens()) + { + QRect res = screen->geometry(); + if (res.width() > max.width()) + max.setWidth(res.width()); + if (res.height() > max.height()) + max.setHeight(res.height()); + } +#else int screens = QApplication::desktop()->screenCount(); for (int i = 0; i < screens; ++i) { @@ -320,6 +335,7 @@ QRect Launcher::GraphicsPage::getMaximumResolution() if (res.height() > max.height()) max.setHeight(res.height()); } +#endif return max; } diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index f4aa34d6f..0e36d7b2c 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -116,6 +116,10 @@ void Launcher::MainDialog::createIcons() void Launcher::MainDialog::createPages() { + // Avoid creating the widgets twice + if (pagesWidget->count() != 0) + return; + mPlayPage = new PlayPage(this); mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this); mGraphicsPage = new GraphicsPage(mCfgMgr, mEngineSettings, this); @@ -166,18 +170,20 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog() QAbstractButton *skipButton = msgBox.addButton(tr("Skip"), QMessageBox::RejectRole); - Q_UNUSED(skipButton); // Surpress compiler unused warning - msgBox.exec(); if (msgBox.clickedButton() == wizardButton) { - if (!mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false)) { - return FirstRunDialogResultFailure; - } else { + if (mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false)) return FirstRunDialogResultWizard; - } } + else if (msgBox.clickedButton() == skipButton) + { + // Don't bother setting up absent game data. + if (setup()) + return FirstRunDialogResultContinue; + } + return FirstRunDialogResultFailure; } if (!setup() || !setupGameData()) { @@ -384,22 +390,23 @@ bool Launcher::MainDialog::setupGameData() QMessageBox msgBox; msgBox.setWindowTitle(tr("Error detecting Morrowind installation")); msgBox.setIcon(QMessageBox::Warning); - msgBox.setStandardButtons(QMessageBox::Cancel); + msgBox.setStandardButtons(QMessageBox::NoButton); msgBox.setText(tr("
Could not find the Data Files location

\ The directory containing the data files was not found.")); QAbstractButton *wizardButton = msgBox.addButton(tr("Run &Installation Wizard..."), QMessageBox::ActionRole); + QAbstractButton *skipButton = + msgBox.addButton(tr("Skip"), QMessageBox::RejectRole); + + Q_UNUSED(skipButton); // Supress compiler unused warning msgBox.exec(); if (msgBox.clickedButton() == wizardButton) { - if (!mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false)) { + if (!mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false)) return false; - } else { - return true; - } } } @@ -582,7 +589,7 @@ void Launcher::MainDialog::wizardFinished(int exitCode, QProcess::ExitStatus exi // HACK: Ensure the pages are created, else segfault setup(); - if (reloadSettings()) + if (setupGameData() && reloadSettings()) show(); } diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 5dda78919..e2c3be789 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -236,7 +236,6 @@ namespace CSMWorld { ColumnId_FactionReactions, "Reactions" }, { ColumnId_FactionRanks, "Ranks" }, - //{ ColumnId_FactionID, "Faction ID" }, { ColumnId_FactionReaction, "Reaction" }, { ColumnId_FactionAttrib1, "Attrib 1" }, @@ -248,7 +247,6 @@ namespace CSMWorld { ColumnId_EffectList, "Effects" }, { ColumnId_EffectId, "Effect" }, - //{ ColumnId_EffectAttribute, "Attrib" }, { ColumnId_EffectRange, "Range" }, { ColumnId_EffectArea, "Area" }, @@ -257,7 +255,6 @@ namespace CSMWorld { ColumnId_AiWanderDist, "Wander Dist" }, { ColumnId_AiDuration, "Ai Duration" }, { ColumnId_AiWanderToD, "Wander ToD" }, - //{ ColumnId_AiWanderIdle, "Wander Idle" }, { ColumnId_AiWanderRepeat, "Wander Repeat" }, { ColumnId_AiActivateName, "Activate" }, { ColumnId_AiTargetId, "Target ID" }, @@ -291,7 +288,6 @@ namespace CSMWorld { ColumnId_UChar, "Value [0..255]" }, { ColumnId_NpcMisc, "NPC Misc" }, { ColumnId_Level, "Level" }, - { ColumnId_NpcFactionID, "Faction ID" }, { ColumnId_GenderNpc, "Gender"}, { ColumnId_Mana, "Mana" }, { ColumnId_Fatigue, "Fatigue" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 3430a4837..085e6e178 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -225,12 +225,10 @@ namespace CSMWorld ColumnId_SoundChance = 210, ColumnId_FactionReactions = 211, - //ColumnId_FactionID = 212, ColumnId_FactionReaction = 213, ColumnId_EffectList = 214, ColumnId_EffectId = 215, - //ColumnId_EffectAttribute = 216, ColumnId_EffectRange = 217, ColumnId_EffectArea = 218, @@ -275,7 +273,6 @@ namespace CSMWorld ColumnId_UChar = 250, ColumnId_NpcMisc = 251, ColumnId_Level = 252, - ColumnId_NpcFactionID = 253, ColumnId_GenderNpc = 254, ColumnId_Mana = 255, ColumnId_Fatigue = 256, diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 3c9faa211..d85fcc068 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -1096,27 +1096,25 @@ QVariant CSMWorld::NpcMiscRefIdAdapter::getNestedData (const RefIdColumn *column case 1: return QVariant(QVariant::UserType); case 2: return QVariant(QVariant::UserType); case 3: return QVariant(QVariant::UserType); - case 4: return QVariant(QVariant::UserType); - case 5: return static_cast(record.get().mNpdt.mDisposition); - case 6: return static_cast(record.get().mNpdt.mReputation); - case 7: return static_cast(record.get().mNpdt.mRank); - case 8: return record.get().mNpdt.mGold; - case 9: return record.get().mPersistent == true; + case 4: return static_cast(record.get().mNpdt.mDisposition); + case 5: return static_cast(record.get().mNpdt.mReputation); + case 6: return static_cast(record.get().mNpdt.mRank); + case 7: return record.get().mNpdt.mGold; + case 8: return record.get().mPersistent == true; default: return QVariant(); // throw an exception here? } else switch (subColIndex) { case 0: return static_cast(record.get().mNpdt.mLevel); - case 1: return static_cast(record.get().mNpdt.mFactionID); - case 2: return static_cast(record.get().mNpdt.mHealth); - case 3: return static_cast(record.get().mNpdt.mMana); - case 4: return static_cast(record.get().mNpdt.mFatigue); - case 5: return static_cast(record.get().mNpdt.mDisposition); - case 6: return static_cast(record.get().mNpdt.mReputation); - case 7: return static_cast(record.get().mNpdt.mRank); - case 8: return record.get().mNpdt.mGold; - case 9: return record.get().mPersistent == true; + case 1: return static_cast(record.get().mNpdt.mHealth); + case 2: return static_cast(record.get().mNpdt.mMana); + case 3: return static_cast(record.get().mNpdt.mFatigue); + case 4: return static_cast(record.get().mNpdt.mDisposition); + case 5: return static_cast(record.get().mNpdt.mReputation); + case 6: return static_cast(record.get().mNpdt.mRank); + case 7: return record.get().mNpdt.mGold; + case 8: return record.get().mPersistent == true; default: return QVariant(); // throw an exception here? } } @@ -1137,27 +1135,25 @@ void CSMWorld::NpcMiscRefIdAdapter::setNestedData (const RefIdColumn *column, case 1: return; case 2: return; case 3: return; - case 4: return; - case 5: npc.mNpdt.mDisposition = static_cast(value.toInt()); break; - case 6: npc.mNpdt.mReputation = static_cast(value.toInt()); break; - case 7: npc.mNpdt.mRank = static_cast(value.toInt()); break; - case 8: npc.mNpdt.mGold = value.toInt(); break; - case 9: npc.mPersistent = value.toBool(); break; + case 4: npc.mNpdt.mDisposition = static_cast(value.toInt()); break; + case 5: npc.mNpdt.mReputation = static_cast(value.toInt()); break; + case 6: npc.mNpdt.mRank = static_cast(value.toInt()); break; + case 7: npc.mNpdt.mGold = value.toInt(); break; + case 8: npc.mPersistent = value.toBool(); break; default: return; // throw an exception here? } else switch(subColIndex) { case 0: npc.mNpdt.mLevel = static_cast(value.toInt()); break; - case 1: npc.mNpdt.mFactionID = static_cast(value.toInt()); break; - case 2: npc.mNpdt.mHealth = static_cast(value.toInt()); break; - case 3: npc.mNpdt.mMana = static_cast(value.toInt()); break; - case 4: npc.mNpdt.mFatigue = static_cast(value.toInt()); break; - case 5: npc.mNpdt.mDisposition = static_cast(value.toInt()); break; - case 6: npc.mNpdt.mReputation = static_cast(value.toInt()); break; - case 7: npc.mNpdt.mRank = static_cast(value.toInt()); break; - case 8: npc.mNpdt.mGold = value.toInt(); break; - case 9: npc.mPersistent = value.toBool(); break; + case 1: npc.mNpdt.mHealth = static_cast(value.toInt()); break; + case 2: npc.mNpdt.mMana = static_cast(value.toInt()); break; + case 3: npc.mNpdt.mFatigue = static_cast(value.toInt()); break; + case 4: npc.mNpdt.mDisposition = static_cast(value.toInt()); break; + case 5: npc.mNpdt.mReputation = static_cast(value.toInt()); break; + case 6: npc.mNpdt.mRank = static_cast(value.toInt()); break; + case 7: npc.mNpdt.mGold = value.toInt(); break; + case 8: npc.mPersistent = value.toBool(); break; default: return; // throw an exception here? } @@ -1166,7 +1162,7 @@ void CSMWorld::NpcMiscRefIdAdapter::setNestedData (const RefIdColumn *column, int CSMWorld::NpcMiscRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const { - return 10; // Level, FactionID, Health, Mana, Fatigue, Disposition, Reputation, Rank, Gold, Persist + return 9; // Level, Health, Mana, Fatigue, Disposition, Reputation, Rank, Gold, Persist } int CSMWorld::NpcMiscRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 19d2900da..ff146bb91 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -535,8 +535,6 @@ CSMWorld::RefIdCollection::RefIdCollection() mNestedAdapters.push_back (std::make_pair(&mColumns.back(), miscMap)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_Level, CSMWorld::ColumnBase::Display_SignedInteger16)); - mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_NpcFactionID, CSMWorld::ColumnBase::Display_SignedInteger8)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_Health, CSMWorld::ColumnBase::Display_UnsignedInteger16)); mColumns.back().addColumn( diff --git a/apps/opencs/view/doc/newgame.cpp b/apps/opencs/view/doc/newgame.cpp index b3e2a4f63..8e976c68f 100644 --- a/apps/opencs/view/doc/newgame.cpp +++ b/apps/opencs/view/doc/newgame.cpp @@ -6,6 +6,10 @@ #include #include +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) +#include +#endif + #include "filewidget.hpp" #include "adjusterwidget.hpp" @@ -46,7 +50,11 @@ CSVDoc::NewGameDialogue::NewGameDialogue() connect (mFileWidget, SIGNAL (nameChanged (const QString&, bool)), mAdjusterWidget, SLOT (setName (const QString&, bool))); +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + QRect scr = QGuiApplication::primaryScreen()->geometry(); +#else QRect scr = QApplication::desktop()->screenGeometry(); +#endif QRect rect = geometry(); move (scr.center().x() - rect.center().x(), scr.center().y() - rect.center().y()); } diff --git a/apps/opencs/view/doc/startup.cpp b/apps/opencs/view/doc/startup.cpp index 78f18b3a1..beb2cf7d8 100644 --- a/apps/opencs/view/doc/startup.cpp +++ b/apps/opencs/view/doc/startup.cpp @@ -10,6 +10,10 @@ #include #include +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) +#include +#endif + QPushButton *CSVDoc::StartupDialogue::addButton (const QString& label, const QIcon& icon) { int column = mColumn--; @@ -119,7 +123,12 @@ CSVDoc::StartupDialogue::StartupDialogue() : mWidth (0), mColumn (2) setLayout (layout); +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + QRect scr = QGuiApplication::primaryScreen()->geometry(); +#else QRect scr = QApplication::desktop()->screenGeometry(); +#endif + QRect rect = geometry(); move (scr.center().x() - rect.center().x(), scr.center().y() - rect.center().y()); } diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 529f21165..9c0e33080 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -15,6 +15,10 @@ #include #include +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) +#include +#endif + #include "../../model/doc/document.hpp" #include "../../model/prefs/state.hpp" #include "../../model/prefs/shortcut.hpp" @@ -1050,7 +1054,7 @@ void CSVDoc::View::updateWidth(bool isGrowLimit, int minSubViewWidth) if (isGrowLimit) rect = dw->screenGeometry(this); else - rect = dw->screenGeometry(dw->screen(dw->screenNumber(this))); + rect = QGuiApplication::screens().at(dw->screenNumber(this))->geometry(); if (!mScrollbarOnly && mScroll && mSubViews.size() > 1) { diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp index 0d32ebd0a..853031ccd 100644 --- a/apps/opencs/view/prefs/dialogue.cpp +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -8,6 +8,10 @@ #include #include +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) +#include +#endif + #include #include "../../model/prefs/state.hpp" @@ -34,7 +38,12 @@ void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main) ++iter) { QString label = QString::fromUtf8 (iter->second.getKey().c_str()); + +#if QT_VERSION >= QT_VERSION_CHECK(5,11,0) + maxWidth = std::max (maxWidth, metrics.horizontalAdvance (label)); +#else maxWidth = std::max (maxWidth, metrics.width (label)); +#endif list->addItem (label); } @@ -107,8 +116,15 @@ void CSVPrefs::Dialogue::show() } else { +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + QRect scr = QGuiApplication::primaryScreen()->geometry(); +#else + QRect scr = QApplication::desktop()->screenGeometry(); +#endif + // otherwise place at the centre of the screen - QPoint screenCenter = QApplication::desktop()->screenGeometry().center(); + QPoint screenCenter = scr.center(); + move (screenCenter - QPoint(frameGeometry().width()/2, frameGeometry().height()/2)); } diff --git a/apps/opencs/view/render/terrainstorage.hpp b/apps/opencs/view/render/terrainstorage.hpp index 032261ad4..74c30ce5c 100644 --- a/apps/opencs/view/render/terrainstorage.hpp +++ b/apps/opencs/view/render/terrainstorage.hpp @@ -18,6 +18,8 @@ namespace CSVRender TerrainStorage(const CSMWorld::Data& data); void setAlteredHeight(int inCellX, int inCellY, float heightMap); void resetHeights(); + + virtual bool useAlteration() const { return true; } float getSumOfAlteredAndTrueHeight(int cellX, int cellY, int inCellX, int inCellY); float* getAlteredHeight(int inCellX, int inCellY); diff --git a/apps/opencs/view/widget/coloreditor.cpp b/apps/opencs/view/widget/coloreditor.cpp index e30696458..cd19e54a3 100644 --- a/apps/opencs/view/widget/coloreditor.cpp +++ b/apps/opencs/view/widget/coloreditor.cpp @@ -6,6 +6,10 @@ #include #include +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) +#include +#endif + #include "colorpickerpopup.hpp" CSVWidget::ColorEditor::ColorEditor(const QColor &color, QWidget *parent, const bool popupOnStart) @@ -95,7 +99,11 @@ QPoint CSVWidget::ColorEditor::calculatePopupPosition() { QRect editorGeometry = geometry(); QRect popupGeometry = mColorPicker->geometry(); +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + QRect screenGeometry = QGuiApplication::primaryScreen()->geometry(); +#else QRect screenGeometry = QApplication::desktop()->screenGeometry(); +#endif // Center the popup horizontally relative to the editor int localPopupX = (editorGeometry.width() - popupGeometry.width()) / 2; diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index dd4405a92..0f920db94 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -134,7 +134,12 @@ QSize CSVWorld::EnumDelegate::sizeHint(const QStyleOptionViewItem &option, const itemOption.state = option.state; const QString &valueText = mValues.at(valueIndex).second; + +#if QT_VERSION >= QT_VERSION_CHECK(5,11,0) + QSize valueSize = QSize(itemOption.fontMetrics.horizontalAdvance(valueText), itemOption.fontMetrics.height()); +#else QSize valueSize = QSize(itemOption.fontMetrics.width(valueText), itemOption.fontMetrics.height()); +#endif itemOption.currentText = valueText; return QApplication::style()->sizeFromContents(QStyle::CT_ComboBox, &itemOption, valueSize); diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index 1105404b3..996e80da4 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -205,7 +205,12 @@ bool CSVWorld::ScriptEdit::stringNeedsQuote (const std::string& id) const void CSVWorld::ScriptEdit::setTabWidth() { // Set tab width to specified number of characters using current font. +#if QT_VERSION >= QT_VERSION_CHECK(5,11,0) + setTabStopDistance(mTabCharCount * fontMetrics().horizontalAdvance(' ')); +#else setTabStopWidth(mTabCharCount * fontMetrics().width(' ')); +#endif + } void CSVWorld::ScriptEdit::wrapLines(bool wrap) @@ -285,7 +290,11 @@ int CSVWorld::ScriptEdit::lineNumberAreaWidth() ++digits; } +#if QT_VERSION >= QT_VERSION_CHECK(5,11,0) + int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits; +#else int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits; +#endif return space; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9c0eba4a8..35e6bbbef 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -253,7 +253,7 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); MyGUI::FactoryManager::getInstance().registerFactory("Resource", "AutoSizedResourceSkin"); MyGUI::ResourceManager::getInstance().load("core.xml"); - loadUserFonts(); + WindowManager::loadUserFonts(); bool keyboardNav = Settings::Manager::getBool("keyboard navigation", "GUI"); mKeyboardNavigation.reset(new KeyboardNavigation()); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ed680a059..06b5a6edb 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -332,10 +332,10 @@ namespace MWMechanics bool wasEquipped = currentItem != store.end() && Misc::StringUtils::ciEqual(currentItem->getCellRef().getRefId(), itemId); - store.remove(itemId, 1, actor); - if (actor != MWMechanics::getPlayer()) { + store.remove(itemId, 1, actor); + // Equip a replacement if (!wasEquipped) return; @@ -362,17 +362,19 @@ namespace MWMechanics std::string prevItemId = player.getPreviousItem(itemId); player.erasePreviousItem(itemId); - if (prevItemId.empty()) - return; + if (!prevItemId.empty()) + { + // Find previous item (or its replacement) by id. + // we should equip previous item only if expired bound item was equipped. + MWWorld::Ptr item = store.findReplacement(prevItemId); + if (!item.isEmpty() && wasEquipped) + { + MWWorld::ActionEquip action(item); + action.execute(actor); + } + } - // Find previous item (or its replacement) by id. - // we should equip previous item only if expired bound item was equipped. - MWWorld::Ptr item = store.findReplacement(prevItemId); - if (item.isEmpty() || !wasEquipped) - return; - - MWWorld::ActionEquip action(item); - action.execute(actor); + store.remove(itemId, 1, actor); } void Actors::updateActor (const MWWorld::Ptr& ptr, float duration) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 70df1b4b8..067925e22 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -593,6 +593,13 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup mCurrentMovement = movementAnimName; if(!mCurrentMovement.empty()) { + if (resetIdle) + { + mAnimation->disable(mCurrentIdle); + mIdleState = CharState_None; + idle = CharState_None; + } + // For non-flying creatures, MW uses the Walk animation to calculate the animation velocity // even if we are running. This must be replicated, otherwise the observed speed would differ drastically. std::string anim = mCurrentMovement; @@ -632,9 +639,6 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup mAnimation->play(mCurrentMovement, Priority_Movement, movemask, false, 1.f, "start", "stop", startpoint, ~0ul, true); - - if (resetIdle) - mAnimation->disable(mCurrentIdle); } else mMovementState = CharState_None; @@ -1814,6 +1818,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle) mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim) { mAnimation->disable(mCurrentIdle); + mIdleState = CharState_None; } animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 758c07a65..6d9f53831 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -450,6 +450,11 @@ namespace MWMechanics mFallHeight += height; } + float CreatureStats::getFallHeight() const + { + return mFallHeight; + } + float CreatureStats::land(bool isPlayer) { if (isPlayer) diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 50b984567..57e9c8363 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -115,6 +115,7 @@ namespace MWMechanics bool needToRecalcDynamicStats(); void setNeedRecalcDynamicStats(bool val); + float getFallHeight() const; void addToFallHeight(float height); /// Reset the fall height diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 68821d415..c97d673c6 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -431,7 +431,8 @@ int MWMechanics::NpcStats::getReputation() const void MWMechanics::NpcStats::setReputation(int reputation) { - mReputation = reputation; + // Reputation is capped in original engine + mReputation = std::min(255, std::max(0, reputation)); } int MWMechanics::NpcStats::getCrimeId() const diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 56c3846af..3505ea261 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -515,13 +515,11 @@ namespace MWRender protected: virtual void setDefaults(osg::StateSet* stateset) { - osg::Material* material = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); - osg::BlendFunc* blendfunc (new osg::BlendFunc); stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); // FIXME: overriding diffuse/ambient/emissive colors - material = new osg::Material; + osg::Material* material = new osg::Material; material->setColorMode(osg::Material::OFF); material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,mAlpha)); material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); @@ -635,7 +633,7 @@ namespace MWRender Animation::~Animation() { - setLightEffect(0.f); + Animation::setLightEffect(0.f); if (mObjectRoot) mInsert->removeChild(mObjectRoot); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index abc2583d5..e9f62e25c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -409,6 +409,7 @@ void NpcAnimation::setRenderBin() void NpcAnimation::rebuild() { mScabbard.reset(); + mHolsteredShield.reset(); updateNpcBase(); MWBase::Environment::get().getMechanicsManager()->forceStateUpdate(mPtr); @@ -597,7 +598,7 @@ void NpcAnimation::updateParts() }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); - bool wasArrowAttached = (mAmmunition.get() != nullptr); + bool wasArrowAttached = isArrowAttached(); mAmmunition.reset(); const MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 4c41a5b40..9c87cac19 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -1489,7 +1489,7 @@ OpenAL_Output::OpenAL_Output(SoundManager &mgr) OpenAL_Output::~OpenAL_Output() { - deinit(); + OpenAL_Output::deinit(); } } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index e01df7aa9..5c277d09e 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -1362,7 +1362,7 @@ namespace MWSound void SoundManager::clear() { - stopMusic(); + SoundManager::stopMusic(); for(SoundMap::value_type &snd : mActiveSounds) { diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 30f969193..4cb0dbe51 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -93,7 +93,7 @@ namespace MWWorld { for (slot=slots_.first.begin();slot!=slots_.first.end(); ++slot) { - invStore.unequipSlot(*slot, actor); + invStore.unequipSlot(*slot, actor, false); if (slot+1 != slots_.first.end()) invStore.equip(*slot, invStore.getSlot(*(slot+1)), actor); else diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 467f50420..ab5cbf9c4 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -832,7 +832,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor return retCount; } -MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, const MWWorld::Ptr& actor) +MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, const MWWorld::Ptr& actor, bool fireEvent) { if (slot<0 || slot>=static_cast (mSlots.size())) throw std::runtime_error ("slot number out of range"); @@ -864,7 +864,9 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, c } } - fireEquipmentChangedEvent(actor); + if (fireEvent) + fireEquipmentChangedEvent(actor); + updateMagicEffects(actor); return retval; diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 2293f96af..663e7a2d3 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -173,7 +173,7 @@ namespace MWWorld /// /// @return the number of items actually removed - ContainerStoreIterator unequipSlot(int slot, const Ptr& actor); + ContainerStoreIterator unequipSlot(int slot, const Ptr& actor, bool fireEvent=true); ///< Unequip \a slot. /// /// @return an iterator to the item that was previously in the slot diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index bb2ad60f8..67d38bbbe 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -215,12 +215,11 @@ namespace struct InsertVisitor { MWWorld::CellStore& mCell; - bool mRescale; Loading::Listener& mLoadingListener; std::vector mToInsert; - InsertVisitor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener); + InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener); bool operator() (const MWWorld::Ptr& ptr); @@ -228,8 +227,8 @@ namespace void insert(AddObject&& addObject); }; - InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener) - : mCell (cell), mRescale (rescale), mLoadingListener (loadingListener) + InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener) + : mCell (cell), mLoadingListener (loadingListener) {} bool InsertVisitor::operator() (const MWWorld::Ptr& ptr) @@ -245,14 +244,6 @@ namespace { for (MWWorld::Ptr& ptr : mToInsert) { - if (mRescale) - { - if (ptr.getCellRef().getScale()<0.5) - ptr.getCellRef().setScale(0.5); - else if (ptr.getCellRef().getScale()>2) - ptr.getCellRef().setScale(2); - } - if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled()) { try @@ -459,19 +450,7 @@ namespace MWWorld cell->respawn(); // ... then references. This is important for adjustPosition to work correctly. - /// \todo rescale depending on the state of a new GMST - - /* - Start of tes3mp change (major) - - Instead of always rescaling objects as in the original code, never rescale them, - so they can maintain their server-set scales when their cells are reloaded - */ - insertCell(*cell, false, loadingListener); - /* - End of tes3mp change (major) - */ - + insertCell (*cell, loadingListener); mRendering.addCell(cell); MWBase::Environment::get().getWindowManager()->addCell(cell); @@ -852,9 +831,9 @@ namespace MWWorld mCellChanged = false; } - void Scene::insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener) + void Scene::insertCell (CellStore &cell, Loading::Listener* loadingListener) { - InsertVisitor insertVisitor (cell, rescale, *loadingListener); + InsertVisitor insertVisitor (cell, *loadingListener); cell.forEach (insertVisitor); insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mRendering); }); insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mNavigator); }); diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 056c3acb2..57f994fab 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -85,7 +85,7 @@ namespace MWWorld osg::Vec3f mLastPlayerPos; - void insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener); + void insertCell (CellStore &cell, Loading::Listener* loadingListener); // Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center void changeCellGrid (int playerCellX, int playerCellY, bool changeEvent = true); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d616a1b4b..f58203548 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2806,7 +2806,9 @@ namespace MWWorld if (isUnderwater(currentCell, playerPos) || isWalkingOnWater(player)) return Rest_PlayerIsUnderwater; - if ((actor->getCollisionMode() && !mPhysics->isOnSolidGround(player)) || isFlying(player)) + float fallHeight = player.getClass().getCreatureStats(player).getFallHeight(); + float epsilon = 1e-4; + if ((actor->getCollisionMode() && (!mPhysics->isOnSolidGround(player) || fallHeight >= epsilon)) || isFlying(player)) return Rest_PlayerIsInAir; if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || player.getClass().getNpcStats(player).isWerewolf()) diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index c64c96a78..4849e3372 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -67,6 +67,10 @@ void ESM::CellRef::loadData(ESMReader &esm, bool &isDeleted) break; case ESM::FourCC<'X','S','C','L'>::value: esm.getHT(mScale); + if (mScale < 0.5) + mScale = 0.5; + else if (mScale > 2) + mScale = 2; break; case ESM::FourCC<'A','N','A','M'>::value: mOwner = esm.getHString(); @@ -141,7 +145,12 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory, bool } if (mScale != 1.0) { - esm.writeHNT("XSCL", mScale); + float scale = mScale; + if (scale < 0.5) + scale = 0.5; + else if (scale > 2) + scale = 2; + esm.writeHNT("XSCL", scale); } esm.writeHNOCString("ANAM", mOwner); diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 657d92d6e..ec4155f59 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -160,7 +160,7 @@ namespace ESM void Cell::save(ESMWriter &esm, bool isDeleted) const { - esm.writeHNOCString("NAME", mName); + esm.writeHNCString("NAME", mName); esm.writeHNT("DATA", mData, 12); if (isDeleted) diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index b68aa6375..2bb0811ac 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -216,9 +216,9 @@ namespace ESM mNpdt.mReputation = 0; mNpdt.mHealth = mNpdt.mMana = mNpdt.mFatigue = 0; mNpdt.mDisposition = 0; - mNpdt.mFactionID = 0; + mNpdt.mUnknown1 = 0; mNpdt.mRank = 0; - mNpdt.mUnknown = 0; + mNpdt.mUnknown2 = 0; mNpdt.mGold = 0; } diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index ac3f1a343..687afeaf6 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -87,10 +87,10 @@ struct NPC // mSkill can grow up to 200, it must be unsigned unsigned char mSkills[Skill::Length]; - char mFactionID; + char mUnknown1; unsigned short mHealth, mMana, mFatigue; unsigned char mDisposition, mReputation, mRank; - char mUnknown; + char mUnknown2; int mGold; }; // 52 bytes diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 52af530f5..021ae32e9 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -201,6 +201,8 @@ namespace ESMTerrain LandCache cache; + bool alteration = useAlteration(); + float vertY_ = 0; // of current cell corner for (int cellY = startCellY; cellY < startCellY + std::ceil(size); ++cellY) { @@ -251,11 +253,12 @@ namespace ESMTerrain float height = defaultHeight; if (heightData) height = heightData->mHeights[col*ESM::Land::LAND_SIZE + row]; - + if (alteration) + height += getAlteredHeight(col, row); (*positions)[static_cast(vertX*numVerts + vertY)] = osg::Vec3f((vertX / float(numVerts - 1) - 0.5f) * size * Constants::CellSizeInUnits, (vertY / float(numVerts - 1) - 0.5f) * size * Constants::CellSizeInUnits, - height + getAlteredHeight(col, row)); + height); if (normalData) { @@ -290,8 +293,8 @@ namespace ESMTerrain color.g() = 255; color.b() = 255; } - - adjustColor(col, row, heightData, color); //Does nothing by default, override in OpenMW-CS + if (alteration) + adjustColor(col, row, heightData, color); //Does nothing by default, override in OpenMW-CS // Unlike normals, colors mostly connect seamlessly between cells, but not always... if (col == ESM::Land::LAND_SIZE-1 || row == ESM::Land::LAND_SIZE-1) diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index 65e531e5c..a5f62ba48 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -125,6 +125,7 @@ namespace ESMTerrain inline const LandObject* getLand(int cellX, int cellY, LandCache& cache); + virtual bool useAlteration() const { return false; } virtual void adjustColor(int col, int row, const ESM::Land::LandData *heightData, osg::Vec4ub& color) const; virtual float getAlteredHeight(int col, int row) const; diff --git a/components/interpreter/runtime.cpp b/components/interpreter/runtime.cpp index 6599882f1..a90bda94b 100644 --- a/components/interpreter/runtime.cpp +++ b/components/interpreter/runtime.cpp @@ -15,7 +15,8 @@ namespace Interpreter int Runtime::getIntegerLiteral (int index) const { - assert (index>=0 && index (mCode[1])); + if (index < 0 || index >= static_cast (mCode[1])) + throw std::out_of_range("out of range"); const Type_Code *literalBlock = mCode + 4 + mCode[0]; @@ -24,7 +25,8 @@ namespace Interpreter float Runtime::getFloatLiteral (int index) const { - assert (index>=0 && index (mCode[2])); + if (index < 0 || index >= static_cast (mCode[2])) + throw std::out_of_range("out of range"); const Type_Code *literalBlock = mCode + 4 + mCode[0] + mCode[1]; @@ -33,7 +35,8 @@ namespace Interpreter std::string Runtime::getStringLiteral (int index) const { - assert (index>=0 && static_cast (mCode[3])>0); + if (index < 0 || static_cast (mCode[3]) <= 0) + throw std::out_of_range("out of range"); const char *literalBlock = reinterpret_cast (mCode + 4 + mCode[0] + mCode[1] + mCode[2]); @@ -43,7 +46,8 @@ namespace Interpreter for (; index; --index) { offset += std::strlen (literalBlock+offset) + 1; - assert (offset/4 (mCode[3])); + if (offset / 4 >= static_cast (mCode[3])) + throw std::out_of_range("out of range"); } return literalBlock+offset; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 901dccc51..2fd42e77a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -614,8 +614,6 @@ namespace NifOsg if (composite->getNumControllers() > 0) node->addUpdateCallback(composite); - // Note: NiTriShapes are not allowed to have KeyframeControllers (the vanilla engine just crashes when there is one). - // We can take advantage of this constraint for optimizations later. if (nifNode->recType != Nif::RC_NiTriShape && nifNode->recType != Nif::RC_NiTriStrips && !nifNode->controller.empty() && node->getDataVariance() == osg::Object::DYNAMIC) handleNodeControllers(nifNode, static_cast(node.get()), animflags); @@ -663,6 +661,8 @@ namespace NifOsg if (ctrl->recType == Nif::RC_NiUVController) { const Nif::NiUVController *niuvctrl = static_cast(ctrl.getPtr()); + if (niuvctrl->data.empty()) + continue; const unsigned int uvSet = niuvctrl->uvSet; std::set texUnits; // UVController should work only for textures which use a given UV Set, usually 0. @@ -676,6 +676,17 @@ namespace NifOsg setupController(niuvctrl, uvctrl, animflags); composite->addController(uvctrl); } + else if (ctrl->recType == Nif::RC_NiKeyframeController) + { + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + if(!key->data.empty()) + { + osg::ref_ptr callback(new KeyframeController(key->data.getPtr())); + + setupController(key, callback, animflags); + node->addUpdateCallback(callback); + } + } else if (ctrl->recType == Nif::RC_NiVisController) { handleVisController(static_cast(ctrl.getPtr()), node, animflags); @@ -719,6 +730,8 @@ namespace NifOsg void handleVisController(const Nif::NiVisController* visctrl, osg::Node* node, int animflags) { + if (visctrl->data.empty()) + return; osg::ref_ptr callback(new VisController(visctrl->data.getPtr())); setupController(visctrl, callback, animflags); node->addUpdateCallback(callback); @@ -726,6 +739,8 @@ namespace NifOsg void handleRollController(const Nif::NiRollController* rollctrl, osg::Node* node, int animflags) { + if (rollctrl->data.empty()) + return; osg::ref_ptr callback(new RollController(rollctrl->data.getPtr())); setupController(rollctrl, callback, animflags); node->addUpdateCallback(callback); @@ -740,6 +755,8 @@ namespace NifOsg if (ctrl->recType == Nif::RC_NiAlphaController) { const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); + if (alphactrl->data.empty()) + continue; osg::ref_ptr osgctrl(new AlphaController(alphactrl->data.getPtr())); setupController(alphactrl, osgctrl, animflags); composite->addController(osgctrl); @@ -747,6 +764,8 @@ namespace NifOsg else if (ctrl->recType == Nif::RC_NiMaterialColorController) { const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); + if (matctrl->data.empty()) + continue; // Two bits that correspond to the controlled material color. // 00: Ambient // 01: Diffuse @@ -1133,10 +1152,12 @@ namespace NifOsg continue; if(ctrl->recType == Nif::RC_NiGeomMorpherController) { - drawable = handleMorphGeometry(static_cast(ctrl.getPtr()), geom, parentNode, composite, boundTextures, animflags); + const Nif::NiGeomMorpherController* nimorphctrl = static_cast(ctrl.getPtr()); + if (nimorphctrl->data.empty()) + continue; + drawable = handleMorphGeometry(nimorphctrl, geom, parentNode, composite, boundTextures, animflags); - osg::ref_ptr morphctrl = new GeomMorpherController( - static_cast(ctrl.getPtr())->data.getPtr()); + osg::ref_ptr morphctrl = new GeomMorpherController(nimorphctrl->data.getPtr()); setupController(ctrl.getPtr(), morphctrl, animflags); drawable->setUpdateCallback(morphctrl); break; @@ -1389,7 +1410,7 @@ namespace NifOsg return image; } - void handleTextureProperty(const Nif::NiTexturingProperty* texprop, osg::StateSet* stateset, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager, std::vector& boundTextures, int animflags) + void handleTextureProperty(const Nif::NiTexturingProperty* texprop, const std::string& nodeName, osg::StateSet* stateset, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager, std::vector& boundTextures, int animflags) { if (!boundTextures.empty()) { @@ -1423,7 +1444,7 @@ namespace NifOsg } default: { - Log(Debug::Info) << "Unhandled texture stage " << i << " in " << mFilename; + Log(Debug::Info) << "Unhandled texture stage " << i << " on shape \"" << nodeName << "\" in " << mFilename; continue; } } @@ -1431,7 +1452,8 @@ namespace NifOsg const Nif::NiTexturingProperty::Texture& tex = texprop->textures[i]; if(tex.texture.empty() && texprop->controller.empty()) { - Log(Debug::Verbose) << "Texture layer " << i << " is in use but empty in " << mFilename; + if (i == 0) + Log(Debug::Warning) << "Base texture is in use but empty on shape \"" << nodeName << "\" in " << mFilename; continue; } @@ -1619,7 +1641,7 @@ namespace NifOsg { const Nif::NiTexturingProperty* texprop = static_cast(property); osg::StateSet* stateset = node->getOrCreateStateSet(); - handleTextureProperty(texprop, stateset, composite, imageManager, boundTextures, animflags); + handleTextureProperty(texprop, node->getName(), stateset, composite, imageManager, boundTextures, animflags); break; } // unused by mw diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 6c51951cb..c1ccede1a 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -27,7 +27,7 @@ ParticleSystem::ParticleSystem(const ParticleSystem ©, const osg::CopyOp &co { // For some reason the osgParticle constructor doesn't copy the particles for (int i=0;i texture, unsigned int shadowMapNumber, const osg::Matrixd &matrix, osgUtil::CullVisitor& cv); + void draw(osg::ref_ptr texture, unsigned int shadowMapNumber, const osg::Matrixd &matrix, osgUtil::CullVisitor& cv); - virtual void releaseGLObjects(osg::State* state = 0) const; + void releaseGLObjects(osg::State* state = 0) const; - virtual void setFrustumVertices(osg::ref_ptr vertices, unsigned int traversalNumber); + void setFrustumVertices(osg::ref_ptr vertices, unsigned int traversalNumber); protected: - virtual void addAnotherShadowMap(); + void addAnotherShadowMap(); static const int sDebugTextureUnit = 0; diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 928de4543..c823ecf86 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -19,15 +19,13 @@ namespace SceneUtil ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager); - virtual ~ShadowManager() = default; + void setupShadowSettings(); - virtual void setupShadowSettings(); + Shader::ShaderManager::DefineMap getShadowDefines(); - virtual Shader::ShaderManager::DefineMap getShadowDefines(); + void enableIndoorMode(); - virtual void enableIndoorMode(); - - virtual void enableOutdoorMode(); + void enableOutdoorMode(); protected: bool mEnableShadows; diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index ad8454b25..cd5e80c31 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -20,7 +20,7 @@ GraphicsWindowSDL2::GraphicsWindowSDL2(osg::GraphicsContext::Traits *traits) _traits = traits; init(); - if(valid()) + if(GraphicsWindowSDL2::valid()) { setState(new osg::State); getState()->setGraphicsContext(this); diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index c91240334..7310846c2 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -28,7 +28,7 @@ TerrainGrid::~TerrainGrid() { while (!mGrid.empty()) { - unloadCell(mGrid.begin()->first.first, mGrid.begin()->first.second); + TerrainGrid::unloadCell(mGrid.begin()->first.first, mGrid.begin()->first.second); } } diff --git a/extern/recastnavigation/Detour/Include/DetourNavMesh.h b/extern/recastnavigation/Detour/Include/DetourNavMesh.h index 98293c49d..0bf59ab06 100644 --- a/extern/recastnavigation/Detour/Include/DetourNavMesh.h +++ b/extern/recastnavigation/Detour/Include/DetourNavMesh.h @@ -306,9 +306,6 @@ struct dtMeshTile int dataSize; ///< Size of the tile data. int flags; ///< Tile flags. (See: #dtTileFlags) dtMeshTile* next; ///< The next free tile, or the next tile in the spatial grid. -private: - dtMeshTile(const dtMeshTile&); - dtMeshTile& operator=(const dtMeshTile&); }; /// Get flags for edge in detail triangle.