From 5d14a2afcce241fe9b1677aa48e2b1b4a07a274f Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Thu, 24 Aug 2017 17:12:15 -0400 Subject: [PATCH 001/505] Initial LTEX/LAND tables --- apps/opencs/model/prefs/state.cpp | 2 + apps/opencs/model/world/columnimp.hpp | 64 ++++++++++++++++++++++--- apps/opencs/model/world/columns.cpp | 4 +- apps/opencs/model/world/columns.hpp | 3 ++ apps/opencs/model/world/data.cpp | 14 ++++++ apps/opencs/model/world/universalid.cpp | 8 +++- apps/opencs/model/world/universalid.hpp | 4 ++ apps/opencs/view/doc/view.cpp | 20 ++++++++ apps/opencs/view/doc/view.hpp | 4 ++ apps/opencs/view/world/subviews.cpp | 2 + 10 files changed, 116 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 5c0b2e282..0101a432b 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -240,6 +240,8 @@ void CSMPrefs::State::declare() declareShortcut ("document-world-cells", "Open Cell List", QKeySequence()); declareShortcut ("document-world-referencables", "Open Object List", QKeySequence()); declareShortcut ("document-world-references", "Open Instance List", QKeySequence()); + declareShortcut ("document-world-lands", "Open Lands List", QKeySequence()); + declareShortcut ("document-world-landtextures", "Open Land Textures List", QKeySequence()); declareShortcut ("document-world-pathgrid", "Open Pathgrid List", QKeySequence()); declareShortcut ("document-world-regionmap", "Open Region Map", QKeySequence()); declareShortcut ("document-mechanics-globals", "Open Global List", QKeySequence()); diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 154bdab82..a9a48ef0d 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -15,6 +15,9 @@ #include "columns.hpp" #include "info.hpp" +#include "land.hpp" +#include "landtexture.hpp" + namespace CSMWorld { /// \note Shares ID with VarValueColumn. A table can not have both. @@ -1499,9 +1502,9 @@ namespace CSMWorld template struct TopicColumn : public Column { - TopicColumn (bool journal) + TopicColumn (bool journal) : Column (journal ? Columns::ColumnId_Journal : Columns::ColumnId_Topic, - journal ? ColumnBase::Display_Journal : ColumnBase::Display_Topic) + journal ? ColumnBase::Display_Journal : ColumnBase::Display_Topic) {} virtual QVariant get (const Record& record) const @@ -1755,7 +1758,7 @@ namespace CSMWorld return true; } }; - + template struct GenderNpcColumn : public Column { @@ -2198,8 +2201,8 @@ namespace CSMWorld struct EffectTextureColumn : public Column { EffectTextureColumn (Columns::ColumnId columnId) - : Column (columnId, - columnId == Columns::ColumnId_Particle ? ColumnBase::Display_Texture + : Column (columnId, + columnId == Columns::ColumnId_Particle ? ColumnBase::Display_Texture : ColumnBase::Display_Icon) { assert (this->mColumnId==Columns::ColumnId_Icon || @@ -2417,7 +2420,56 @@ namespace CSMWorld return true; } }; - + + template + struct TextureIndexColumn : public Column + { + TextureIndexColumn() + : Column (Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) + {} + + QVariant get (const Record& record) const + { + return record.get().mIndex; + } + + virtual bool isEditable() const + { + return false; + } + }; + + // TODO remove + template + struct PluginIndexColumn : public Column + { + PluginIndexColumn() + : Column (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer) + {} + + QVariant get (const Record& record) const + { + return -1; + } + + virtual bool isEditable() const + { + return false; + } + }; + + template<> + inline QVariant PluginIndexColumn::get (const Record& record) const + { + return record.get().mPlugin; + } + + template<> + inline QVariant PluginIndexColumn::get (const Record& record) const + { + return record.get().mPluginIndex; + } + struct BodyPartRaceColumn : public RaceColumn { const MeshTypeColumn *mMeshType; diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index aeee0d208..cec11211c 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -124,7 +124,7 @@ namespace CSMWorld { ColumnId_Portable, "Portable" }, { ColumnId_NegativeLight, "Negative Light" }, { ColumnId_EmitterType, "Emitter Type" }, - + { ColumnId_Fire, "Fire" }, { ColumnId_OffByDefault, "Off by default" }, { ColumnId_IsKey, "Is Key" }, @@ -330,6 +330,8 @@ namespace CSMWorld { ColumnId_WeatherChance, "Percent Chance" }, { ColumnId_Text, "Text" }, + { ColumnId_PluginIndex, "Plugin Index" }, + { ColumnId_TextureIndex, "Texture Index" }, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index b23d86367..1ff871c84 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -329,6 +329,9 @@ namespace CSMWorld ColumnId_Text = 297, + ColumnId_PluginIndex = 298, + ColumnId_TextureIndex = 299, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 007190e4a..456d2bccc 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -412,6 +412,18 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat Columns::ColumnId_NegativeLight, ESM::MagicEffect::NegativeLight)); mMagicEffects.addColumn (new DescriptionColumn); + mLand.addColumn (new StringIdColumn); + mLand.addColumn (new RecordStateColumn); + mLand.addColumn (new FixedRecordTypeColumn(UniversalId::Type_Land)); + mLand.addColumn (new PluginIndexColumn); + + mLandTextures.addColumn (new StringIdColumn); + mLandTextures.addColumn (new RecordStateColumn); + mLandTextures.addColumn (new FixedRecordTypeColumn(UniversalId::Type_LandTexture)); + mLandTextures.addColumn (new PluginIndexColumn); + mLandTextures.addColumn (new TextureIndexColumn); + mLandTextures.addColumn (new TextureColumn); + mPathgrids.addColumn (new StringIdColumn); mPathgrids.addColumn (new RecordStateColumn); mPathgrids.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Pathgrid)); @@ -531,6 +543,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat addModel (new IdTable (&mBodyParts), UniversalId::Type_BodyPart); addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); + addModel (new IdTable (&mLand), UniversalId::Type_Land); + addModel (new IdTable (&mLandTextures), UniversalId::Type_LandTexture); addModel (new IdTree (&mPathgrids, &mPathgrids), UniversalId::Type_Pathgrid); addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); addModel (new IdTree (&mReferenceables, &mReferenceables, IdTable::Feature_Preview), diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 77db2be10..38386f6da 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -53,6 +53,8 @@ namespace { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_RunLog, "Run Log", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_SoundGens, "Sound Generators", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", 0 }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Lands, "Lands", 0 }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_LandTextures, "LandTextures", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Meta Data Table", 0 }, @@ -118,6 +120,8 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_DebugProfile, "Debug Profile", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_SoundGen, "Sound Generator", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Land, "Land", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_LandTexture, "LandTexture", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Meta Data", 0 }, @@ -364,8 +368,8 @@ std::vector CSMWorld::UniversalId::listTypes (int c for (int i=0; sIndexArg[i].mName; ++i) if (sIndexArg[i].mClass & classes) list.push_back (sIndexArg[i].mType); - - return list; + + return list; } CSMWorld::UniversalId::Type CSMWorld::UniversalId::getParentType (Type type) diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index e9104fc22..accd1b78d 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -126,6 +126,10 @@ namespace CSMWorld Type_SoundGen, Type_MagicEffects, Type_MagicEffect, + Type_Lands, + Type_Land, + Type_LandTextures, + Type_LandTexture, Type_Pathgrids, Type_Pathgrid, Type_StartScripts, diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index dfbeea031..10de46e06 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -172,6 +172,16 @@ void CSVDoc::View::setupWorldMenu() setupShortcut("document-world-references", references); world->addAction (references); + QAction *lands = new QAction (tr ("Lands"), this); + connect (lands, SIGNAL (triggered()), this, SLOT (addLandsSubView())); + setupShortcut("document-world-lands", lands); + world->addAction (lands); + + QAction *landTextures = new QAction (tr ("Land Textures"), this); + connect (landTextures, SIGNAL (triggered()), this, SLOT (addLandTexturesSubView())); + setupShortcut("document-world-landtextures", landTextures); + world->addAction (landTextures); + QAction *grid = new QAction (tr ("Pathgrid"), this); connect (grid, SIGNAL (triggered()), this, SLOT (addPathgridSubView())); setupShortcut("document-world-pathgrid", grid); @@ -876,6 +886,16 @@ void CSVDoc::View::addRunLogSubView() addSubView (CSMWorld::UniversalId::Type_RunLog); } +void CSVDoc::View::addLandsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Lands); +} + +void CSVDoc::View::addLandTexturesSubView() +{ + addSubView (CSMWorld::UniversalId::Type_LandTextures); +} + void CSVDoc::View::addPathgridSubView() { addSubView (CSMWorld::UniversalId::Type_Pathgrids); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 834407be0..46aa87891 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -224,6 +224,10 @@ namespace CSVDoc void addRunLogSubView(); + void addLandsSubView(); + + void addLandTexturesSubView(); + void addPathgridSubView(); void addStartScriptsSubView(); diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 7c27bdf7a..b570397b7 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -43,6 +43,8 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Spells, CSMWorld::UniversalId::Type_Enchantments, CSMWorld::UniversalId::Type_SoundGens, + CSMWorld::UniversalId::Type_Lands, + CSMWorld::UniversalId::Type_LandTextures, CSMWorld::UniversalId::Type_None // end marker }; From 9e41f1340ae3b7bd9ee3a598b11d7fb479bc36e5 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 25 Aug 2017 19:51:30 -0400 Subject: [PATCH 002/505] Replace nonconst getId with setId, add template specialization and specialized derived classes for LandTexture --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/collection.hpp | 31 +++-- apps/opencs/model/world/columnimp.hpp | 43 ++++++- apps/opencs/model/world/columns.cpp | 1 + apps/opencs/model/world/columns.hpp | 5 +- apps/opencs/model/world/data.cpp | 5 +- apps/opencs/model/world/idtable.cpp | 31 +++++ apps/opencs/model/world/idtable.hpp | 15 +++ apps/opencs/model/world/landtexture.cpp | 17 +++ apps/opencs/model/world/landtexture.hpp | 5 + apps/opencs/view/world/landtexturecreator.cpp | 106 ++++++++++++++++++ apps/opencs/view/world/landtexturecreator.hpp | 49 ++++++++ apps/opencs/view/world/subviews.cpp | 15 ++- components/esm/loadltex.cpp | 2 +- components/esm/loadltex.hpp | 3 +- 15 files changed, 308 insertions(+), 22 deletions(-) create mode 100644 apps/opencs/view/world/landtexturecreator.cpp create mode 100644 apps/opencs/view/world/landtexturecreator.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0a146dc06..4207258db 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -70,7 +70,7 @@ opencs_units (view/world cellcreator pathgridcreator referenceablecreator startscriptcreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator - bodypartcreator + bodypartcreator landtexturecreator ) opencs_units_noqt (view/world diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 16f5ce51f..9d867ff93 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -13,8 +14,8 @@ #include #include "columnbase.hpp" - #include "collectionbase.hpp" +#include "landtexture.hpp" namespace CSMWorld { @@ -22,15 +23,14 @@ namespace CSMWorld template struct IdAccessor { - std::string& getId (ESXRecordT& record); - + void setId(ESXRecordT& record, const std::string& id) const; const std::string getId (const ESXRecordT& record) const; }; template - std::string& IdAccessor::getId (ESXRecordT& record) + void IdAccessor::setId(ESXRecordT& record, const std::string& id) const { - return record.mId; + record.mId = id; } template @@ -39,6 +39,23 @@ namespace CSMWorld return record.mId; } + template<> + inline void IdAccessor::setId (LandTexture& record, const std::string& id) const + { + int plugin = 0; + int index = 0; + + LandTexture::parseUniqueRecordId(id, plugin, index); + record.mPluginIndex = plugin; + record.mIndex = index; + } + + template<> + inline const std::string IdAccessor::getId (const LandTexture& record) const + { + return LandTexture::createUniqueRecordId(record.mPluginIndex, record.mIndex); + } + /// \brief Single-type record collection template > class Collection : public CollectionBase @@ -213,7 +230,7 @@ namespace CSMWorld Record copy; copy.mModified = getRecord(origin).get(); copy.mState = RecordBase::State_ModifiedOnly; - copy.get().mId = destination; + IdAccessorT().setId(copy.get(), destination); insertRecord(copy, getAppendIndex(destination, type)); } @@ -366,7 +383,7 @@ namespace CSMWorld UniversalId::Type type) { ESXRecordT record; - IdAccessorT().getId (record) = id; + IdAccessorT().setId(record, id); record.blank(); Record record2; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index a9a48ef0d..316fa4366 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -63,6 +63,13 @@ namespace CSMWorld } }; + template<> + inline QVariant StringIdColumn::get(const Record& record) const + { + const LandTexture& ltex = record.get(); + return QString::fromUtf8(std::string('L' + std::to_string(ltex.mPluginIndex) + '#' + std::to_string(ltex.mIndex)).c_str()); + } + template struct RecordStateColumn : public Column { @@ -2421,6 +2428,31 @@ namespace CSMWorld } }; + template + struct TextureHandleColumn : public Column + { + TextureHandleColumn() + : Column (Columns::ColumnId_TextureHandle, ColumnBase::Display_String) + {} + + QVariant get(const Record& record) const override + { + return QString::fromUtf8(record.get().mId.c_str()); + } + + void set(Record& record, const QVariant& data) override + { + ESXRecordT copy = record.get(); + copy.mId = data.toString().toUtf8().constData(); + record.setModified(copy); + } + + bool isEditable() const override + { + return true; + } + }; + template struct TextureIndexColumn : public Column { @@ -2428,31 +2460,30 @@ namespace CSMWorld : Column (Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) {} - QVariant get (const Record& record) const + QVariant get(const Record& record) const override { return record.get().mIndex; } - virtual bool isEditable() const + bool isEditable() const override { return false; } }; - // TODO remove template struct PluginIndexColumn : public Column { PluginIndexColumn() - : Column (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer) + : Column (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer,0) {} - QVariant get (const Record& record) const + QVariant get(const Record& record) const override { return -1; } - virtual bool isEditable() const + virtual bool isEditable() const override { return false; } diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index cec11211c..49935d40d 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -330,6 +330,7 @@ namespace CSMWorld { ColumnId_WeatherChance, "Percent Chance" }, { ColumnId_Text, "Text" }, + { ColumnId_TextureHandle, "Texture Handle" }, { ColumnId_PluginIndex, "Plugin Index" }, { ColumnId_TextureIndex, "Texture Index" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 1ff871c84..c6e2a2a41 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -329,8 +329,9 @@ namespace CSMWorld ColumnId_Text = 297, - ColumnId_PluginIndex = 298, - ColumnId_TextureIndex = 299, + ColumnId_TextureHandle = 298, + ColumnId_PluginIndex = 299, + ColumnId_TextureIndex = 300, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 456d2bccc..b0ab73de1 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -417,9 +417,10 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat mLand.addColumn (new FixedRecordTypeColumn(UniversalId::Type_Land)); mLand.addColumn (new PluginIndexColumn); - mLandTextures.addColumn (new StringIdColumn); + mLandTextures.addColumn (new StringIdColumn(true)); mLandTextures.addColumn (new RecordStateColumn); mLandTextures.addColumn (new FixedRecordTypeColumn(UniversalId::Type_LandTexture)); + mLandTextures.addColumn (new TextureHandleColumn); mLandTextures.addColumn (new PluginIndexColumn); mLandTextures.addColumn (new TextureIndexColumn); mLandTextures.addColumn (new TextureColumn); @@ -544,7 +545,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); addModel (new IdTable (&mLand), UniversalId::Type_Land); - addModel (new IdTable (&mLandTextures), UniversalId::Type_LandTexture); + addModel (new LandTextureIdTable (&mLandTextures), UniversalId::Type_LandTexture); addModel (new IdTree (&mPathgrids, &mPathgrids), UniversalId::Type_Pathgrid); addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); addModel (new IdTree (&mReferenceables, &mReferenceables, IdTable::Feature_Preview), diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 7975e05ea..078484aab 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -281,3 +281,34 @@ CSMWorld::CollectionBase *CSMWorld::IdTable::idCollection() const { return mIdCollection; } + +CSMWorld::LandTextureIdTable::LandTextureIdTable(CollectionBase* idCollection, unsigned int features) + : IdTable(idCollection, features) +{ +} + +QVariant CSMWorld::LandTextureIdTable::data(const QModelIndex& index, int role) const +{ + if (role==Qt::EditRole && !idCollection()->getRecord(index.row()).isModified()) + return QVariant(); + + return IdTable::data(index, role); +} + +bool CSMWorld::LandTextureIdTable::setData(const QModelIndex& index, const QVariant& value, int role) +{ + if (!idCollection()->getRecord(index.row()).isModified()) + return false; + else + return IdTable::setData(index, value, role); +} + +Qt::ItemFlags CSMWorld::LandTextureIdTable::flags(const QModelIndex& index) const +{ + Qt::ItemFlags flags = IdTable::flags(index); + + if (!idCollection()->getRecord(index.row()).isModified()) + flags &= ~Qt::ItemIsEditable; + + return flags; +} diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 9faf64d71..ecca269d3 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -93,6 +93,21 @@ namespace CSMWorld virtual CollectionBase *idCollection() const; }; + + /// An IdTable customized to handle the more unique needs of LandTextureId's which behave + /// differently from other records. + class LandTextureIdTable : public IdTable + { + public: + + LandTextureIdTable(CollectionBase* idCollection, unsigned int features=0); + + QVariant data(const QModelIndex& index, int role=Qt::DisplayRole) const override; + + bool setData(const QModelIndex& index, const QVariant& value, int role) override; + + Qt::ItemFlags flags (const QModelIndex & index) const override; + }; } #endif diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 266377d0f..4b82f8d73 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -1,5 +1,7 @@ #include "landtexture.hpp" +#include + #include namespace CSMWorld @@ -11,4 +13,19 @@ namespace CSMWorld mPluginIndex = esm.getIndex(); } + std::string LandTexture::createUniqueRecordId(int plugin, int index) + { + return 'L' + std::to_string(plugin) + '#' + std::to_string(index); + } + + void LandTexture::parseUniqueRecordId(const std::string& id, int& plugin, int& index) + { + size_t middle = id.find('#'); + + if (middle == std::string::npos || id[0] != 'L') + throw std::runtime_error("Invalid LandTexture ID"); + + plugin = std::stoi(id.substr(1,middle-1)); + index = std::stoi(id.substr(middle+1)); + } } diff --git a/apps/opencs/model/world/landtexture.hpp b/apps/opencs/model/world/landtexture.hpp index 91459eee2..a7376438c 100644 --- a/apps/opencs/model/world/landtexture.hpp +++ b/apps/opencs/model/world/landtexture.hpp @@ -13,6 +13,11 @@ namespace CSMWorld int mPluginIndex; void load (ESM::ESMReader &esm, bool &isDeleted); + + /// Returns a string identifier that will be unique to any LandTexture. + static std::string createUniqueRecordId(int plugin, int index); + /// Deconstructs a unique string identifier into plugin and index. + static void parseUniqueRecordId(const std::string& id, int& plugin, int& index); }; } diff --git a/apps/opencs/view/world/landtexturecreator.cpp b/apps/opencs/view/world/landtexturecreator.cpp new file mode 100644 index 000000000..f79c08427 --- /dev/null +++ b/apps/opencs/view/world/landtexturecreator.cpp @@ -0,0 +1,106 @@ +#include "landtexturecreator.hpp" + +#include +#include + +#include +#include +#include + +#include "../../model/world/commands.hpp" +#include "../../model/world/idtable.hpp" +#include "../../model/world/landtexture.hpp" + +namespace CSVWorld +{ + LandTextureCreator::LandTextureCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id) + : GenericCreator(data, undoStack, id) + { + // One index is reserved for a default texture + const size_t MaxIndex = std::numeric_limits::max() - 1; + + setManualEditing(false); + + QLabel* nameLabel = new QLabel("Name"); + insertBeforeButtons(nameLabel, false); + + mNameEdit = new QLineEdit(this); + insertBeforeButtons(mNameEdit, true); + + QLabel* indexLabel = new QLabel("Index"); + insertBeforeButtons(indexLabel, false); + + QIntValidator* indexValidator = new QIntValidator(0, MaxIndex, this); + + mIndexEdit = new QLineEdit(this); + mIndexEdit->setValidator(indexValidator); + insertBeforeButtons(mIndexEdit, true); + + connect(mNameEdit, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&))); + connect(mIndexEdit, SIGNAL(textChanged(const QString&)), this, SLOT(indexChanged(const QString&))); + } + + void LandTextureCreator::cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) + { + GenericCreator::cloneMode(originId, type); + + CSMWorld::IdTable& table = dynamic_cast(*getData().getTableModel(getCollectionId())); + + int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureHandle); + mNameEdit->setText((table.data(table.getModelIndex(originId, column)).toString())); + + column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureIndex); + mIndexEdit->setText((table.data(table.getModelIndex(originId, column)).toString())); + } + + void LandTextureCreator::focus() + { + mIndexEdit->setFocus(); + } + + void LandTextureCreator::reset() + { + GenericCreator::reset(); + mNameEdit->setText(""); + mIndexEdit->setText(""); + } + + std::string LandTextureCreator::getErrors() const + { + std::string id = getId(); + + // TODO empty index edit? + if (getData().getLandTextures().searchId(getId()) >= 0) + { + return "Index is already in use"; + } + + return ""; + } + + void LandTextureCreator::configureCreateCommand(CSMWorld::CreateCommand& command) const + { + GenericCreator::configureCreateCommand(command); + + CSMWorld::IdTable& table = dynamic_cast(*getData().getTableModel(getCollectionId())); + int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureHandle); + command.addValue(column, mName.c_str()); + } + + std::string LandTextureCreator::getId() const + { + return CSMWorld::LandTexture::createUniqueRecordId(0, mIndex); + } + + void LandTextureCreator::nameChanged(const QString& value) + { + mName = value.toUtf8().constData(); + update(); + } + + void LandTextureCreator::indexChanged(const QString& value) + { + mIndex = value.toInt(); + update(); + } +} diff --git a/apps/opencs/view/world/landtexturecreator.hpp b/apps/opencs/view/world/landtexturecreator.hpp new file mode 100644 index 000000000..46388bf03 --- /dev/null +++ b/apps/opencs/view/world/landtexturecreator.hpp @@ -0,0 +1,49 @@ +#ifndef CSV_WORLD_LANDTEXTURECREATOR_H +#define CSV_WORLD_LANDTEXTURECREATOR_H + +#include + +#include "genericcreator.hpp" + +class QLineEdit; + +namespace CSVWorld +{ + class LandTextureCreator : public GenericCreator + { + Q_OBJECT + + public: + + LandTextureCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id); + + void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) override; + + void focus() override; + + void reset() override; + + std::string getErrors() const override; + + protected: + + void configureCreateCommand(CSMWorld::CreateCommand& command) const override; + + std::string getId() const override; + + private slots: + + void nameChanged(const QString& val); + void indexChanged(const QString& val); + + private: + + QLineEdit* mNameEdit; + QLineEdit* mIndexEdit; + + std::string mName; + int mIndex; + }; +} + +#endif diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index b570397b7..a33802823 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -18,6 +18,7 @@ #include "pathgridcreator.hpp" #include "previewsubview.hpp" #include "bodypartcreator.hpp" +#include "landtexturecreator.hpp" void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) { @@ -43,8 +44,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Spells, CSMWorld::UniversalId::Type_Enchantments, CSMWorld::UniversalId::Type_SoundGens, - CSMWorld::UniversalId::Type_Lands, - CSMWorld::UniversalId::Type_LandTextures, CSMWorld::UniversalId::Type_None // end marker }; @@ -83,6 +82,12 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Pathgrids, new CSVDoc::SubViewFactoryWithCreator); + manager.add (CSMWorld::UniversalId::Type_Lands, + new CSVDoc::SubViewFactoryWithCreator >); + + manager.add (CSMWorld::UniversalId::Type_LandTextures, + new CSVDoc::SubViewFactoryWithCreator >); + manager.add (CSMWorld::UniversalId::Type_Globals, new CSVDoc::SubViewFactoryWithCreator >); @@ -183,6 +188,12 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Pathgrid, new CSVDoc::SubViewFactoryWithCreator (false)); + manager.add (CSMWorld::UniversalId::Type_Land, + new CSVDoc::SubViewFactoryWithCreator >(false)); + + manager.add (CSMWorld::UniversalId::Type_LandTexture, + new CSVDoc::SubViewFactoryWithCreator >(false)); + manager.add (CSMWorld::UniversalId::Type_DebugProfile, new CSVDoc::SubViewFactoryWithCreator > (false)); diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index 613b706e3..3e150f9c0 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -59,7 +59,7 @@ namespace ESM void LandTexture::blank() { + mId.clear(); mTexture.clear(); - mIndex = -1; } } diff --git a/components/esm/loadltex.hpp b/components/esm/loadltex.hpp index 2cb5abf0c..1604e9281 100644 --- a/components/esm/loadltex.hpp +++ b/components/esm/loadltex.hpp @@ -31,14 +31,15 @@ struct LandTexture /// Return a string descriptor for this record type. Currently used for debugging / error logs only. static std::string getRecordType() { return "LandTexture"; } + // mId is merely a user friendly name for the texture in the editor. std::string mId, mTexture; int mIndex; void load(ESMReader &esm, bool &isDeleted); void save(ESMWriter &esm, bool isDeleted = false) const; + /// Sets the record to the default state. Does not touch the index. Does touch mID. void blank(); - ///< Set record to default state (does not touch the ID). }; } #endif From 1d480015b46f78f747642d2d7b3b381b161119c9 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Thu, 31 Aug 2017 22:01:38 -0400 Subject: [PATCH 003/505] Add ability to touch records, LAND records in particular --- apps/opencs/model/world/collection.hpp | 23 ++++++++++++ apps/opencs/model/world/collectionbase.hpp | 2 ++ apps/opencs/model/world/columnimp.hpp | 2 +- apps/opencs/model/world/commands.cpp | 25 +++++++++++++ apps/opencs/model/world/commands.hpp | 19 ++++++++++ apps/opencs/model/world/data.cpp | 2 +- apps/opencs/model/world/idtable.cpp | 20 +++++++++++ apps/opencs/model/world/idtable.hpp | 5 +++ apps/opencs/model/world/idtablebase.hpp | 6 ++-- apps/opencs/model/world/refidcollection.cpp | 6 ++++ apps/opencs/model/world/refidcollection.hpp | 2 ++ apps/opencs/view/world/table.cpp | 40 +++++++++++++++++++-- apps/opencs/view/world/table.hpp | 3 ++ 13 files changed, 149 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 9d867ff93..f69d06d78 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -125,6 +125,10 @@ namespace CSMWorld const std::string& destination, const UniversalId::Type type); + virtual bool touchRecord(const std::string& id); + ///< Change the state of a record from base to modified, if it is not already. + /// \return True if the record was changed. + virtual int searchId (const std::string& id) const; ////< Search record with \a id. /// \return index of record (if found) or -1 (not found) @@ -235,6 +239,25 @@ namespace CSMWorld insertRecord(copy, getAppendIndex(destination, type)); } + template + bool Collection::touchRecord(const std::string& id) + { + int index = getIndex(id); + Record& record = mRecords.at(index); + if (record.isDeleted()) + { + throw std::runtime_error("attempt to touch deleted record"); + } + + if (!record.isModified() && !record.isDeleted() && !record.isErased()) + { + record.setModified(record.get()); + return true; + } + else + return false; + } + template Collection::Collection() {} diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index ef826e31c..bac790c5d 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -78,6 +78,8 @@ namespace CSMWorld const std::string& destination, const UniversalId::Type type) = 0; + virtual bool touchRecord(const std::string& id) = 0; + virtual const RecordBase& getRecord (const std::string& id) const = 0; virtual const RecordBase& getRecord (int index) const = 0; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 316fa4366..92e899a45 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -67,7 +67,7 @@ namespace CSMWorld inline QVariant StringIdColumn::get(const Record& record) const { const LandTexture& ltex = record.get(); - return QString::fromUtf8(std::string('L' + std::to_string(ltex.mPluginIndex) + '#' + std::to_string(ltex.mIndex)).c_str()); + return QString(LandTexture::createUniqueRecordId(ltex.mPluginIndex, ltex.mIndex).c_str()); } template diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 5f9422376..c6a56f7b8 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -15,6 +15,31 @@ #include "nestedtablewrapper.hpp" #include "pathgrid.hpp" +CSMWorld::TouchCommand::TouchCommand(IdTable& table, const std::string& id, QUndoCommand* parent) + : QUndoCommand(parent) + , mTable(table) + , mId(id) + , mOld(nullptr) + , mChanged(false) +{ + setText(("Touch " + mId).c_str()); + mOld.reset(mTable.getRecord(mId).clone()); +} + +void CSMWorld::TouchCommand::redo() +{ + mChanged = mTable.touchRecord(mId); +} + +void CSMWorld::TouchCommand::undo() +{ + if (mChanged) + { + mTable.setRecord(mId, *mOld); + mChanged = false; + } +} + CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand* parent) : QUndoCommand (parent), mModel (&model), mIndex (index), mNew (new_), mHasRecordState(false), mOldRecordState(CSMWorld::RecordBase::State_BaseOnly) diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index b54a1d5ac..4c9be7e8a 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -24,6 +25,24 @@ namespace CSMWorld struct RecordBase; struct NestedTableWrapperBase; + class TouchCommand : public QUndoCommand + { + public: + + TouchCommand(IdTable& model, const std::string& id, QUndoCommand* parent=nullptr); + + virtual void redo(); + virtual void undo(); + + private: + + IdTable& mTable; + std::string mId; + std::unique_ptr mOld; + + bool mChanged; + }; + class ModifyCommand : public QUndoCommand { QAbstractItemModel *mModel; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index b0ab73de1..27a914aeb 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -544,7 +544,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat addModel (new IdTable (&mBodyParts), UniversalId::Type_BodyPart); addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); - addModel (new IdTable (&mLand), UniversalId::Type_Land); + addModel (new IdTable (&mLand, IdTable::Feature_AllowTouch), UniversalId::Type_Land); addModel (new LandTextureIdTable (&mLandTextures), UniversalId::Type_LandTexture); addModel (new IdTree (&mPathgrids, &mPathgrids), UniversalId::Type_Pathgrid); addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 078484aab..94eab3fc3 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -179,6 +179,26 @@ void CSMWorld::IdTable::cloneRecord(const std::string& origin, endInsertRows(); } +bool CSMWorld::IdTable::touchRecord(const std::string& id) +{ + bool changed = mIdCollection->touchRecord(id); + + int row = mIdCollection->getIndex(id); + int column = mIdCollection->searchColumnIndex(Columns::ColumnId_RecordType); + if (changed && column != -1) + { + QModelIndex modelIndex = index(row, column); + emit dataChanged(modelIndex, modelIndex); + } + + return changed; +} + +std::string CSMWorld::IdTable::getId(int row) const +{ + return mIdCollection->getId(row); +} + ///This method can return only indexes to the top level table cells QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const { diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index ecca269d3..5e5f9da4a 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -61,6 +61,11 @@ namespace CSMWorld const std::string& destination, UniversalId::Type type = UniversalId::Type_None); + bool touchRecord(const std::string& id); + ///< Will change the record state to modified, if it is not already. + + std::string getId(int row) const; + virtual QModelIndex getModelIndex (const std::string& id, int column) const; void setRecord (const std::string& id, const RecordBase& record, diff --git a/apps/opencs/model/world/idtablebase.hpp b/apps/opencs/model/world/idtablebase.hpp index 0d77d48ef..8b82f984b 100644 --- a/apps/opencs/model/world/idtablebase.hpp +++ b/apps/opencs/model/world/idtablebase.hpp @@ -32,7 +32,9 @@ namespace CSMWorld Feature_Preview = 8, /// Table can not be modified through ordinary means. - Feature_Constant = 16 + Feature_Constant = 16, + + Feature_AllowTouch = 32 }; private: @@ -61,7 +63,7 @@ namespace CSMWorld virtual bool isDeleted (const std::string& id) const = 0; virtual int getColumnId (int column) const = 0; - + unsigned int getFeatures() const; }; } diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 31dae256e..44a6ce07d 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -813,6 +813,12 @@ void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin, mData.insertRecord(*newRecord, type, destination); } +bool CSMWorld::RefIdCollection::touchRecord(const std::string& id) +{ + throw std::runtime_error("RefIdCollection::touchRecord is unimplemented"); + return false; +} + void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record, UniversalId::Type type) { diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index de5a709c6..48558d1c2 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -80,6 +80,8 @@ namespace CSMWorld const std::string& destination, const UniversalId::Type type); + virtual bool touchRecord(const std::string& id); + virtual void appendBlankRecord (const std::string& id, UniversalId::Type type); ///< \param type Will be ignored, unless the collection supports multiple record types diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 30dba4241..580d27a24 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -60,6 +60,9 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) menu.addAction(mCloneAction); } + if (mTouchAction) + menu.addAction (mTouchAction); + if (mCreateAction) menu.addAction (mCreateAction); @@ -226,8 +229,8 @@ void CSVWorld::Table::mouseDoubleClickEvent (QMouseEvent *event) CSVWorld::Table::Table (const CSMWorld::UniversalId& id, bool createAndDelete, bool sorting, CSMDoc::Document& document) -: DragRecordTable(document), mCreateAction (0), - mCloneAction(0), mRecordStatusDisplay (0), mJumpToAddedRecord(false), mUnselectAfterJump(false) + : DragRecordTable(document), mCreateAction (nullptr), mCloneAction(nullptr), mTouchAction(nullptr), + mRecordStatusDisplay (0), mJumpToAddedRecord(false), mUnselectAfterJump(false) { mModel = &dynamic_cast (*mDocument.getData().getTableModel (id)); @@ -302,6 +305,15 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, cloneShortcut->associateAction(mCloneAction); } + if (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_AllowTouch) + { + mTouchAction = new QAction(tr("Touch Record"), this); + connect(mTouchAction, SIGNAL(triggered()), this, SLOT(touchRecord())); + addAction(mTouchAction); + CSMPrefs::Shortcut* touchShortcut = new CSMPrefs::Shortcut("table-touch", this); + touchShortcut->associateAction(mTouchAction); + } + mRevertAction = new QAction (tr ("Revert Record"), this); connect (mRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeRevert())); addAction (mRevertAction); @@ -442,6 +454,30 @@ void CSVWorld::Table::cloneRecord() } } +void CSVWorld::Table::touchRecord() +{ + if (!mEditLock && mModel->getFeatures() & CSMWorld::IdTableBase::Feature_AllowTouch) + { + if (CSMWorld::IdTable* table = dynamic_cast(mModel)) + { + QUndoCommand* touchRecords = new QUndoCommand(); + touchRecords->setText("Touch records"); + + QModelIndexList selectedRows = selectionModel()->selectedRows(); + for (auto it = selectedRows.begin(); it != selectedRows.end(); ++it) + { + QModelIndex index = mProxyModel->mapToSource(mProxyModel->index(it->row(),0)); + std::string id = table->getId(index.row()); + + // command is a child of touchRecords + QUndoCommand* command = new CSMWorld::TouchCommand(*table, id, touchRecords); + } + + mDocument.getUndoStack().push(touchRecords); + } + } +} + void CSVWorld::Table::moveUpRecord() { if (mEditLock || (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant)) diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 26f6e7899..d6fa17ef9 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -56,6 +56,7 @@ namespace CSVWorld QAction *mEditAction; QAction *mCreateAction; QAction *mCloneAction; + QAction *mTouchAction; QAction *mRevertAction; QAction *mDeleteAction; QAction *mMoveUpAction; @@ -129,6 +130,8 @@ namespace CSVWorld void cloneRecord(); + void touchRecord(); + void moveUpRecord(); void moveDownRecord(); From 51c7efa3f3f0b407bcf6a34c61a86e675d2d7aed Mon Sep 17 00:00:00 2001 From: John Date: Fri, 1 Sep 2017 12:36:41 +0200 Subject: [PATCH 004/505] [CMake] CMake fix install --- CMakeLists.txt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f6889515..6424346bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -397,13 +397,16 @@ IF(NOT WIN32 AND NOT APPLE) # Install binaries IF(BUILD_OPENMW) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" ) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/tes3mp" DESTINATION "${BINDIR}" ) ENDIF(BUILD_OPENMW) + IF(BUILD_OPENMW_MP) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/tes3mp-server" DESTINATION "${BINDIR}") + ENDIF(BUILD_OPENMW_MP) IF(BUILD_LAUNCHER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-launcher" DESTINATION "${BINDIR}" ) ENDIF(BUILD_LAUNCHER) IF(BUILD_BROWSER) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-browser" DESTINATION "${BINDIR}" ) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/tes3mp-browser" DESTINATION "${BINDIR}" ) ENDIF(BUILD_BROWSER) IF(BUILD_BSATOOL) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" ) @@ -448,10 +451,11 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(FILES "${OpenMW_BINARY_DIR}/resources/version" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-client-default" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-client.install" DESTINATION "${SYSCONFDIR}" RENAME "tes3mp-client.cfg" COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-server-default" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw-mp") - INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-server.install" DESTINATION "${SYSCONFDIR}" RENAME "tes3mp-server.cfg" COMPONENT "openmw-mp") + INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-client-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") + #INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-client.install" DESTINATION "${SYSCONFDIR}" RENAME "tes3mp-client.cfg" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-server-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw-mp") + #INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-server.install" DESTINATION "${SYSCONFDIR}" RENAME "tes3mp-server.cfg" COMPONENT "openmw-mp") + #They both do not exist IF(BUILD_OPENCS) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs") From 30ba1d4c2599822730c5e6a204d383517c3206ed Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 3 Sep 2017 16:41:54 -0400 Subject: [PATCH 005/505] Move touch command to creator, to allow customization and not break abstraction --- apps/opencs/view/world/creator.hpp | 3 +++ apps/opencs/view/world/genericcreator.cpp | 17 +++++++++++++++++ apps/opencs/view/world/genericcreator.hpp | 2 ++ apps/opencs/view/world/table.cpp | 22 +++++++--------------- apps/opencs/view/world/table.hpp | 2 ++ apps/opencs/view/world/tablebottombox.cpp | 11 ++++++++--- apps/opencs/view/world/tablebottombox.hpp | 1 + apps/opencs/view/world/tablesubview.cpp | 3 +++ 8 files changed, 43 insertions(+), 18 deletions(-) diff --git a/apps/opencs/view/world/creator.hpp b/apps/opencs/view/world/creator.hpp index 320bbf6ae..0020fd3c8 100644 --- a/apps/opencs/view/world/creator.hpp +++ b/apps/opencs/view/world/creator.hpp @@ -31,6 +31,9 @@ namespace CSVWorld virtual void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) = 0; + /// Touches a record, if the creator supports it. + virtual void touch(const std::vector& ids) = 0; + virtual void setEditLock (bool locked) = 0; virtual void toggleWidgets(bool active = true) = 0; diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index bf4c4967f..bde523a09 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -254,6 +254,23 @@ void CSVWorld::GenericCreator::cloneMode(const std::string& originId, mClonedType = type; } +void CSVWorld::GenericCreator::touch(const std::vector& ids) +{ + // Combine multiple touch commands into one "macro" command + std::unique_ptr macro(new QUndoCommand()); + macro->setText("Touch records"); + + CSMWorld::IdTable& table = dynamic_cast(*mData.getTableModel(mListId)); + for (const CSMWorld::UniversalId& uid : ids) + { + // This is not leaked, touchCmd is a child of macro and managed by Qt + CSMWorld::TouchCommand* touchCmd = new CSMWorld::TouchCommand(table, uid.getId(), macro.get()); + } + + // Execute + mUndoStack.push(macro.release()); +} + void CSVWorld::GenericCreator::toggleWidgets(bool active) { } diff --git a/apps/opencs/view/world/genericcreator.hpp b/apps/opencs/view/world/genericcreator.hpp index 60d487bc1..d708c1047 100644 --- a/apps/opencs/view/world/genericcreator.hpp +++ b/apps/opencs/view/world/genericcreator.hpp @@ -103,6 +103,8 @@ namespace CSVWorld virtual void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type); + virtual void touch(const std::vector& ids); + virtual std::string getErrors() const; ///< Return formatted error descriptions for the current state of the creator. if an empty /// string is returned, there is no error. diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 580d27a24..3cccaaa22 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -458,23 +458,15 @@ void CSVWorld::Table::touchRecord() { if (!mEditLock && mModel->getFeatures() & CSMWorld::IdTableBase::Feature_AllowTouch) { - if (CSMWorld::IdTable* table = dynamic_cast(mModel)) - { - QUndoCommand* touchRecords = new QUndoCommand(); - touchRecords->setText("Touch records"); - - QModelIndexList selectedRows = selectionModel()->selectedRows(); - for (auto it = selectedRows.begin(); it != selectedRows.end(); ++it) - { - QModelIndex index = mProxyModel->mapToSource(mProxyModel->index(it->row(),0)); - std::string id = table->getId(index.row()); - - // command is a child of touchRecords - QUndoCommand* command = new CSMWorld::TouchCommand(*table, id, touchRecords); - } + std::vector touchIds; - mDocument.getUndoStack().push(touchRecords); + QModelIndexList selectedRows = selectionModel()->selectedRows(); + for (auto it = selectedRows.begin(); it != selectedRows.end(); ++it) + { + touchIds.push_back(getUniversalId(it->row())); } + + emit touchRequest(touchIds); } } diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index d6fa17ef9..02f9023e7 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -116,6 +116,8 @@ namespace CSVWorld void cloneRequest(const CSMWorld::UniversalId&); + void touchRequest(const std::vector& ids); + void closeRequest(); void extendedDeleteConfigRequest(const std::vector &selectedIds); diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index 5a25bbc53..cfde5c694 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -72,9 +72,9 @@ void CSVWorld::TableBottomBox::extendedConfigRequest(CSVWorld::ExtendedCommandCo mExtendedConfigurator->setFocus(); } -CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, - CSMDoc::Document& document, - const CSMWorld::UniversalId& id, +CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, + CSMDoc::Document& document, + const CSMWorld::UniversalId& id, QWidget *parent) : QWidget (parent), mShowStatusBar (false), mEditMode(EditMode_None), mHasPosition(false), mRow(0), mColumn(0) { @@ -249,6 +249,11 @@ void CSVWorld::TableBottomBox::cloneRequest(const std::string& id, mCreator->focus(); } +void CSVWorld::TableBottomBox::touchRequest(const std::vector& ids) +{ + mCreator->touch(ids); +} + void CSVWorld::TableBottomBox::extendedDeleteConfigRequest(const std::vector &selectedIds) { extendedConfigRequest(ExtendedCommandConfigurator::Mode_Delete, selectedIds); diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index 781cccc9e..5402c466e 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -102,6 +102,7 @@ namespace CSVWorld void createRequest(); void cloneRequest(const std::string& id, const CSMWorld::UniversalId::Type type); + void touchRequest(const std::vector&); void extendedDeleteConfigRequest(const std::vector &selectedIds); void extendedRevertConfigRequest(const std::vector &selectedIds); diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 6664a3771..12e29995d 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -69,6 +69,9 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D connect (this, SIGNAL(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type)), mBottom, SLOT(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type))); + connect (mTable, SIGNAL(touchRequest(const std::vector&)), + mBottom, SLOT(touchRequest(const std::vector&))); + connect (mTable, SIGNAL(extendedDeleteConfigRequest(const std::vector &)), mBottom, SLOT(extendedDeleteConfigRequest(const std::vector &))); connect (mTable, SIGNAL(extendedRevertConfigRequest(const std::vector &)), From 7cc95a11a47721cd9c3f70d6acf9b0d595f576ba Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 3 Sep 2017 20:00:19 -0400 Subject: [PATCH 006/505] Add more land table columns --- apps/opencs/model/world/columnimp.cpp | 234 ++++++++++++++++++++++++-- apps/opencs/model/world/columnimp.hpp | 45 +++++ apps/opencs/model/world/columns.hpp | 5 + apps/opencs/model/world/data.cpp | 5 + components/esm/loadland.hpp | 4 +- 5 files changed, 274 insertions(+), 19 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index dc3d39edb..65d2fecd2 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -1,28 +1,226 @@ #include "columnimp.hpp" -CSMWorld::BodyPartRaceColumn::BodyPartRaceColumn(const MeshTypeColumn *meshType) - : mMeshType(meshType) -{} - -QVariant CSMWorld::BodyPartRaceColumn::get(const Record &record) const +namespace CSMWorld { - if (mMeshType != NULL && mMeshType->get(record) == ESM::BodyPart::MT_Skin) + /* LandMapLodColumn */ + LandMapLodColumn::LandMapLodColumn() + : Column(Columns::ColumnId_LandMapLodIndex, ColumnBase::Display_String, 0) { - return QString::fromUtf8(record.get().mRace.c_str()); } - return QVariant(QVariant::UserType); -} -void CSMWorld::BodyPartRaceColumn::set(Record &record, const QVariant &data) -{ - ESM::BodyPart record2 = record.get(); + QVariant LandMapLodColumn::get(const Record& record) const + { + // Note: original data is signed + const char* rawData = reinterpret_cast(&record.get().mWnam[0]); + return QByteArray(rawData, Land::LAND_GLOBAL_MAP_LOD_SIZE); + } + + void LandMapLodColumn::set(Record& record, const QVariant& data) + { + Land copy = record.get(); + QByteArray array = data.toByteArray(); + const signed char* rawData = reinterpret_cast(array.data()); - record2.mRace = data.toString().toUtf8().constData(); + assert (array.count() == Land::LAND_GLOBAL_MAP_LOD_SIZE); - record.setModified(record2); -} + for (int i = 0; i < array.count(); ++i) + { + copy.mWnam[i] = rawData[i]; + } -bool CSMWorld::BodyPartRaceColumn::isEditable() const -{ - return true; + record.setModified(copy); + } + + bool LandMapLodColumn::isEditable() const + { + return true; + } + + /* LandNormalsColumn */ + LandNormalsColumn::LandNormalsColumn() + : Column(Columns::ColumnId_LandNormalsIndex, ColumnBase::Display_String, 0) + { + } + + QVariant LandNormalsColumn::get(const Record& record) const + { + const Land::LandData* landData = record.get().getLandData(); + assert(landData); + + // Note: original data is signed + const char* rawData = reinterpret_cast(&landData->mNormals[0]); + return QByteArray(rawData, Land::LAND_NUM_VERTS * 3); + } + + void LandNormalsColumn::set(Record& record, const QVariant& data) + { + Land copy = record.get(); + Land::LandData* landData = copy.getLandData(); + assert (landData); + + QByteArray array = data.toByteArray(); + const signed char* rawData = reinterpret_cast(array.data()); + + assert (array.count() == Land::LAND_NUM_VERTS * 3); + + for (int i = 0; i < array.count(); ++i) + { + landData->mNormals[i] = rawData[i]; + } + + record.setModified(copy); + } + + bool LandNormalsColumn::isEditable() const + { + return true; + } + + /* LandHeightsColumn */ + LandHeightsColumn::LandHeightsColumn() + : Column(Columns::ColumnId_LandHeightsIndex, ColumnBase::Display_String, 0) + { + } + + QVariant LandHeightsColumn::get(const Record& record) const + { + const Land::LandData* landData = record.get().getLandData(); + assert(landData); + + // Note: original data is float + const char* rawData = reinterpret_cast(&landData->mHeights[0]); + return QByteArray(rawData, Land::LAND_NUM_VERTS * sizeof(float)); + } + + void LandHeightsColumn::set(Record& record, const QVariant& data) + { + Land copy = record.get(); + Land::LandData* landData = copy.getLandData(); + assert (landData); + + QByteArray array = data.toByteArray(); + const float* rawData = reinterpret_cast(array.data()); + + assert (array.count() == Land::LAND_NUM_VERTS * sizeof(float)); + + for (int i = 0; i < array.count(); ++i) + { + landData->mHeights[i] = rawData[i]; + } + + record.setModified(copy); + } + + bool LandHeightsColumn::isEditable() const + { + return true; + } + + /* LandColoursColumn */ + LandColoursColumn::LandColoursColumn() + : Column(Columns::ColumnId_LandColoursIndex, ColumnBase::Display_String, 0) + { + } + + QVariant LandColoursColumn::get(const Record& record) const + { + const Land::LandData* landData = record.get().getLandData(); + assert(landData); + + // Note: original data is unsigned char + const char* rawData = reinterpret_cast(&landData->mColours[0]); + return QByteArray(rawData, Land::LAND_NUM_VERTS * 3); + } + + void LandColoursColumn::set(Record& record, const QVariant& data) + { + Land copy = record.get(); + Land::LandData* landData = copy.getLandData(); + assert (landData); + + QByteArray array = data.toByteArray(); + const unsigned char* rawData = reinterpret_cast(array.data()); + + assert (array.count() == Land::LAND_NUM_VERTS * 3); + + for (int i = 0; i < array.count(); ++i) + { + landData->mColours[i] = rawData[i]; + } + + record.setModified(copy); + } + + bool LandColoursColumn::isEditable() const + { + return true; + } + + /* LandTexturesColumn */ + LandTexturesColumn::LandTexturesColumn() + : Column(Columns::ColumnId_LandTexturesIndex, ColumnBase::Display_String, 0) + { + } + + QVariant LandTexturesColumn::get(const Record& record) const + { + const Land::LandData* landData = record.get().getLandData(); + assert(landData); + + // Note: original data is uint16_t + const char* rawData = reinterpret_cast(&landData->mTextures[0]); + return QByteArray(rawData, Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); + } + + void LandTexturesColumn::set(Record& record, const QVariant& data) + { + Land copy = record.get(); + Land::LandData* landData = copy.getLandData(); + assert (landData); + + QByteArray array = data.toByteArray(); + const uint16_t* rawData = reinterpret_cast(array.data()); + + assert (array.count() == Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); + + for (int i = 0; i < array.count(); ++i) + { + landData->mTextures[i] = rawData[i]; + } + + record.setModified(copy); + } + + bool LandTexturesColumn::isEditable() const + { + return true; + } + + /* BodyPartRaceColumn */ + BodyPartRaceColumn::BodyPartRaceColumn(const MeshTypeColumn *meshType) + : mMeshType(meshType) + {} + + QVariant BodyPartRaceColumn::get(const Record &record) const + { + if (mMeshType != NULL && mMeshType->get(record) == ESM::BodyPart::MT_Skin) + { + return QString::fromUtf8(record.get().mRace.c_str()); + } + return QVariant(QVariant::UserType); + } + + void BodyPartRaceColumn::set(Record &record, const QVariant &data) + { + ESM::BodyPart record2 = record.get(); + + record2.mRace = data.toString().toUtf8().constData(); + + record.setModified(record2); + } + + bool BodyPartRaceColumn::isEditable() const + { + return true; + } } diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 92e899a45..f58a35bc4 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2501,6 +2501,51 @@ namespace CSMWorld return record.get().mPluginIndex; } + struct LandMapLodColumn : public Column + { + LandMapLodColumn(); + + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; + }; + + struct LandNormalsColumn : public Column + { + LandNormalsColumn(); + + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; + }; + + struct LandHeightsColumn : public Column + { + LandHeightsColumn(); + + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; + }; + + struct LandColoursColumn : public Column + { + LandColoursColumn(); + + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; + }; + + struct LandTexturesColumn : public Column + { + LandTexturesColumn(); + + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; + }; + struct BodyPartRaceColumn : public RaceColumn { const MeshTypeColumn *mMeshType; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index c6e2a2a41..432597105 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -332,6 +332,11 @@ namespace CSMWorld ColumnId_TextureHandle = 298, ColumnId_PluginIndex = 299, ColumnId_TextureIndex = 300, + ColumnId_LandMapLodIndex = 301, + ColumnId_LandNormalsIndex = 302, + ColumnId_LandHeightsIndex = 303, + ColumnId_LandColoursIndex = 304, + ColumnId_LandTexturesIndex = 305, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 27a914aeb..3284d9b05 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -416,6 +416,11 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat mLand.addColumn (new RecordStateColumn); mLand.addColumn (new FixedRecordTypeColumn(UniversalId::Type_Land)); mLand.addColumn (new PluginIndexColumn); + mLand.addColumn (new LandMapLodColumn); + mLand.addColumn (new LandNormalsColumn); + mLand.addColumn (new LandHeightsColumn); + mLand.addColumn (new LandColoursColumn); + mLand.addColumn (new LandTexturesColumn); mLandTextures.addColumn (new StringIdColumn(true)); mLandTextures.addColumn (new RecordStateColumn); diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 9f33c37da..a7b97a465 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -64,6 +64,8 @@ struct Land //total number of textures per land static const int LAND_NUM_TEXTURES = LAND_TEXTURE_SIZE * LAND_TEXTURE_SIZE; + static const int LAND_GLOBAL_MAP_LOD_SIZE = 81; + #pragma pack(push,1) struct VHGT { @@ -109,7 +111,7 @@ struct Land }; // low-LOD heightmap (used for rendering the global map) - signed char mWnam[81]; + signed char mWnam[LAND_GLOBAL_MAP_LOD_SIZE]; void load(ESMReader &esm, bool &isDeleted); void save(ESMWriter &esm, bool isDeleted = false) const; From 90c485104a8e13e9f1e876b40b7b1b539bf73c9f Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 4 Sep 2017 01:06:58 -0400 Subject: [PATCH 007/505] Land creator --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/collection.hpp | 86 ++++++++++++++++++++++---- apps/opencs/model/world/land.cpp | 20 +++++- apps/opencs/model/world/land.hpp | 3 + apps/opencs/view/world/landcreator.cpp | 79 +++++++++++++++++++++++ apps/opencs/view/world/landcreator.hpp | 42 +++++++++++++ apps/opencs/view/world/subviews.cpp | 5 +- 7 files changed, 220 insertions(+), 17 deletions(-) create mode 100644 apps/opencs/view/world/landcreator.cpp create mode 100644 apps/opencs/view/world/landcreator.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 4207258db..36ff8cf67 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -70,7 +70,7 @@ opencs_units (view/world cellcreator pathgridcreator referenceablecreator startscriptcreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator - bodypartcreator landtexturecreator + bodypartcreator landtexturecreator landcreator ) opencs_units_noqt (view/world diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index f69d06d78..fccbebd43 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -15,6 +15,7 @@ #include "columnbase.hpp" #include "collectionbase.hpp" +#include "land.hpp" #include "landtexture.hpp" namespace CSMWorld @@ -39,6 +40,18 @@ namespace CSMWorld return record.mId; } + template<> + inline void IdAccessor::setId (Land& record, const std::string& id) const + { + int x=0, y=0; + + Land::parseUniqueRecordId(id, x, y); + record.mX = x; + record.mY = y; + // TODO check for uses of mId and remove them + record.mId = id; + } + template<> inline void IdAccessor::setId (LandTexture& record, const std::string& id) const { @@ -50,6 +63,12 @@ namespace CSMWorld record.mIndex = index; } + template<> + inline const std::string IdAccessor::getId (const Land& record) const + { + return Land::createUniqueRecordId(record.mX, record.mY); + } + template<> inline const std::string IdAccessor::getId (const LandTexture& record) const { @@ -86,6 +105,13 @@ namespace CSMWorld /// /// \return Success? + int cloneRecordImp (const std::string& origin, const std::string& dest, + UniversalId::Type type); + ///< Returns the index of the clone. + + int touchRecordImp (const std::string& id); + ///< Returns the index of the record on success, -1 on failure. + public: Collection(); @@ -227,20 +253,22 @@ namespace CSMWorld } template - void Collection::cloneRecord(const std::string& origin, - const std::string& destination, - const UniversalId::Type type) + int Collection::cloneRecordImp(const std::string& origin, + const std::string& destination, UniversalId::Type type) { - Record copy; - copy.mModified = getRecord(origin).get(); - copy.mState = RecordBase::State_ModifiedOnly; - IdAccessorT().setId(copy.get(), destination); + Record copy; + copy.mModified = getRecord(origin).get(); + copy.mState = RecordBase::State_ModifiedOnly; + IdAccessorT().setId(copy.get(), destination); - insertRecord(copy, getAppendIndex(destination, type)); + int index = getAppendIndex(destination, type); + insertRecord(copy, getAppendIndex(destination, type)); + + return index; } template - bool Collection::touchRecord(const std::string& id) + int Collection::touchRecordImp(const std::string& id) { int index = getIndex(id); Record& record = mRecords.at(index); @@ -249,13 +277,47 @@ namespace CSMWorld throw std::runtime_error("attempt to touch deleted record"); } - if (!record.isModified() && !record.isDeleted() && !record.isErased()) + if (!record.isModified()) { record.setModified(record.get()); + return index; + } + + return -1; + } + + template + void Collection::cloneRecord(const std::string& origin, + const std::string& destination, const UniversalId::Type type) + { + cloneRecordImp(origin, destination, type); + } + + template<> + inline void Collection >::cloneRecord(const std::string& origin, + const std::string& destination, const UniversalId::Type type) + { + int index = cloneRecordImp(origin, destination, type); + mRecords.at(index).get().mPlugin = 0; + } + + template + bool Collection::touchRecord(const std::string& id) + { + return touchRecordImp(id) != -1; + } + + template<> + inline bool Collection >::touchRecord(const std::string& id) + { + int index = touchRecordImp(id); + if (index >= 0) + { + mRecords.at(index).get().mPlugin = 0; return true; } - else - return false; + + return false; } template diff --git a/apps/opencs/model/world/land.cpp b/apps/opencs/model/world/land.cpp index 80f86c746..22fc96599 100644 --- a/apps/opencs/model/world/land.cpp +++ b/apps/opencs/model/world/land.cpp @@ -8,8 +8,24 @@ namespace CSMWorld { ESM::Land::load(esm, isDeleted); + mId = createUniqueRecordId(mX, mY); + } + + std::string Land::createUniqueRecordId(int x, int y) + { std::ostringstream stream; - stream << "#" << mX << " " << mY; - mId = stream.str(); + stream << "#" << x << " " << y; + return stream.str(); + } + + void Land::parseUniqueRecordId(const std::string& id, int& x, int& y) + { + size_t mid = id.find(' '); + + if (mid == std::string::npos || id[0] != '#') + throw std::runtime_error("Invalid Land ID"); + + x = std::stoi(id.substr(1, mid - 1)); + y = std::stoi(id.substr(mid + 1)); } } diff --git a/apps/opencs/model/world/land.hpp b/apps/opencs/model/world/land.hpp index e5f25c1d3..cc7e914af 100644 --- a/apps/opencs/model/world/land.hpp +++ b/apps/opencs/model/world/land.hpp @@ -16,6 +16,9 @@ namespace CSMWorld /// Loads the metadata and ID void load (ESM::ESMReader &esm, bool &isDeleted); + + static std::string createUniqueRecordId(int x, int y); + static void parseUniqueRecordId(const std::string& id, int& x, int& y); }; } diff --git a/apps/opencs/view/world/landcreator.cpp b/apps/opencs/view/world/landcreator.cpp new file mode 100644 index 000000000..34599b2c4 --- /dev/null +++ b/apps/opencs/view/world/landcreator.cpp @@ -0,0 +1,79 @@ +#include "landcreator.hpp" + +#include + +#include "../../model/world/land.hpp" + +namespace CSVWorld +{ + LandCreator::LandCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id) + : GenericCreator(data, undoStack, id) + , mXLabel(nullptr) + , mYLabel(nullptr) + , mX(nullptr) + , mY(nullptr) + { + const int MaxInt = std::numeric_limits::max(); + const int MinInt = std::numeric_limits::min(); + + setManualEditing(false); + + mXLabel = new QLabel("X: "); + mX = new QSpinBox(); + mX->setMinimum(MinInt); + mX->setMaximum(MaxInt); + insertBeforeButtons(mXLabel, false); + insertBeforeButtons(mX, true); + + mYLabel = new QLabel("Y: "); + mY = new QSpinBox(); + mY->setMinimum(MinInt); + mY->setMaximum(MaxInt); + insertBeforeButtons(mYLabel, false); + insertBeforeButtons(mY, true); + + connect (mX, SIGNAL(valueChanged(int)), this, SLOT(coordChanged(int))); + connect (mY, SIGNAL(valueChanged(int)), this, SLOT(coordChanged(int))); + } + + void LandCreator::cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) + { + GenericCreator::cloneMode(originId, type); + + int x = 0, y = 0; + CSMWorld::Land::parseUniqueRecordId(originId, x, y); + + mX->setValue(x); + mY->setValue(y); + } + + void LandCreator::focus() + { + mX->setFocus(); + } + + void LandCreator::reset() + { + GenericCreator::reset(); + mX->setValue(0); + mY->setValue(0); + } + + std::string LandCreator::getErrors() const + { + if (getData().getLand().searchId(getId()) >= 0) + return "A land with that name already exists."; + + return ""; + } + + std::string LandCreator::getId() const + { + return CSMWorld::Land::createUniqueRecordId(mX->value(), mY->value()); + } + + void LandCreator::coordChanged(int value) + { + update(); + } +} diff --git a/apps/opencs/view/world/landcreator.hpp b/apps/opencs/view/world/landcreator.hpp new file mode 100644 index 000000000..aea202dcd --- /dev/null +++ b/apps/opencs/view/world/landcreator.hpp @@ -0,0 +1,42 @@ +#ifndef CSV_WORLD_LANDCREATOR_H +#define CSV_WORLD_LANDCREATOR_H + +#include +#include + +#include "genericcreator.hpp" + +namespace CSVWorld +{ + class LandCreator : public GenericCreator + { + Q_OBJECT + + QLabel* mXLabel; + QLabel* mYLabel; + QSpinBox* mX; + QSpinBox* mY; + + public: + + LandCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id); + + void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) override; + + void focus() override; + + void reset() override; + + std::string getErrors() const override; + + private slots: + + void coordChanged(int value); + + protected: + + std::string getId() const override; + }; +} + +#endif diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index a33802823..3e72f9a9e 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -18,6 +18,7 @@ #include "pathgridcreator.hpp" #include "previewsubview.hpp" #include "bodypartcreator.hpp" +#include "landcreator.hpp" #include "landtexturecreator.hpp" void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) @@ -83,7 +84,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator); manager.add (CSMWorld::UniversalId::Type_Lands, - new CSVDoc::SubViewFactoryWithCreator >); + new CSVDoc::SubViewFactoryWithCreator >); manager.add (CSMWorld::UniversalId::Type_LandTextures, new CSVDoc::SubViewFactoryWithCreator >); @@ -189,7 +190,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator (false)); manager.add (CSMWorld::UniversalId::Type_Land, - new CSVDoc::SubViewFactoryWithCreator >(false)); + new CSVDoc::SubViewFactoryWithCreator >(false)); manager.add (CSMWorld::UniversalId::Type_LandTexture, new CSVDoc::SubViewFactoryWithCreator >(false)); From d3014cf39424972a3b86bc61bfe92cf54551d7b2 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 4 Sep 2017 15:13:45 -0400 Subject: [PATCH 008/505] Temporary fix for adding new lands, cloned lands will still reference old data though --- apps/opencs/view/render/terrainstorage.cpp | 21 ++++----- components/esm/loadland.cpp | 52 +++++++++++++++++++++- components/esm/loadland.hpp | 6 ++- 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index c63d41be3..51c9dd009 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -1,5 +1,8 @@ #include "terrainstorage.hpp" +#include "../../model/world/land.hpp" +#include "../../model/world/landtexture.hpp" + namespace CSVRender { @@ -11,12 +14,9 @@ namespace CSVRender osg::ref_ptr TerrainStorage::getLand(int cellX, int cellY) { - std::ostringstream stream; - stream << "#" << cellX << " " << cellY; - // The cell isn't guaranteed to have Land. This is because the terrain implementation // has to wrap the vertices of the last row and column to the next cell, which may be a nonexisting cell - int index = mData.getLand().searchId(stream.str()); + int index = mData.getLand().searchId(CSMWorld::Land::createUniqueRecordId(cellX, cellY)); if (index == -1) return NULL; @@ -26,16 +26,11 @@ namespace CSVRender const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin) { - int numRecords = mData.getLandTextures().getSize(); - - for (int i=0; imIndex == index && ltex->mPluginIndex == plugin) - return ltex; - } + int row = mData.getLandTextures().searchId(CSMWorld::LandTexture::createUniqueRecordId(plugin, index)); + if (row == -1) + return nullptr; - return NULL; + return &mData.getLandTextures().getRecord(row).get(); } void TerrainStorage::getBounds(float &minX, float &maxX, float &minY, float &maxY) diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 72c3eb98d..7d48dd037 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -15,6 +15,7 @@ namespace ESM , mX(0) , mY(0) , mPlugin(0) + , mNoFile(false) , mDataTypes(0) , mLandData(NULL) { @@ -175,6 +176,47 @@ namespace ESM } + void Land::blank() + { + if (mLandData) + { + delete mLandData; + } + + mPlugin = 0; + + for (int i = 0; i < LAND_GLOBAL_MAP_LOD_SIZE; ++i) + mWnam[0] = 0; + + mLandData = new LandData; + mLandData->mHeightOffset = 0; + for (int i = 0; i < LAND_NUM_VERTS; ++i) + mLandData->mHeights[i] = 0; + mLandData->mMinHeight = 0; + mLandData->mMaxHeight = 0; + for (int i = 0; i < LAND_NUM_VERTS; ++i) + { + mLandData->mNormals[i*3+0] = 0; + mLandData->mNormals[i*3+1] = -1; + mLandData->mNormals[i*3+2] = 0; + } + for (int i = 0; i < LAND_NUM_TEXTURES; ++i) + mLandData->mTextures[i] = 0; + for (int i = 0; i < LAND_NUM_VERTS; ++i) + { + mLandData->mColours[i*3+0] = -1; + mLandData->mColours[i*3+1] = -1; + mLandData->mColours[i*3+2] = -1; + } + mLandData->mUnk1 = 0; + mLandData->mUnk2 = 0; + mLandData->mDataLoaded = Land::DATA_VNML | Land::DATA_VHGT | Land::DATA_WNAM | + Land::DATA_VCLR | Land::DATA_VTEX; + mDataTypes = mLandData->mDataLoaded; + + mNoFile = true; + } + void Land::loadData(int flags, LandData* target) const { // Create storage if nothing is loaded @@ -193,6 +235,13 @@ namespace ESM return; } + // Copy data to target if no file + if (mNoFile) + { + *target = *mLandData; + return; + } + ESM::ESMReader reader; reader.restoreContext(mContext); @@ -271,7 +320,7 @@ namespace ESM Land::Land (const Land& land) : mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin), - mContext (land.mContext), mDataTypes (land.mDataTypes), + mContext (land.mContext), mNoFile(land.mNoFile), mDataTypes (land.mDataTypes), mLandData (land.mLandData ? new LandData (*land.mLandData) : 0) {} @@ -288,6 +337,7 @@ namespace ESM std::swap (mY, land.mY); std::swap (mPlugin, land.mPlugin); std::swap (mContext, land.mContext); + std::swap (mNoFile, land.mNoFile); std::swap (mDataTypes, land.mDataTypes); std::swap (mLandData, land.mLandData); } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index a7b97a465..223b7975a 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -33,6 +33,10 @@ struct Land // location later when we are ready to load the full data set. ESM_Context mContext; + // In the editor, a new Land is not associated with a file, thus mContext should not be accessed + // when land data is being requested. Instead simply copy over the data. + bool mNoFile; + int mDataTypes; enum @@ -116,7 +120,7 @@ struct Land void load(ESMReader &esm, bool &isDeleted); void save(ESMWriter &esm, bool isDeleted = false) const; - void blank() {} + void blank(); /** * Actually loads data into target From 5c3e90da881948ff1f2fde5dd595fe7e2a0882e9 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 4 Sep 2017 15:14:42 -0400 Subject: [PATCH 009/505] Fix includes --- apps/opencs/model/world/land.cpp | 1 + apps/opencs/model/world/landtexture.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/opencs/model/world/land.cpp b/apps/opencs/model/world/land.cpp index 22fc96599..2b12b55fe 100644 --- a/apps/opencs/model/world/land.cpp +++ b/apps/opencs/model/world/land.cpp @@ -1,6 +1,7 @@ #include "land.hpp" #include +#include namespace CSMWorld { diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 4b82f8d73..63ebbc11f 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -1,6 +1,7 @@ #include "landtexture.hpp" #include +#include #include From dca31b7ffa4fc4c8f2b15fcf0491f9e9ef4cde23 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 4 Sep 2017 19:34:26 +0000 Subject: [PATCH 010/505] Remove redundant _boundingBoxComputed which no longer exists in osg master (Fixes #4075) --- components/sceneutil/morphgeometry.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/sceneutil/morphgeometry.cpp b/components/sceneutil/morphgeometry.cpp index 2ffbace3b..1b7e4ca93 100644 --- a/components/sceneutil/morphgeometry.cpp +++ b/components/sceneutil/morphgeometry.cpp @@ -62,10 +62,7 @@ void MorphGeometry::dirty() { mDirty = true; if (!mMorphedBoundingBox) - { - _boundingBoxComputed = false; dirtyBound(); - } } osg::ref_ptr MorphGeometry::getSourceGeometry() const From 97d0fd756a2dff3ac73bd308a1ad7f88c3e4e13d Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 4 Sep 2017 19:31:09 -0400 Subject: [PATCH 011/505] LTEX importing --- apps/opencs/model/world/commands.cpp | 85 +++++++++++++++++++++++++ apps/opencs/model/world/commands.hpp | 25 +++++++- apps/opencs/model/world/idtable.cpp | 57 +++++++++++++++++ apps/opencs/model/world/idtable.hpp | 16 ++++- apps/opencs/model/world/land.cpp | 2 +- apps/opencs/model/world/landtexture.cpp | 2 +- apps/opencs/view/world/landcreator.cpp | 20 ++++++ apps/opencs/view/world/landcreator.hpp | 2 + 8 files changed, 204 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index c6a56f7b8..c98f52777 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -40,6 +41,90 @@ void CSMWorld::TouchCommand::undo() } } +CSMWorld::TouchLandCommand::TouchLandCommand(IdTable& landTable, IdTable& ltexTable, const std::string& id, QUndoCommand* parent) + : QUndoCommand(parent) + , mLands(landTable) + , mLtexs(ltexTable) + , mId(id) + , mOld(nullptr) + , mChanged(false) +{ + setText(("Touch " + mId).c_str()); + mOld.reset(mLands.getRecord(mId).clone()); +} + +void CSMWorld::TouchLandCommand::redo() +{ + int pluginColumn = mLands.findColumnIndex(Columns::ColumnId_PluginIndex); + int oldPlugin = mLands.data(mLands.getModelIndex(mId, pluginColumn)).toInt(); + + mChanged = mLands.touchRecord(mId); + if (mChanged) + { + // Original data + int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); + QByteArray textureByteArray = mLands.data(mLands.getModelIndex(mId, textureColumn)).toByteArray(); + const uint16_t* textureData = reinterpret_cast(textureByteArray.data()); + + // Need to make a copy so the old values can be looked up + QByteArray newTextureByteArray(textureByteArray.data(), textureByteArray.size()); + uint16_t* newTextureData = reinterpret_cast(newTextureByteArray.data()); + + // Find all indices used + std::unordered_set texIndices; + for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) + { + // All indices are offset by 1 for a default texture + if (textureData[i] > 0) + texIndices.insert(textureData[i] - 1); + } + + std::vector oldTextures; + for (int index : texIndices) + { + oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index)); + } + + // Import the textures, replace old values + LandTextureIdTable::ImportResults results = dynamic_cast(mLtexs).importTextures(oldTextures); + mCreatedTextures = std::move(results.createdRecords); + for (const auto& it : results.recordMapping) + { + int plugin = 0, newIndex = 0, oldIndex = 0; + LandTexture::parseUniqueRecordId(it.first, plugin, oldIndex); + LandTexture::parseUniqueRecordId(it.second, plugin, newIndex); + + if (newIndex != oldIndex) + { + for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) + { + // All indices are offset by 1 for a default texture + if (textureData[i] == oldIndex) + newTextureData[i] = newIndex + 1; + } + } + } + + mLands.setData(mLands.getModelIndex(mId, textureColumn), newTextureByteArray); + } +} + +void CSMWorld::TouchLandCommand::undo() +{ + if (mChanged) + { + mLands.setRecord(mId, *mOld); + mChanged = false; + + for (const std::string& id : mCreatedTextures) + { + int row = mLtexs.getModelIndex(id, 0).row(); + mLtexs.removeRows(row, 1); + } + mCreatedTextures.clear(); + } +} + CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand* parent) : QUndoCommand (parent), mModel (&model), mIndex (index), mNew (new_), mHasRecordState(false), mOldRecordState(CSMWorld::RecordBase::State_BaseOnly) diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 4c9be7e8a..5f4259cb8 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -31,8 +31,8 @@ namespace CSMWorld TouchCommand(IdTable& model, const std::string& id, QUndoCommand* parent=nullptr); - virtual void redo(); - virtual void undo(); + void redo() override; + void undo() override; private: @@ -43,6 +43,27 @@ namespace CSMWorld bool mChanged; }; + class TouchLandCommand : public QUndoCommand + { + public: + + TouchLandCommand(IdTable& landTable, IdTable& ltexTable, const std::string& id, + QUndoCommand* parent = nullptr); + + void redo() override; + void undo() override; + + private: + + IdTable& mLands; + IdTable& mLtexs; + std::string mId; + std::unique_ptr mOld; + std::vector mCreatedTextures; + + bool mChanged; + }; + class ModifyCommand : public QUndoCommand { QAbstractItemModel *mModel; diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 94eab3fc3..5543fc13f 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,11 +1,13 @@ #include "idtable.hpp" +#include #include #include #include "collectionbase.hpp" #include "columnbase.hpp" +#include "landtexture.hpp" CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features) : IdTableBase (features), mIdCollection (idCollection) @@ -332,3 +334,58 @@ Qt::ItemFlags CSMWorld::LandTextureIdTable::flags(const QModelIndex& index) cons return flags; } + +CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::importTextures(const std::vector& ids) +{ + ImportResults results; + + for (const std::string& id : ids) + { + int plugin, index; + + LandTexture::parseUniqueRecordId(id, plugin, index); + int oldRow = idCollection()->searchId(id); + + // If it does not exist or it is in the current plugin, it can be skipped. + if (oldRow <= 0 || plugin == 0) + { + results.recordMapping.push_back(std::make_pair(id, id)); + continue; + } + + // Try a direct mapping to the current plugin first. Otherwise iterate until one is found. + // Iteration is deterministic to avoid duplicates. + do { + std::string newId = LandTexture::createUniqueRecordId(0, index); + int newRow = idCollection()->searchId(newId); + + if (newRow < 0) + { + // Id not taken, clone it + cloneRecord(id, newId, UniversalId::Type_LandTexture); + results.createdRecords.push_back(newId); + results.recordMapping.push_back(std::make_pair(id, newId)); + break; + } + + // Id is taken, check if same handle and texture. Note that mId is the handle. + const LandTexture& oldLtex = dynamic_cast&>(idCollection()->getRecord(oldRow)).get(); + const LandTexture& newLtex = dynamic_cast&>(idCollection()->getRecord(newRow)).get(); + if (oldLtex.mId == newLtex.mId && oldLtex.mTexture == newLtex.mTexture) + { + // It's a match + results.recordMapping.push_back(std::make_pair(id, newId)); + break; + } + + // Determine next index. Spread out the indices to reduce conflicts. + size_t MaxIndex = std::numeric_limits::max(); + size_t Prime = (1 << 19) - 1; // A mersenne prime + size_t K = 2154; + + index = ((K * index) % Prime) % MaxIndex; + } while (true); + } + + return results; +} diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 5e5f9da4a..ccc5ac404 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -100,11 +100,22 @@ namespace CSMWorld }; /// An IdTable customized to handle the more unique needs of LandTextureId's which behave - /// differently from other records. + /// differently from other records. The major difference is that base records cannot be + /// modified. class LandTextureIdTable : public IdTable { public: + struct ImportResults + { + using StringPair = std::pair; + + /// The newly added records + std::vector createdRecords; + /// The 1st string is the original id, the 2nd is the mapped id + std::vector recordMapping; + }; + LandTextureIdTable(CollectionBase* idCollection, unsigned int features=0); QVariant data(const QModelIndex& index, int role=Qt::DisplayRole) const override; @@ -112,6 +123,9 @@ namespace CSMWorld bool setData(const QModelIndex& index, const QVariant& value, int role) override; Qt::ItemFlags flags (const QModelIndex & index) const override; + + /// Finds and maps/recreates the specified ids. + ImportResults importTextures(const std::vector& ids); }; } diff --git a/apps/opencs/model/world/land.cpp b/apps/opencs/model/world/land.cpp index 2b12b55fe..74833d7ef 100644 --- a/apps/opencs/model/world/land.cpp +++ b/apps/opencs/model/world/land.cpp @@ -1,7 +1,7 @@ #include "land.hpp" #include -#include +#include namespace CSMWorld { diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 63ebbc11f..32bab1e6d 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -1,7 +1,7 @@ #include "landtexture.hpp" #include -#include +#include #include diff --git a/apps/opencs/view/world/landcreator.cpp b/apps/opencs/view/world/landcreator.cpp index 34599b2c4..08b8b3620 100644 --- a/apps/opencs/view/world/landcreator.cpp +++ b/apps/opencs/view/world/landcreator.cpp @@ -2,6 +2,8 @@ #include +#include "../../model/world/commands.hpp" +#include "../../model/world/idtable.hpp" #include "../../model/world/land.hpp" namespace CSVWorld @@ -47,6 +49,24 @@ namespace CSVWorld mY->setValue(y); } + void LandCreator::touch(const std::vector& ids) + { + // Combine multiple touch commands into one "macro" command + std::unique_ptr macro(new QUndoCommand()); + macro->setText("Touch records"); + + CSMWorld::IdTable& lands = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_Lands)); + CSMWorld::IdTable& ltexs = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures)); + for (const CSMWorld::UniversalId& uid : ids) + { + // This is not leaked, touchCmd is a child of macro and managed by Qt + CSMWorld::TouchLandCommand* touchCmd = new CSMWorld::TouchLandCommand(lands, ltexs, uid.getId(), macro.get()); + } + + // Execute + getUndoStack().push(macro.release()); + } + void LandCreator::focus() { mX->setFocus(); diff --git a/apps/opencs/view/world/landcreator.hpp b/apps/opencs/view/world/landcreator.hpp index aea202dcd..ef8cf60d5 100644 --- a/apps/opencs/view/world/landcreator.hpp +++ b/apps/opencs/view/world/landcreator.hpp @@ -23,6 +23,8 @@ namespace CSVWorld void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) override; + void touch(const std::vector& ids) override; + void focus() override; void reset() override; From 99e90ef808ec95d3c5e22e3e72d99ef10e58b0d9 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Tue, 5 Sep 2017 19:29:07 -0400 Subject: [PATCH 012/505] Cleanup. Also modify ltex index generation. --- apps/opencs/model/prefs/state.cpp | 1 + apps/opencs/model/world/collection.hpp | 2 -- apps/opencs/model/world/columnimp.hpp | 9 ++++++- apps/opencs/model/world/columns.cpp | 5 ++++ apps/opencs/model/world/idtable.cpp | 8 +++--- apps/opencs/model/world/land.cpp | 2 -- apps/opencs/model/world/land.hpp | 2 -- apps/opencs/model/world/landtexture.cpp | 6 +++-- apps/opencs/view/world/landcreator.cpp | 3 +++ apps/opencs/view/world/landcreator.hpp | 6 ++--- apps/opencs/view/world/landtexturecreator.cpp | 27 ++++++++----------- apps/opencs/view/world/landtexturecreator.hpp | 6 ++--- 12 files changed, 42 insertions(+), 35 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 0101a432b..1f84c5a87 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -278,6 +278,7 @@ void CSMPrefs::State::declare() declareShortcut ("table-edit", "Edit Record", QKeySequence()); declareShortcut ("table-add", "Add Row/Record", QKeySequence(Qt::ShiftModifier | Qt::Key_A)); declareShortcut ("table-clone", "Clone Record", QKeySequence(Qt::ShiftModifier | Qt::Key_D)); + declareShortcut ("touch-record", "Touch Record", QKeySequence()); declareShortcut ("table-revert", "Revert Record", QKeySequence()); declareShortcut ("table-remove", "Remove Row/Record", QKeySequence(Qt::Key_Delete)); declareShortcut ("table-moveup", "Move Record Up", QKeySequence()); diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index fccbebd43..80117d0c6 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -48,8 +48,6 @@ namespace CSMWorld Land::parseUniqueRecordId(id, x, y); record.mX = x; record.mY = y; - // TODO check for uses of mId and remove them - record.mId = id; } template<> diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index f58a35bc4..8e5908bd3 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -63,6 +63,13 @@ namespace CSMWorld } }; + template<> + inline QVariant StringIdColumn::get(const Record& record) const + { + const Land& land = record.get(); + return QString(Land::createUniqueRecordId(land.mX, land.mY).c_str()); + } + template<> inline QVariant StringIdColumn::get(const Record& record) const { @@ -2483,7 +2490,7 @@ namespace CSMWorld return -1; } - virtual bool isEditable() const override + bool isEditable() const override { return false; } diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 49935d40d..63ccb6017 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -333,6 +333,11 @@ namespace CSMWorld { ColumnId_TextureHandle, "Texture Handle" }, { ColumnId_PluginIndex, "Plugin Index" }, { ColumnId_TextureIndex, "Texture Index" }, + { ColumnId_LandMapLodIndex, "Land map height LOD" }, + { ColumnId_LandNormalsIndex, "Land normals" }, + { ColumnId_LandHeightsIndex, "Land heights" }, + { ColumnId_LandColoursIndex, "Land colors" }, + { ColumnId_LandTexturesIndex, "Land textures" }, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 5543fc13f..127ffde2c 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,5 +1,6 @@ #include "idtable.hpp" +#include #include #include @@ -379,11 +380,10 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import } // Determine next index. Spread out the indices to reduce conflicts. - size_t MaxIndex = std::numeric_limits::max(); - size_t Prime = (1 << 19) - 1; // A mersenne prime - size_t K = 2154; + size_t MaxIndex = std::numeric_limits::max() - 1; + size_t Prime = (1 << 13) - 1; // A mersenne prime - index = ((K * index) % Prime) % MaxIndex; + index = (index + Prime) % MaxIndex; } while (true); } diff --git a/apps/opencs/model/world/land.cpp b/apps/opencs/model/world/land.cpp index 74833d7ef..bfa927444 100644 --- a/apps/opencs/model/world/land.cpp +++ b/apps/opencs/model/world/land.cpp @@ -8,8 +8,6 @@ namespace CSMWorld void Land::load(ESM::ESMReader &esm, bool &isDeleted) { ESM::Land::load(esm, isDeleted); - - mId = createUniqueRecordId(mX, mY); } std::string Land::createUniqueRecordId(int x, int y) diff --git a/apps/opencs/model/world/land.hpp b/apps/opencs/model/world/land.hpp index cc7e914af..e604f1311 100644 --- a/apps/opencs/model/world/land.hpp +++ b/apps/opencs/model/world/land.hpp @@ -12,8 +12,6 @@ namespace CSMWorld /// \todo Add worldspace support to the Land record. struct Land : public ESM::Land { - std::string mId; - /// Loads the metadata and ID void load (ESM::ESMReader &esm, bool &isDeleted); diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 32bab1e6d..43deb64a4 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -1,6 +1,6 @@ #include "landtexture.hpp" -#include +#include #include #include @@ -16,7 +16,9 @@ namespace CSMWorld std::string LandTexture::createUniqueRecordId(int plugin, int index) { - return 'L' + std::to_string(plugin) + '#' + std::to_string(index); + std::stringstream ss; + ss << 'L' << plugin << '#' << index; + return ss.str(); } void LandTexture::parseUniqueRecordId(const std::string& id, int& plugin, int& index) diff --git a/apps/opencs/view/world/landcreator.cpp b/apps/opencs/view/world/landcreator.cpp index 08b8b3620..a227a6a87 100644 --- a/apps/opencs/view/world/landcreator.cpp +++ b/apps/opencs/view/world/landcreator.cpp @@ -2,6 +2,9 @@ #include +#include +#include + #include "../../model/world/commands.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/land.hpp" diff --git a/apps/opencs/view/world/landcreator.hpp b/apps/opencs/view/world/landcreator.hpp index ef8cf60d5..9674a2b58 100644 --- a/apps/opencs/view/world/landcreator.hpp +++ b/apps/opencs/view/world/landcreator.hpp @@ -1,11 +1,11 @@ #ifndef CSV_WORLD_LANDCREATOR_H #define CSV_WORLD_LANDCREATOR_H -#include -#include - #include "genericcreator.hpp" +class QLabel; +class QSpinBox; + namespace CSVWorld { class LandCreator : public GenericCreator diff --git a/apps/opencs/view/world/landtexturecreator.cpp b/apps/opencs/view/world/landtexturecreator.cpp index f79c08427..fdabfb281 100644 --- a/apps/opencs/view/world/landtexturecreator.cpp +++ b/apps/opencs/view/world/landtexturecreator.cpp @@ -3,9 +3,9 @@ #include #include -#include #include #include +#include #include "../../model/world/commands.hpp" #include "../../model/world/idtable.hpp" @@ -30,14 +30,13 @@ namespace CSVWorld QLabel* indexLabel = new QLabel("Index"); insertBeforeButtons(indexLabel, false); - QIntValidator* indexValidator = new QIntValidator(0, MaxIndex, this); - - mIndexEdit = new QLineEdit(this); - mIndexEdit->setValidator(indexValidator); - insertBeforeButtons(mIndexEdit, true); + mIndexBox = new QSpinBox(this); + mIndexBox->setMinimum(0); + mIndexBox->setMaximum(MaxIndex); + insertBeforeButtons(mIndexBox, true); connect(mNameEdit, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&))); - connect(mIndexEdit, SIGNAL(textChanged(const QString&)), this, SLOT(indexChanged(const QString&))); + connect(mIndexBox, SIGNAL(valueChanged(int)), this, SLOT(indexChanged(int))); } void LandTextureCreator::cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) @@ -50,26 +49,23 @@ namespace CSVWorld mNameEdit->setText((table.data(table.getModelIndex(originId, column)).toString())); column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureIndex); - mIndexEdit->setText((table.data(table.getModelIndex(originId, column)).toString())); + mIndexBox->setValue((table.data(table.getModelIndex(originId, column)).toInt())); } void LandTextureCreator::focus() { - mIndexEdit->setFocus(); + mIndexBox->setFocus(); } void LandTextureCreator::reset() { GenericCreator::reset(); mNameEdit->setText(""); - mIndexEdit->setText(""); + mIndexBox->setValue(0); } std::string LandTextureCreator::getErrors() const { - std::string id = getId(); - - // TODO empty index edit? if (getData().getLandTextures().searchId(getId()) >= 0) { return "Index is already in use"; @@ -89,7 +85,7 @@ namespace CSVWorld std::string LandTextureCreator::getId() const { - return CSMWorld::LandTexture::createUniqueRecordId(0, mIndex); + return CSMWorld::LandTexture::createUniqueRecordId(0, mIndexBox->value()); } void LandTextureCreator::nameChanged(const QString& value) @@ -98,9 +94,8 @@ namespace CSVWorld update(); } - void LandTextureCreator::indexChanged(const QString& value) + void LandTextureCreator::indexChanged(int value) { - mIndex = value.toInt(); update(); } } diff --git a/apps/opencs/view/world/landtexturecreator.hpp b/apps/opencs/view/world/landtexturecreator.hpp index 46388bf03..b11c47758 100644 --- a/apps/opencs/view/world/landtexturecreator.hpp +++ b/apps/opencs/view/world/landtexturecreator.hpp @@ -6,6 +6,7 @@ #include "genericcreator.hpp" class QLineEdit; +class QSpinBox; namespace CSVWorld { @@ -34,15 +35,14 @@ namespace CSVWorld private slots: void nameChanged(const QString& val); - void indexChanged(const QString& val); + void indexChanged(int val); private: QLineEdit* mNameEdit; - QLineEdit* mIndexEdit; + QSpinBox* mIndexBox; std::string mName; - int mIndex; }; } From 7559d2531773a256ef83a803938d8e9110c6693c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 6 Sep 2017 15:11:47 +0400 Subject: [PATCH 013/505] Update alchemy effects after every created potion (#4079) --- apps/openmw/mwmechanics/alchemy.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 124468641..48705dc72 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -262,22 +262,16 @@ const ESM::Potion *MWMechanics::Alchemy::getRecord(const ESM::Potion& toFind) co void MWMechanics::Alchemy::removeIngredients() { - bool needsUpdate = false; - for (TIngredientsContainer::iterator iter (mIngredients.begin()); iter!=mIngredients.end(); ++iter) if (!iter->isEmpty()) { iter->getContainerStore()->remove(*iter, 1, mAlchemist); if (iter->getRefData().getCount()<1) - { - needsUpdate = true; *iter = MWWorld::Ptr(); - } } - if (needsUpdate) - updateEffects(); + updateEffects(); } void MWMechanics::Alchemy::addPotion (const std::string& name) From 538498230b97f478532441c75e2afe125cee43c8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 6 Sep 2017 15:59:54 +0400 Subject: [PATCH 014/505] Declare mClient variable --- components/widgets/windowcaption.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/widgets/windowcaption.hpp b/components/widgets/windowcaption.hpp index bdd4c0a2e..b45da2d1c 100644 --- a/components/widgets/windowcaption.hpp +++ b/components/widgets/windowcaption.hpp @@ -23,6 +23,7 @@ namespace Gui private: MyGUI::Widget* mLeft; MyGUI::Widget* mRight; + MyGUI::Widget* mClient; void align(); }; From dc0313a36f7c01952c0f10f89566441bc05a8cac Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 7 Sep 2017 21:06:10 +0400 Subject: [PATCH 015/505] Use base skill value when calculating rank requirements --- 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 595635206..f0fc7fb6e 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -380,7 +380,7 @@ bool MWMechanics::NpcStats::hasSkillsForRank (const std::string& factionId, int for (int i=0; i<7; ++i) { if (faction.mData.mSkills[i] != -1) - skills.push_back (static_cast (getSkill (faction.mData.mSkills[i]).getModified())); + skills.push_back (static_cast (getSkill (faction.mData.mSkills[i]).getBase())); } if (skills.empty()) From ab607f302834c1409e1f0d72caa0dc68be83361c Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 8 Sep 2017 00:51:46 -0400 Subject: [PATCH 016/505] Tweaks to land loading, land cloning, terrain signals, placeholder land update handling --- apps/opencs/model/world/collection.hpp | 2 + apps/opencs/model/world/commands.cpp | 170 ++++++++++++------ apps/opencs/model/world/commands.hpp | 54 +++++- apps/opencs/view/render/cell.cpp | 72 ++++++-- apps/opencs/view/render/cell.hpp | 14 ++ .../view/render/pagedworldspacewidget.cpp | 81 +++++++++ .../view/render/pagedworldspacewidget.hpp | 8 + apps/opencs/view/world/genericcreator.cpp | 5 + apps/opencs/view/world/genericcreator.hpp | 2 + apps/opencs/view/world/landcreator.cpp | 19 ++ apps/opencs/view/world/landcreator.hpp | 11 +- components/esm/loadland.cpp | 9 +- components/esm/loadland.hpp | 6 +- 13 files changed, 363 insertions(+), 90 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 80117d0c6..6e74a1726 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -297,6 +297,7 @@ namespace CSMWorld { int index = cloneRecordImp(origin, destination, type); mRecords.at(index).get().mPlugin = 0; + mRecords.at(index).get().mContext.filename.clear(); } template @@ -312,6 +313,7 @@ namespace CSMWorld if (index >= 0) { mRecords.at(index).get().mPlugin = 0; + mRecords.at(index).get().mContext.filename.clear(); return true; } diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index c98f52777..5bfcd6846 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -41,87 +41,145 @@ void CSMWorld::TouchCommand::undo() } } -CSMWorld::TouchLandCommand::TouchLandCommand(IdTable& landTable, IdTable& ltexTable, const std::string& id, QUndoCommand* parent) +CSMWorld::ImportLandTexturesCommand::ImportLandTexturesCommand(IdTable& landTable, + IdTable& ltexTable, QUndoCommand* parent) : QUndoCommand(parent) , mLands(landTable) , mLtexs(ltexTable) - , mId(id) - , mOld(nullptr) - , mChanged(false) + , mOldState(0) { - setText(("Touch " + mId).c_str()); - mOld.reset(mLands.getRecord(mId).clone()); + setText("Import land textures"); } -void CSMWorld::TouchLandCommand::redo() +void CSMWorld::ImportLandTexturesCommand::redo() { int pluginColumn = mLands.findColumnIndex(Columns::ColumnId_PluginIndex); - int oldPlugin = mLands.data(mLands.getModelIndex(mId, pluginColumn)).toInt(); + int oldPlugin = mLands.data(mLands.getModelIndex(getOriginId(), pluginColumn)).toInt(); - mChanged = mLands.touchRecord(mId); - if (mChanged) + // Original data + int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); + mOld = mLands.data(mLands.getModelIndex(getOriginId(), textureColumn)).toByteArray(); + const uint16_t* textureData = reinterpret_cast(mOld.data()); + + // Need to make a copy so the old values can be looked up + QByteArray newTextureByteArray(mOld.data(), mOld.size()); + uint16_t* newTextureData = reinterpret_cast(newTextureByteArray.data()); + + // Perform touch/copy/etc... + onRedo(); + + // Find all indices used + std::unordered_set texIndices; + for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) { - // Original data - int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); - QByteArray textureByteArray = mLands.data(mLands.getModelIndex(mId, textureColumn)).toByteArray(); - const uint16_t* textureData = reinterpret_cast(textureByteArray.data()); - - // Need to make a copy so the old values can be looked up - QByteArray newTextureByteArray(textureByteArray.data(), textureByteArray.size()); - uint16_t* newTextureData = reinterpret_cast(newTextureByteArray.data()); - - // Find all indices used - std::unordered_set texIndices; - for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) - { - // All indices are offset by 1 for a default texture - if (textureData[i] > 0) - texIndices.insert(textureData[i] - 1); - } + // All indices are offset by 1 for a default texture + if (textureData[i] > 0) + texIndices.insert(textureData[i] - 1); + } - std::vector oldTextures; - for (int index : texIndices) - { - oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index)); - } + std::vector oldTextures; + for (int index : texIndices) + { + oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index)); + } - // Import the textures, replace old values - LandTextureIdTable::ImportResults results = dynamic_cast(mLtexs).importTextures(oldTextures); - mCreatedTextures = std::move(results.createdRecords); - for (const auto& it : results.recordMapping) - { - int plugin = 0, newIndex = 0, oldIndex = 0; - LandTexture::parseUniqueRecordId(it.first, plugin, oldIndex); - LandTexture::parseUniqueRecordId(it.second, plugin, newIndex); + // Import the textures, replace old values + LandTextureIdTable::ImportResults results = dynamic_cast(mLtexs).importTextures(oldTextures); + mCreatedTextures = std::move(results.createdRecords); + for (const auto& it : results.recordMapping) + { + int plugin = 0, newIndex = 0, oldIndex = 0; + LandTexture::parseUniqueRecordId(it.first, plugin, oldIndex); + LandTexture::parseUniqueRecordId(it.second, plugin, newIndex); - if (newIndex != oldIndex) + if (newIndex != oldIndex) + { + for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) { - for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) - { - // All indices are offset by 1 for a default texture - if (textureData[i] == oldIndex) - newTextureData[i] = newIndex + 1; - } + // All indices are offset by 1 for a default texture + if (textureData[i] == oldIndex + 1) + newTextureData[i] = newIndex + 1; } } + } - mLands.setData(mLands.getModelIndex(mId, textureColumn), newTextureByteArray); + // Apply modification + int stateColumn = mLands.findColumnIndex(Columns::ColumnId_Modification); + mOldState = mLands.data(mLands.getModelIndex(getDestinationId(), stateColumn)).toInt(); + + mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), newTextureByteArray); +} + +void CSMWorld::ImportLandTexturesCommand::undo() +{ + // Restore to previous + int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); + mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), mOld); + + int stateColumn = mLands.findColumnIndex(Columns::ColumnId_Modification); + mLands.setData(mLands.getModelIndex(getDestinationId(), stateColumn), mOldState); + + // Undo copy/touch/etc... + onUndo(); + + for (const std::string& id : mCreatedTextures) + { + int row = mLtexs.getModelIndex(id, 0).row(); + mLtexs.removeRows(row, 1); } + mCreatedTextures.clear(); } -void CSMWorld::TouchLandCommand::undo() +CSMWorld::CopyLandTexturesCommand::CopyLandTexturesCommand(IdTable& landTable, IdTable& ltexTable, + const std::string& origin, const std::string& dest, QUndoCommand* parent) + : ImportLandTexturesCommand(landTable, ltexTable, parent) + , mOriginId(origin) + , mDestId(dest) +{ +} + +const std::string& CSMWorld::CopyLandTexturesCommand::getOriginId() const +{ + return mOriginId; +} + +const std::string& CSMWorld::CopyLandTexturesCommand::getDestinationId() const +{ + return mDestId; +} + +CSMWorld::TouchLandCommand::TouchLandCommand(IdTable& landTable, IdTable& ltexTable, + const std::string& id, QUndoCommand* parent) + : ImportLandTexturesCommand(landTable, ltexTable, parent) + , mId(id) + , mOld(nullptr) + , mChanged(false) +{ + setText(("Touch " + mId).c_str()); + mOld.reset(mLands.getRecord(mId).clone()); +} + +const std::string& CSMWorld::TouchLandCommand::getOriginId() const +{ + return mId; +} + +const std::string& CSMWorld::TouchLandCommand::getDestinationId() const +{ + return mId; +} + +void CSMWorld::TouchLandCommand::onRedo() +{ + mChanged = mLands.touchRecord(mId); +} + +void CSMWorld::TouchLandCommand::onUndo() { if (mChanged) { mLands.setRecord(mId, *mOld); mChanged = false; - - for (const std::string& id : mCreatedTextures) - { - int row = mLtexs.getModelIndex(id, 0).row(); - mLtexs.removeRows(row, 1); - } - mCreatedTextures.clear(); } } diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 5f4259cb8..aab0c5410 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -43,23 +43,67 @@ namespace CSMWorld bool mChanged; }; - class TouchLandCommand : public QUndoCommand + class ImportLandTexturesCommand : public QUndoCommand { public: - TouchLandCommand(IdTable& landTable, IdTable& ltexTable, const std::string& id, - QUndoCommand* parent = nullptr); + ImportLandTexturesCommand(IdTable& landTable, IdTable& ltexTable, + QUndoCommand* parent); void redo() override; void undo() override; - private: + protected: + + virtual const std::string& getOriginId() const = 0; + virtual const std::string& getDestinationId() const = 0; + + virtual void onRedo() = 0; + virtual void onUndo() = 0; IdTable& mLands; IdTable& mLtexs; + QByteArray mOld; + int mOldState; + std::vector mCreatedTextures; + }; + + class CopyLandTexturesCommand : public ImportLandTexturesCommand + { + public: + + CopyLandTexturesCommand(IdTable& landTable, IdTable& ltexTable, const std::string& origin, + const std::string& dest, QUndoCommand* parent = nullptr); + + private: + + const std::string& getOriginId() const override; + const std::string& getDestinationId() const override; + + void onRedo() override {} + void onUndo() override {} + + std::string mOriginId; + std::string mDestId; + }; + + class TouchLandCommand : public ImportLandTexturesCommand + { + public: + + TouchLandCommand(IdTable& landTable, IdTable& ltexTable, + const std::string& id, QUndoCommand* parent = nullptr); + + private: + + const std::string& getOriginId() const override; + const std::string& getDestinationId() const override; + + void onRedo() override; + void onUndo() override; + std::string mId; std::unique_ptr mOld; - std::vector mCreatedTextures; bool mChanged; }; diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 765c5b316..51279cac4 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -75,6 +75,31 @@ bool CSVRender::Cell::addObjects (int start, int end) return modified; } +void CSVRender::Cell::createLand() +{ + if (mDeleted) + { + mTerrain.reset(); + return; + } + + const CSMWorld::IdCollection& land = mData.getLand(); + int landIndex = land.searchId(mId); + if (landIndex != -1) + { + const ESM::Land& esmLand = land.getRecord(mId).get(); + + if (esmLand.getLandData (ESM::Land::DATA_VHGT)) + { + mTerrain.reset(new Terrain::TerrainGrid(mCellNode, mCellNode, mData.getResourceSystem().get(), new TerrainStorage(mData), Mask_Terrain)); + mTerrain->loadCell(esmLand.mX, esmLand.mY); + + mCellBorder.reset(new CellBorder(mCellNode, mCoordinates)); + mCellBorder->buildShape(esmLand); + } + } +} + CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, bool deleted) : mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted), mSubMode (0), @@ -99,22 +124,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st addObjects (0, rows-1); - const CSMWorld::IdCollection& land = mData.getLand(); - int landIndex = land.searchId(mId); - if (landIndex != -1) - { - const ESM::Land& esmLand = land.getRecord(mId).get(); - - if (esmLand.getLandData (ESM::Land::DATA_VHGT)) - { - mTerrain.reset(new Terrain::TerrainGrid(mCellNode, mCellNode, data.getResourceSystem().get(), new TerrainStorage(mData), Mask_Terrain)); - mTerrain->loadCell(esmLand.mX, - esmLand.mY); - - mCellBorder.reset(new CellBorder(mCellNode, mCoordinates)); - mCellBorder->buildShape(esmLand); - } - } + createLand(); mPathgrid.reset(new Pathgrid(mData, mCellNode, mId, mCoordinates)); mCellWater.reset(new CellWater(mData, mCellNode, mId, mCoordinates)); @@ -285,6 +295,36 @@ void CSVRender::Cell::pathgridRemoved() mPathgrid->removeGeometry(); } +void CSVRender::Cell::landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + createLand(); +} + +void CSVRender::Cell::landAboutToBeRemoved (const QModelIndex& parent, int start, int end) +{ + createLand(); +} + +void CSVRender::Cell::landAdded (const QModelIndex& parent, int start, int end) +{ + createLand(); +} + +void CSVRender::Cell::landTextureChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + createLand(); +} + +void CSVRender::Cell::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end) +{ + createLand(); +} + +void CSVRender::Cell::landTextureAdded (const QModelIndex& parent, int start, int end) +{ + createLand(); +} + void CSVRender::Cell::reloadAssets() { for (std::map::const_iterator iter (mObjects.begin()); diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index f53f61973..f6db475d7 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -72,6 +72,8 @@ namespace CSVRender /// \return Have any objects been added? bool addObjects (int start, int end); + void createLand(); + public: enum Selection @@ -118,6 +120,18 @@ namespace CSVRender void pathgridRemoved(); + void landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + + void landAboutToBeRemoved (const QModelIndex& parent, int start, int end); + + void landAdded (const QModelIndex& parent, int start, int end); + + void landTextureChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + + void landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end); + + void landTextureAdded (const QModelIndex& parent, int start, int end); + void reloadAssets(); void setSelection (int elementMask, Selection mode); diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index b1077139c..b224ac1c4 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -351,6 +351,69 @@ void CSVRender::PagedWorldspaceWidget::pathgridAdded(const QModelIndex& parent, } } +void CSVRender::PagedWorldspaceWidget::landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + for (int r = topLeft.row(); r <= bottomRight.row(); ++r) + { + std::string id = mDocument.getData().getLand().getId(r); + + auto cellIt = mCells.find(CSMWorld::CellCoordinates::fromId(id).first); + if (cellIt != mCells.end()) + { + cellIt->second->landDataChanged(topLeft, bottomRight); + flagAsModified(); + } + } +} + +void CSVRender::PagedWorldspaceWidget::landAboutToBeRemoved (const QModelIndex& parent, int start, int end) +{ + for (int r = start; r <= end; ++r) + { + std::string id = mDocument.getData().getLand().getId(r); + + auto cellIt = mCells.find(CSMWorld::CellCoordinates::fromId(id).first); + if (cellIt != mCells.end()) + { + cellIt->second->landAboutToBeRemoved(parent, start, end); + flagAsModified(); + } + } +} + +void CSVRender::PagedWorldspaceWidget::landAdded (const QModelIndex& parent, int start, int end) +{ + for (int r = start; r <= end; ++r) + { + std::string id = mDocument.getData().getLand().getId(r); + + auto cellIt = mCells.find(CSMWorld::CellCoordinates::fromId(id).first); + if (cellIt != mCells.end()) + { + cellIt->second->landAdded(parent, start, end); + flagAsModified(); + } + } +} + +void CSVRender::PagedWorldspaceWidget::landTextureDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + for (auto cellIt : mCells) + cellIt.second->landTextureChanged(topLeft, bottomRight); +} + +void CSVRender::PagedWorldspaceWidget::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end) +{ + for (auto cellIt : mCells) + cellIt.second->landTextureAboutToBeRemoved(parent, start, end); +} + +void CSVRender::PagedWorldspaceWidget::landTextureAdded (const QModelIndex& parent, int start, int end) +{ + for (auto cellIt : mCells) + cellIt.second->landTextureAdded(parent, start, end); +} + std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() { @@ -475,6 +538,24 @@ CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc connect (&document.getData(), SIGNAL (assetTablesChanged ()), this, SLOT (assetTablesChanged ())); + QAbstractItemModel *lands = document.getData().getTableModel (CSMWorld::UniversalId::Type_Lands); + + connect (lands, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), + this, SLOT (landDataChanged (const QModelIndex&, const QModelIndex&))); + connect (lands, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), + this, SLOT (landAboutToBeRemoved (const QModelIndex&, int, int))); + connect (lands, SIGNAL (rowsInserted (const QModelIndex&, int, int)), + this, SLOT (landAdded (const QModelIndex&, int, int))); + + QAbstractItemModel *ltexs = document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures); + + connect (ltexs, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), + this, SLOT (landTextureDataChanged (const QModelIndex&, const QModelIndex&))); + connect (ltexs, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), + this, SLOT (landTextureAboutToBeRemoved (const QModelIndex&, int, int))); + connect (ltexs, SIGNAL (rowsInserted (const QModelIndex&, int, int)), + this, SLOT (landTextureAdded (const QModelIndex&, int, int))); + // Shortcuts CSMPrefs::Shortcut* loadCameraCellShortcut = new CSMPrefs::Shortcut("scene-load-cam-cell", this); connect(loadCameraCellShortcut, SIGNAL(activated()), this, SLOT(loadCameraCell())); diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 8c41df51e..6672c2268 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -155,6 +155,14 @@ namespace CSVRender virtual void cellAdded (const QModelIndex& index, int start, int end); + virtual void landDataChanged (const QModelIndex& topLeft, const QModelIndex& botomRight); + virtual void landAboutToBeRemoved (const QModelIndex& parent, int start, int end); + virtual void landAdded (const QModelIndex& parent, int start, int end); + + virtual void landTextureDataChanged (const QModelIndex& topLeft, const QModelIndex& botomRight); + virtual void landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end); + virtual void landTextureAdded (const QModelIndex& parent, int start, int end); + void assetTablesChanged (); void loadCameraCell(); diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index bde523a09..bd3da230d 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -51,6 +51,11 @@ std::string CSVWorld::GenericCreator::getId() const return mId->text().toUtf8().constData(); } +std::string CSVWorld::GenericCreator::getClonedId() const +{ + return mClonedId; +} + std::string CSVWorld::GenericCreator::getIdValidatorResult() const { std::string errors; diff --git a/apps/opencs/view/world/genericcreator.hpp b/apps/opencs/view/world/genericcreator.hpp index d708c1047..3baacfc06 100644 --- a/apps/opencs/view/world/genericcreator.hpp +++ b/apps/opencs/view/world/genericcreator.hpp @@ -64,6 +64,8 @@ namespace CSVWorld virtual std::string getId() const; + std::string getClonedId() const; + virtual std::string getIdValidatorResult() const; /// Allow subclasses to add additional data to \a command. diff --git a/apps/opencs/view/world/landcreator.cpp b/apps/opencs/view/world/landcreator.cpp index a227a6a87..dd7bfe68d 100644 --- a/apps/opencs/view/world/landcreator.cpp +++ b/apps/opencs/view/world/landcreator.cpp @@ -95,6 +95,25 @@ namespace CSVWorld return CSMWorld::Land::createUniqueRecordId(mX->value(), mY->value()); } + void LandCreator::pushCommand(std::unique_ptr command, const std::string& id) + { + if (mCloneMode) + { + CSMWorld::IdTable& lands = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_Lands)); + CSMWorld::IdTable& ltexs = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures)); + + getUndoStack().beginMacro(("Clone " + id).c_str()); + getUndoStack().push(command.release()); + + CSMWorld::CopyLandTexturesCommand* ltexCopy = new CSMWorld::CopyLandTexturesCommand(lands, ltexs, getClonedId(), getId()); + getUndoStack().push(ltexCopy); + + getUndoStack().endMacro(); + } + else + getUndoStack().push (command.release()); + } + void LandCreator::coordChanged(int value) { update(); diff --git a/apps/opencs/view/world/landcreator.hpp b/apps/opencs/view/world/landcreator.hpp index 9674a2b58..e0c5577e4 100644 --- a/apps/opencs/view/world/landcreator.hpp +++ b/apps/opencs/view/world/landcreator.hpp @@ -31,13 +31,16 @@ namespace CSVWorld std::string getErrors() const override; - private slots: - - void coordChanged(int value); - protected: std::string getId() const override; + + void pushCommand(std::unique_ptr command, + const std::string& id) override; + + private slots: + + void coordChanged(int value); }; } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 7d48dd037..c81675556 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -15,7 +15,6 @@ namespace ESM , mX(0) , mY(0) , mPlugin(0) - , mNoFile(false) , mDataTypes(0) , mLandData(NULL) { @@ -214,7 +213,8 @@ namespace ESM Land::DATA_VCLR | Land::DATA_VTEX; mDataTypes = mLandData->mDataLoaded; - mNoFile = true; + // No file associated with the land now + mContext.filename.clear(); } void Land::loadData(int flags, LandData* target) const @@ -236,7 +236,7 @@ namespace ESM } // Copy data to target if no file - if (mNoFile) + if (mContext.filename.empty()) { *target = *mLandData; return; @@ -320,7 +320,7 @@ namespace ESM Land::Land (const Land& land) : mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin), - mContext (land.mContext), mNoFile(land.mNoFile), mDataTypes (land.mDataTypes), + mContext (land.mContext), mDataTypes (land.mDataTypes), mLandData (land.mLandData ? new LandData (*land.mLandData) : 0) {} @@ -337,7 +337,6 @@ namespace ESM std::swap (mY, land.mY); std::swap (mPlugin, land.mPlugin); std::swap (mContext, land.mContext); - std::swap (mNoFile, land.mNoFile); std::swap (mDataTypes, land.mDataTypes); std::swap (mLandData, land.mLandData); } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 223b7975a..d7b736f99 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -31,12 +31,10 @@ struct Land // File context. This allows the ESM reader to be 'reset' to this // location later when we are ready to load the full data set. + // In the editor, there may not be a file associated with the Land, + // in which case the filename will be empty. ESM_Context mContext; - // In the editor, a new Land is not associated with a file, thus mContext should not be accessed - // when land data is being requested. Instead simply copy over the data. - bool mNoFile; - int mDataTypes; enum From ac2f20f983ca9be113e36d147e9fec9f226b0b91 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 8 Sep 2017 19:42:06 +0400 Subject: [PATCH 017/505] Update a disposition bar when a dialogue widget is disabled, but visible --- apps/openmw/mwgui/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index f478dad7e..2e80301d2 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -634,7 +634,7 @@ namespace MWGui void DialogueWindow::onFrame() { - if(mMainWidget->getVisible() && mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name()) + if(mMainWidget->getVisible() && mPtr.getTypeName() == typeid(ESM::NPC).name()) { int disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr); mDispositionBar->setProgressRange(100); From 3c0ec0d6d02d9ccd882e283e5973876259c42bfc Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 8 Sep 2017 17:26:46 +0100 Subject: [PATCH 018/505] If CMake supports it, sets the debugger working directory for Visual Studio --- apps/bsatool/CMakeLists.txt | 6 ++++++ apps/esmtool/CMakeLists.txt | 6 ++++++ apps/essimporter/CMakeLists.txt | 6 ++++++ apps/launcher/CMakeLists.txt | 6 +++++- apps/mwiniimporter/CMakeLists.txt | 6 ++++++ apps/niftest/CMakeLists.txt | 6 ++++++ apps/opencs/CMakeLists.txt | 4 ++++ apps/openmw/CMakeLists.txt | 4 ++++ apps/openmw_test_suite/CMakeLists.txt | 6 ++++++ apps/wizard/CMakeLists.txt | 6 ++++++ 10 files changed, 55 insertions(+), 1 deletion(-) diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt index 27baff815..19c9558cf 100644 --- a/apps/bsatool/CMakeLists.txt +++ b/apps/bsatool/CMakeLists.txt @@ -18,3 +18,9 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(bsatool gcov) endif() + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(bsatool PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/esmtool/CMakeLists.txt b/apps/esmtool/CMakeLists.txt index 1d5e662d8..b0c67d8fa 100644 --- a/apps/esmtool/CMakeLists.txt +++ b/apps/esmtool/CMakeLists.txt @@ -21,3 +21,9 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(esmtool gcov) endif() + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(esmtool PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 93f53d0e8..a7c25ca2e 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -46,3 +46,9 @@ endif() if (WIN32) INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".") endif(WIN32) + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw-essimporter PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 8cbe18d51..5d70aa917 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -110,4 +110,8 @@ if (BUILD_WITH_CODE_COVERAGE) target_link_libraries(openmw-launcher gcov) endif() - +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw-launcher PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index 4bd661685..071137556 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -33,3 +33,9 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-iniimporter gcov) endif() + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw-iniimporter PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/niftest/CMakeLists.txt b/apps/niftest/CMakeLists.txt index d7f0200d2..efe440ae7 100644 --- a/apps/niftest/CMakeLists.txt +++ b/apps/niftest/CMakeLists.txt @@ -17,3 +17,9 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(niftest gcov) endif() + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(niftest PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index fc8930b71..65c1d8ed8 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -260,6 +260,10 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) + + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw-cs PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) endif (MSVC) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 89b94ce12..3ef62dfa3 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -215,6 +215,10 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) + + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) endif (MSVC) if (WIN32) diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index ea4b1209c..7d6898367 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -24,6 +24,12 @@ if (GTEST_FOUND) if (UNIX AND NOT APPLE) target_link_libraries(openmw_test_suite ${CMAKE_THREAD_LIBS_INIT}) endif() + + if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw_test_suite PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) + endif (MSVC) endif() diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index d2b9ab0f6..2d9a11c51 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -143,3 +143,9 @@ endif() if (WIN32) INSTALL(TARGETS openmw-wizard RUNTIME DESTINATION ".") endif(WIN32) + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw-wizard PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file From 2eacc2f093e921c983047308eaf0a400b5294889 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 8 Sep 2017 14:37:03 -0400 Subject: [PATCH 019/505] Changes to land creation, add ability to specifically clear terrain cache --- apps/opencs/view/render/cell.cpp | 36 ++++++++++++++++--- apps/opencs/view/render/cell.hpp | 1 + .../view/render/pagedworldspacewidget.cpp | 3 ++ components/terrain/world.cpp | 6 ++++ components/terrain/world.hpp | 4 +++ 5 files changed, 46 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 51279cac4..18614a85f 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -77,27 +77,55 @@ bool CSVRender::Cell::addObjects (int start, int end) void CSVRender::Cell::createLand() { + // Cell is deleted if (mDeleted) { - mTerrain.reset(); + unloadLand(); return; } + // Setup land if available const CSMWorld::IdCollection& land = mData.getLand(); int landIndex = land.searchId(mId); - if (landIndex != -1) + if (landIndex != -1 && !land.getRecord(mId).isDeleted()) { const ESM::Land& esmLand = land.getRecord(mId).get(); if (esmLand.getLandData (ESM::Land::DATA_VHGT)) { - mTerrain.reset(new Terrain::TerrainGrid(mCellNode, mCellNode, mData.getResourceSystem().get(), new TerrainStorage(mData), Mask_Terrain)); + if (mTerrain) + { + mTerrain->unloadCell(mCoordinates.getX(), mCoordinates.getY()); + mTerrain->clearAssociatedCaches(); + } + else + { + mTerrain.reset(new Terrain::TerrainGrid(mCellNode, mCellNode, + mData.getResourceSystem().get(), new TerrainStorage(mData), Mask_Terrain)); + } + mTerrain->loadCell(esmLand.mX, esmLand.mY); - mCellBorder.reset(new CellBorder(mCellNode, mCoordinates)); + if (!mCellBorder) + mCellBorder.reset(new CellBorder(mCellNode, mCoordinates)); + mCellBorder->buildShape(esmLand); + + return; } } + + // No land data + unloadLand(); +} + +void CSVRender::Cell::unloadLand() +{ + if (mTerrain) + mTerrain->unloadCell(mCoordinates.getX(), mCoordinates.getY()); + + if (mCellBorder) + mCellBorder.reset(); } CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index f6db475d7..6418ed249 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -73,6 +73,7 @@ namespace CSVRender bool addObjects (int start, int end); void createLand(); + void unloadLand(); public: diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index b224ac1c4..4a745195b 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -400,18 +400,21 @@ void CSVRender::PagedWorldspaceWidget::landTextureDataChanged (const QModelIndex { for (auto cellIt : mCells) cellIt.second->landTextureChanged(topLeft, bottomRight); + flagAsModified(); } void CSVRender::PagedWorldspaceWidget::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end) { for (auto cellIt : mCells) cellIt.second->landTextureAboutToBeRemoved(parent, start, end); + flagAsModified(); } void CSVRender::PagedWorldspaceWidget::landTextureAdded (const QModelIndex& parent, int start, int end) { for (auto cellIt : mCells) cellIt.second->landTextureAdded(parent, start, end); + flagAsModified(); } diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index b7cc0ae01..22c65b62c 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -75,4 +75,10 @@ void World::updateTextureFiltering() mTextureManager->updateTextureFiltering(); } +void World::clearAssociatedCaches() +{ + mTextureManager->clearCache(); + mChunkManager->clearCache(); +} + } diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index d0576fbd3..e1c3828fc 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -63,6 +63,10 @@ namespace Terrain float getHeightAt (const osg::Vec3f& worldPos); + /// Clears the cached land and landtexture data. + /// @note Thread safe. + virtual void clearAssociatedCaches(); + /// Load a terrain cell at maximum LOD and store it in the View for later use. /// @note Thread safe. virtual void cacheCell(View* view, int x, int y) {} From 1e585ac71a4b6caea25bd6f24b02d70d165e3582 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Fri, 8 Sep 2017 22:50:07 +0200 Subject: [PATCH 020/505] Log a warning in case of missing bookart instead of showing a pink rectangle (Fixes #3826) --- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwgui/formatting.cpp | 18 +++++++++++++----- apps/openmw/mwgui/windowmanagerimp.cpp | 7 +++++-- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index d7ccfa3e4..4560ab270 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -360,7 +360,7 @@ namespace MWBase // In WindowManager for now since there isn't a VFS singleton virtual std::string correctIconPath(const std::string& path) = 0; - virtual std::string correctBookartPath(const std::string& path, int width, int height) = 0; + virtual std::string correctBookartPath(const std::string& path, int width, int height, bool* exists = nullptr) = 0; virtual std::string correctTexturePath(const std::string& path) = 0; virtual bool textureExists(const std::string& path) = 0; diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 72e1c09f3..cf4a5b589 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -275,8 +275,6 @@ namespace MWGui { case BookTextParser::Event_ImgTag: { - pag.setIgnoreLeadingEmptyLines(false); - const BookTextParser::Attributes & attr = parser.getAttributes(); if (attr.find("src") == attr.end() || attr.find("width") == attr.end() || attr.find("height") == attr.end()) @@ -286,8 +284,19 @@ namespace MWGui int width = MyGUI::utility::parseInt(attr.at("width")); int height = MyGUI::utility::parseInt(attr.at("height")); + bool exists; + std::string correctedSrc = MWBase::Environment::get().getWindowManager()->correctBookartPath(src, width, height, &exists); + + if (!exists) + { + std::cerr << "Warning: Could not find \"" << src << "\" referenced by an tag." << std::endl; + break; + } + + pag.setIgnoreLeadingEmptyLines(false); + ImageElement elem(paper, pag, mBlockStyle, - src, width, height); + correctedSrc, width, height); elem.paginate(); break; } @@ -471,8 +480,7 @@ namespace MWGui MyGUI::IntCoord(left, pag.getCurrentTop(), width, mImageHeight), MyGUI::Align::Left | MyGUI::Align::Top, parent->getName() + MyGUI::utility::toString(parent->getChildCount())); - std::string image = MWBase::Environment::get().getWindowManager()->correctBookartPath(src, width, mImageHeight); - mImageBox->setImageTexture(image); + mImageBox->setImageTexture(src); mImageBox->setProperty("NeedMouse", "false"); } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 33ba58cc7..4b7b3c387 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -2090,9 +2090,12 @@ namespace MWGui return Misc::ResourceHelpers::correctIconPath(path, mResourceSystem->getVFS()); } - std::string WindowManager::correctBookartPath(const std::string& path, int width, int height) + std::string WindowManager::correctBookartPath(const std::string& path, int width, int height, bool* exists) { - return Misc::ResourceHelpers::correctBookartPath(path, width, height, mResourceSystem->getVFS()); + std::string corrected = Misc::ResourceHelpers::correctBookartPath(path, width, height, mResourceSystem->getVFS()); + if (exists) + *exists = mResourceSystem->getVFS()->exists(corrected); + return corrected; } std::string WindowManager::correctTexturePath(const std::string& path) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index ceb6f62b7..4f06afb7d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -388,7 +388,7 @@ namespace MWGui // In WindowManager for now since there isn't a VFS singleton virtual std::string correctIconPath(const std::string& path); - virtual std::string correctBookartPath(const std::string& path, int width, int height); + virtual std::string correctBookartPath(const std::string& path, int width, int height, bool* exists = nullptr); virtual std::string correctTexturePath(const std::string& path); virtual bool textureExists(const std::string& path); From 5ce34f1cbfe0527a3e4b03a6b459b7a52324e067 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 8 Sep 2017 22:17:42 +0100 Subject: [PATCH 021/505] Move new behaviour into macro to reduce code duplication --- apps/bsatool/CMakeLists.txt | 10 ++-------- apps/esmtool/CMakeLists.txt | 10 ++-------- apps/essimporter/CMakeLists.txt | 10 ++-------- apps/launcher/CMakeLists.txt | 10 ++-------- apps/mwiniimporter/CMakeLists.txt | 10 ++-------- apps/niftest/CMakeLists.txt | 10 ++-------- apps/opencs/CMakeLists.txt | 6 +----- apps/openmw/CMakeLists.txt | 6 +----- apps/openmw_test_suite/CMakeLists.txt | 8 +------- apps/wizard/CMakeLists.txt | 8 +------- cmake/OpenMWMacros.cmake | 9 +++++++++ 11 files changed, 25 insertions(+), 72 deletions(-) diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt index 19c9558cf..167ab9d2c 100644 --- a/apps/bsatool/CMakeLists.txt +++ b/apps/bsatool/CMakeLists.txt @@ -4,7 +4,7 @@ set(BSATOOL source_group(apps\\bsatool FILES ${BSATOOL}) # Main executable -add_executable(bsatool +openmw_add_executable(bsatool ${BSATOOL} ) @@ -17,10 +17,4 @@ target_link_libraries(bsatool if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(bsatool gcov) -endif() - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(bsatool PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif() \ No newline at end of file diff --git a/apps/esmtool/CMakeLists.txt b/apps/esmtool/CMakeLists.txt index b0c67d8fa..90964f2d7 100644 --- a/apps/esmtool/CMakeLists.txt +++ b/apps/esmtool/CMakeLists.txt @@ -8,7 +8,7 @@ set(ESMTOOL source_group(apps\\esmtool FILES ${ESMTOOL}) # Main executable -add_executable(esmtool +openmw_add_executable(esmtool ${ESMTOOL} ) @@ -20,10 +20,4 @@ target_link_libraries(esmtool if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(esmtool gcov) -endif() - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(esmtool PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif() \ No newline at end of file diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index a7c25ca2e..69200583e 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -28,7 +28,7 @@ set(ESSIMPORTER_FILES convertplayer.cpp ) -add_executable(openmw-essimporter +openmw_add_executable(openmw-essimporter ${ESSIMPORTER_FILES} ) @@ -45,10 +45,4 @@ endif() if (WIN32) INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".") -endif(WIN32) - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw-essimporter PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif(WIN32) \ No newline at end of file diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 5d70aa917..70a6708a8 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -78,7 +78,7 @@ if(NOT WIN32) endif(NOT WIN32) # Main executable -add_executable(openmw-launcher +openmw_add_executable(openmw-launcher ${GUI_TYPE} ${LAUNCHER} ${LAUNCHER_HEADER} @@ -108,10 +108,4 @@ endif() if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-launcher gcov) -endif() - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw-launcher PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif() \ No newline at end of file diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index 071137556..f1717a4c3 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -9,7 +9,7 @@ set(MWINIIMPORT_HEADER source_group(launcher FILES ${MWINIIMPORT} ${MWINIIMPORT_HEADER}) -add_executable(openmw-iniimporter +openmw_add_executable(openmw-iniimporter ${MWINIIMPORT} ) @@ -32,10 +32,4 @@ endif() if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-iniimporter gcov) -endif() - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw-iniimporter PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif() \ No newline at end of file diff --git a/apps/niftest/CMakeLists.txt b/apps/niftest/CMakeLists.txt index efe440ae7..10119d7d7 100644 --- a/apps/niftest/CMakeLists.txt +++ b/apps/niftest/CMakeLists.txt @@ -4,7 +4,7 @@ set(NIFTEST source_group(components\\nif\\tests FILES ${NIFTEST}) # Main executable -add_executable(niftest +openmw_add_executable(niftest ${NIFTEST} ) @@ -16,10 +16,4 @@ target_link_libraries(niftest if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(niftest gcov) -endif() - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(niftest PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif() \ No newline at end of file diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 65c1d8ed8..281921c81 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -174,7 +174,7 @@ else() set (OPENCS_OPENMW_CFG "") endif(APPLE) -add_executable(openmw-cs +openmw_add_executable(openmw-cs MACOSX_BUNDLE ${OPENCS_SRC} ${OPENCS_UI_HDR} @@ -260,10 +260,6 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) - - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw-cs PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) endif (MSVC) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 3ef62dfa3..134953f3d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -99,7 +99,7 @@ add_openmw_dir (mwbase # Main executable if (NOT ANDROID) - add_executable(openmw + openmw_add_executable(openmw ${OPENMW_FILES} ${GAME} ${GAME_HEADER} ${APPLE_BUNDLE_RESOURCES} @@ -215,10 +215,6 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) - - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) endif (MSVC) if (WIN32) diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 7d6898367..9b09bc41f 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -17,19 +17,13 @@ if (GTEST_FOUND) source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) - add_executable(openmw_test_suite openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) + openmw_add_executable(openmw_test_suite openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) target_link_libraries(openmw_test_suite ${GTEST_BOTH_LIBRARIES} components) # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) target_link_libraries(openmw_test_suite ${CMAKE_THREAD_LIBS_INIT}) endif() - - if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw_test_suite PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) - endif (MSVC) endif() diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index 2d9a11c51..5f7338e52 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -96,7 +96,7 @@ if (OPENMW_USE_UNSHIELD) include_directories(${LIBUNSHIELD_INCLUDE_DIRS}) endif() -add_executable(openmw-wizard +openmw_add_executable(openmw-wizard ${GUI_TYPE} ${WIZARD} ${WIZARD_HEADER} @@ -143,9 +143,3 @@ endif() if (WIN32) INSTALL(TARGETS openmw-wizard RUNTIME DESTINATION ".") endif(WIN32) - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw-wizard PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index c5669fa70..9a1722dab 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -142,3 +142,12 @@ foreach (u ${ARGN}) add_hdr (OPENCS ${dir} ${u}) endforeach (u) endmacro (opencs_hdrs_noqt) + +macro (openmw_add_executable target) + add_executable(${target} ${ARGN}) + if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(${target} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) + endif (MSVC) +endmacro (openmw_add_executable) From 8c74f16247b1888f359ba79740e4cf97d9b8b5f7 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 8 Sep 2017 22:20:04 +0100 Subject: [PATCH 022/505] Restore trailing new lines to shrink PR --- apps/bsatool/CMakeLists.txt | 2 +- apps/esmtool/CMakeLists.txt | 2 +- apps/essimporter/CMakeLists.txt | 2 +- apps/launcher/CMakeLists.txt | 3 ++- apps/mwiniimporter/CMakeLists.txt | 2 +- apps/niftest/CMakeLists.txt | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt index 167ab9d2c..ec0615ff9 100644 --- a/apps/bsatool/CMakeLists.txt +++ b/apps/bsatool/CMakeLists.txt @@ -17,4 +17,4 @@ target_link_libraries(bsatool if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(bsatool gcov) -endif() \ No newline at end of file +endif() diff --git a/apps/esmtool/CMakeLists.txt b/apps/esmtool/CMakeLists.txt index 90964f2d7..122ca2f3a 100644 --- a/apps/esmtool/CMakeLists.txt +++ b/apps/esmtool/CMakeLists.txt @@ -20,4 +20,4 @@ target_link_libraries(esmtool if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(esmtool gcov) -endif() \ No newline at end of file +endif() diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 69200583e..82182b7fa 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -45,4 +45,4 @@ endif() if (WIN32) INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".") -endif(WIN32) \ No newline at end of file +endif(WIN32) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 70a6708a8..70281910f 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -108,4 +108,5 @@ endif() if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-launcher gcov) -endif() \ No newline at end of file +endif() + diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index f1717a4c3..e83656708 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -32,4 +32,4 @@ endif() if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-iniimporter gcov) -endif() \ No newline at end of file +endif() diff --git a/apps/niftest/CMakeLists.txt b/apps/niftest/CMakeLists.txt index 10119d7d7..3cbee2b7e 100644 --- a/apps/niftest/CMakeLists.txt +++ b/apps/niftest/CMakeLists.txt @@ -16,4 +16,4 @@ target_link_libraries(niftest if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(niftest gcov) -endif() \ No newline at end of file +endif() From a9b95596bc55deba7daeec8249c811cd75cfa746 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 8 Sep 2017 22:21:00 +0100 Subject: [PATCH 023/505] Add a missed trailing new line. --- apps/launcher/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 70281910f..aac076404 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -110,3 +110,4 @@ if (BUILD_WITH_CODE_COVERAGE) target_link_libraries(openmw-launcher gcov) endif() + From 72cb405de220d5cfe706c5c1c0e57358c32ab2dc Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 8 Sep 2017 21:03:52 -0400 Subject: [PATCH 024/505] Some bug fixes, changes to land load code. --- apps/opencs/model/world/columnimp.cpp | 6 ++++-- apps/opencs/model/world/data.cpp | 14 +------------- apps/opencs/model/world/idcollection.hpp | 17 +++++++++++++++++ components/esm/loadland.cpp | 4 ++-- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index 65d2fecd2..e6b406864 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -103,7 +103,8 @@ namespace CSMWorld assert (array.count() == Land::LAND_NUM_VERTS * sizeof(float)); - for (int i = 0; i < array.count(); ++i) + int count = array.count() / sizeof(float); + for (int i = 0; i < count; ++i) { landData->mHeights[i] = rawData[i]; } @@ -183,7 +184,8 @@ namespace CSMWorld assert (array.count() == Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); - for (int i = 0; i < array.count(); ++i) + int count = array.count() / sizeof(uint16_t); + for (int i = 0; i < count; ++i) { landData->mTextures[i] = rawData[i]; } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 3284d9b05..0ffe5fa21 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -1013,19 +1013,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) case ESM::REC_LTEX: mLandTextures.load (*mReader, mBase); break; - case ESM::REC_LAND: - { - int index = mLand.load(*mReader, mBase); - - // Load all land data for now. A future optimisation may only load non-base data - // if a suitable mechanism for avoiding race conditions can be established. - if (index!=-1/* && !mBase*/) - mLand.getRecord (index).get().loadData ( - ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | - ESM::Land::DATA_VTEX); - - break; - } + case ESM::REC_LAND: mLand.load(*mReader, mBase); break; case ESM::REC_CELL: { diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index ea6eefb88..7849aab92 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -4,6 +4,7 @@ #include #include "collection.hpp" +#include "land.hpp" namespace CSMWorld { @@ -39,6 +40,22 @@ namespace CSMWorld record.load (reader, isDeleted); } + template<> + inline void IdCollection >::loadRecord (Land& record, + ESM::ESMReader& reader, bool& isDeleted) + { + record.load (reader, isDeleted); + + // Load all land data for now. A future optimisation may only load non-base data + // if a suitable mechanism for avoiding race conditions can be established. + int flags = ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | + ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX; + record.loadData (flags); + + // Prevent data from being reloaded. + record.mContext.filename.clear(); + } + template int IdCollection::load (ESM::ESMReader& reader, bool base) { diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index c81675556..6f118c1ab 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -196,8 +196,8 @@ namespace ESM for (int i = 0; i < LAND_NUM_VERTS; ++i) { mLandData->mNormals[i*3+0] = 0; - mLandData->mNormals[i*3+1] = -1; - mLandData->mNormals[i*3+2] = 0; + mLandData->mNormals[i*3+1] = 0; + mLandData->mNormals[i*3+2] = 127; } for (int i = 0; i < LAND_NUM_TEXTURES; ++i) mLandData->mTextures[i] = 0; From c9f099ce07eb0da9df1d84d15e0993f63a6ec33e Mon Sep 17 00:00:00 2001 From: krizd Date: Sat, 9 Sep 2017 03:06:03 +0100 Subject: [PATCH 025/505] Change CMake version check to include 3.8 --- cmake/OpenMWMacros.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 9a1722dab..460751445 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -146,8 +146,8 @@ endmacro (opencs_hdrs_noqt) macro (openmw_add_executable target) add_executable(${target} ${ARGN}) if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) + if (CMAKE_VERSION VERSION_GREATER 3.8 OR CMAKE_VERSION VERSION_EQUAL 3.8) set_target_properties(${target} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) + endif (CMAKE_VERSION VERSION_GREATER 3.8 OR CMAKE_VERSION VERSION_EQUAL 3.8) endif (MSVC) endmacro (openmw_add_executable) From d030b595f8460e92eea09052805fbfcd2fdaeef9 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 9 Sep 2017 11:48:13 -0400 Subject: [PATCH 026/505] Fix potential segfault, cleanup, get rid of warnings. --- apps/opencs/model/world/collection.hpp | 2 -- apps/opencs/view/render/cell.cpp | 16 ++++++++-------- apps/opencs/view/render/cell.hpp | 2 +- apps/opencs/view/world/genericcreator.cpp | 9 ++++----- apps/opencs/view/world/landcreator.cpp | 9 ++++----- components/esm/loadland.cpp | 6 +++++- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 6e74a1726..80117d0c6 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -297,7 +297,6 @@ namespace CSMWorld { int index = cloneRecordImp(origin, destination, type); mRecords.at(index).get().mPlugin = 0; - mRecords.at(index).get().mContext.filename.clear(); } template @@ -313,7 +312,6 @@ namespace CSMWorld if (index >= 0) { mRecords.at(index).get().mPlugin = 0; - mRecords.at(index).get().mContext.filename.clear(); return true; } diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 18614a85f..1c1d496bb 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -75,7 +75,7 @@ bool CSVRender::Cell::addObjects (int start, int end) return modified; } -void CSVRender::Cell::createLand() +void CSVRender::Cell::updateLand() { // Cell is deleted if (mDeleted) @@ -152,7 +152,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st addObjects (0, rows-1); - createLand(); + updateLand(); mPathgrid.reset(new Pathgrid(mData, mCellNode, mId, mCoordinates)); mCellWater.reset(new CellWater(mData, mCellNode, mId, mCoordinates)); @@ -325,32 +325,32 @@ void CSVRender::Cell::pathgridRemoved() void CSVRender::Cell::landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { - createLand(); + updateLand(); } void CSVRender::Cell::landAboutToBeRemoved (const QModelIndex& parent, int start, int end) { - createLand(); + updateLand(); } void CSVRender::Cell::landAdded (const QModelIndex& parent, int start, int end) { - createLand(); + updateLand(); } void CSVRender::Cell::landTextureChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { - createLand(); + updateLand(); } void CSVRender::Cell::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end) { - createLand(); + updateLand(); } void CSVRender::Cell::landTextureAdded (const QModelIndex& parent, int start, int end) { - createLand(); + updateLand(); } void CSVRender::Cell::reloadAssets() diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 6418ed249..101aebd58 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -72,7 +72,7 @@ namespace CSVRender /// \return Have any objects been added? bool addObjects (int start, int end); - void createLand(); + void updateLand(); void unloadLand(); public: diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index bd3da230d..5e2118e9b 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -262,18 +262,17 @@ void CSVWorld::GenericCreator::cloneMode(const std::string& originId, void CSVWorld::GenericCreator::touch(const std::vector& ids) { // Combine multiple touch commands into one "macro" command - std::unique_ptr macro(new QUndoCommand()); - macro->setText("Touch records"); + mUndoStack.beginMacro("Touch Records"); CSMWorld::IdTable& table = dynamic_cast(*mData.getTableModel(mListId)); for (const CSMWorld::UniversalId& uid : ids) { - // This is not leaked, touchCmd is a child of macro and managed by Qt - CSMWorld::TouchCommand* touchCmd = new CSMWorld::TouchCommand(table, uid.getId(), macro.get()); + CSMWorld::TouchCommand* touchCmd = new CSMWorld::TouchCommand(table, uid.getId()); + mUndoStack.push(touchCmd); } // Execute - mUndoStack.push(macro.release()); + mUndoStack.endMacro(); } void CSVWorld::GenericCreator::toggleWidgets(bool active) diff --git a/apps/opencs/view/world/landcreator.cpp b/apps/opencs/view/world/landcreator.cpp index dd7bfe68d..2ebfe1869 100644 --- a/apps/opencs/view/world/landcreator.cpp +++ b/apps/opencs/view/world/landcreator.cpp @@ -55,19 +55,18 @@ namespace CSVWorld void LandCreator::touch(const std::vector& ids) { // Combine multiple touch commands into one "macro" command - std::unique_ptr macro(new QUndoCommand()); - macro->setText("Touch records"); + getUndoStack().beginMacro("Touch records"); CSMWorld::IdTable& lands = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_Lands)); CSMWorld::IdTable& ltexs = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures)); for (const CSMWorld::UniversalId& uid : ids) { - // This is not leaked, touchCmd is a child of macro and managed by Qt - CSMWorld::TouchLandCommand* touchCmd = new CSMWorld::TouchLandCommand(lands, ltexs, uid.getId(), macro.get()); + CSMWorld::TouchLandCommand* touchCmd = new CSMWorld::TouchLandCommand(lands, ltexs, uid.getId()); + getUndoStack().push(touchCmd); } // Execute - getUndoStack().push(macro.release()); + getUndoStack().endMacro(); } void LandCreator::focus() diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 6f118c1ab..f597defd7 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -238,7 +238,11 @@ namespace ESM // Copy data to target if no file if (mContext.filename.empty()) { - *target = *mLandData; + if (mLandData) + *target = *mLandData; + else + target = new LandData; + return; } From 33c77d7a2aefaad6219bba2c43fc76497ceb32e4 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 9 Sep 2017 17:22:55 +0100 Subject: [PATCH 027/505] Try using cmake_parse_arguments to make the macro work --- cmake/OpenMWMacros.cmake | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 460751445..11f230ac6 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -143,8 +143,34 @@ add_hdr (OPENCS ${dir} ${u}) endforeach (u) endmacro (opencs_hdrs_noqt) +include(CMakeParseArguments) + macro (openmw_add_executable target) - add_executable(${target} ${ARGN}) + set(OMW_ADD_EXE_OPTIONS WIN32 MACOSX_BUNDLE EXCLUDE_FROM_ALL) + set(OMW_ADD_EXE_VALUES) + set(OMW_ADD_EXE_MULTI_VALUES) + cmake_parse_arguments(OMW_ADD_EXE "${OMW_ADD_EXE_OPTIONS}" "${OMW_ADD_EXE_VALUES}" "${OMW_ADD_EXE_MULTI_VALUES}" ${ARGN}) + + if (OMW_ADD_EXE_WIN32) + set(OMW_ADD_EXE_WIN32_VALUE WIN32) + endif (OMW_ADD_EXE_WIN32) + + if (OMW_ADD_EXE_MACOSX_BUNDLE) + set(OMW_ADD_EXE_MACOSX_BUNDLE_VALUE MACOSX_BUNDLE) + endif (OMW_ADD_EXE_MACOSX_BUNDLE) + + if (OMW_ADD_EXE_EXCLUDE_FROM_ALL) + set(OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE EXCLUDE_FROM_ALL) + endif (OMW_ADD_EXE_EXCLUDE_FROM_ALL) + + message("Target: " ${target}) + message("WIN32: ${OMW_ADD_EXE_WIN32_VALUE}") + message("MACOSX_BUNDLE: ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE}") + message("EXCLUDE_FROM_ALL: ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE}") + message("Unparsed: ${OMW_ADD_EXE_UNPARSED_ARGUMENTS}") + + add_executable(${target} ${OMW_ADD_EXE_WIN32_VALUE} ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE} ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE} "${OMW_ADD_EXE_UNPARSED_ARGUMENTS}") + if (MSVC) if (CMAKE_VERSION VERSION_GREATER 3.8 OR CMAKE_VERSION VERSION_EQUAL 3.8) set_target_properties(${target} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") From 25d4a0370f7022c8c83b80d99741ad9d9345e5b1 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 9 Sep 2017 15:37:52 -0400 Subject: [PATCH 028/505] Changes to land data access in tables, also update Land once per frame in scene view. --- apps/opencs/model/world/columnimp.cpp | 131 ++++++++++++++++---------- apps/opencs/model/world/idtable.cpp | 3 +- apps/opencs/view/render/cell.cpp | 51 ++++++++-- apps/opencs/view/render/cell.hpp | 3 + components/esm/loadland.cpp | 9 ++ components/esm/loadland.hpp | 3 + 6 files changed, 143 insertions(+), 57 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index e6b406864..1ee7f8a03 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -10,19 +10,31 @@ namespace CSMWorld QVariant LandMapLodColumn::get(const Record& record) const { - // Note: original data is signed - const char* rawData = reinterpret_cast(&record.get().mWnam[0]); - return QByteArray(rawData, Land::LAND_GLOBAL_MAP_LOD_SIZE); + const int Size = Land::LAND_GLOBAL_MAP_LOD_SIZE; + const Land& land = record.get(); + + if (land.isDataLoaded(Land::DATA_WNAM)) + { + // Note: original data is signed + const char* rawData = reinterpret_cast(&land.mWnam[0]); + return QByteArray(rawData, Size); + } + else + { + // Return a blank array + return QByteArray(Size, 0); + } } void LandMapLodColumn::set(Record& record, const QVariant& data) { - Land copy = record.get(); QByteArray array = data.toByteArray(); const signed char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_GLOBAL_MAP_LOD_SIZE); + Land copy = record.get(); + copy.setDataLoaded(Land::DATA_WNAM); + for (int i = 0; i < array.count(); ++i) { copy.mWnam[i] = rawData[i]; @@ -44,28 +56,34 @@ namespace CSMWorld QVariant LandNormalsColumn::get(const Record& record) const { - const Land::LandData* landData = record.get().getLandData(); - assert(landData); + const int Size = Land::LAND_NUM_VERTS * 3; + const Land& land = record.get(); - // Note: original data is signed - const char* rawData = reinterpret_cast(&landData->mNormals[0]); - return QByteArray(rawData, Land::LAND_NUM_VERTS * 3); + if (land.isDataLoaded(Land::DATA_VNML)) + { + // Note: original data is signed + const char* rawData = reinterpret_cast(&land.getLandData()->mNormals[0]); + return QByteArray(rawData, Size); + } + else + { + // Return a blank array + return QByteArray(Size, 0); + } } void LandNormalsColumn::set(Record& record, const QVariant& data) { - Land copy = record.get(); - Land::LandData* landData = copy.getLandData(); - assert (landData); - QByteArray array = data.toByteArray(); const signed char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * 3); + Land copy = record.get(); + copy.setDataLoaded(Land::DATA_VNML); + for (int i = 0; i < array.count(); ++i) { - landData->mNormals[i] = rawData[i]; + copy.getLandData()->mNormals[i] = rawData[i]; } record.setModified(copy); @@ -84,29 +102,34 @@ namespace CSMWorld QVariant LandHeightsColumn::get(const Record& record) const { - const Land::LandData* landData = record.get().getLandData(); - assert(landData); + const int Size = Land::LAND_NUM_VERTS * sizeof(float); + const Land& land = record.get(); - // Note: original data is float - const char* rawData = reinterpret_cast(&landData->mHeights[0]); - return QByteArray(rawData, Land::LAND_NUM_VERTS * sizeof(float)); + if (land.isDataLoaded(Land::DATA_VHGT)) + { + // Note: original data is float + const char* rawData = reinterpret_cast(&land.getLandData()->mHeights[0]); + return QByteArray(rawData, Size); + } + else + { + return QByteArray(Size, 0); + } } void LandHeightsColumn::set(Record& record, const QVariant& data) { - Land copy = record.get(); - Land::LandData* landData = copy.getLandData(); - assert (landData); - QByteArray array = data.toByteArray(); const float* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * sizeof(float)); + Land copy = record.get(); + copy.setDataLoaded(Land::DATA_VHGT); + int count = array.count() / sizeof(float); for (int i = 0; i < count; ++i) { - landData->mHeights[i] = rawData[i]; + copy.getLandData()->mHeights[i] = rawData[i]; } record.setModified(copy); @@ -125,28 +148,33 @@ namespace CSMWorld QVariant LandColoursColumn::get(const Record& record) const { - const Land::LandData* landData = record.get().getLandData(); - assert(landData); + const int Size = Land::LAND_NUM_VERTS * 3; + const Land& land = record.get(); - // Note: original data is unsigned char - const char* rawData = reinterpret_cast(&landData->mColours[0]); - return QByteArray(rawData, Land::LAND_NUM_VERTS * 3); + if (land.isDataLoaded(Land::DATA_VCLR)) + { + // Note: original data is unsigned char + const char* rawData = reinterpret_cast(&land.getLandData()->mColours[0]); + return QByteArray(rawData, Size); + } + else + { + return QByteArray(Size, 0); + } } void LandColoursColumn::set(Record& record, const QVariant& data) { - Land copy = record.get(); - Land::LandData* landData = copy.getLandData(); - assert (landData); - QByteArray array = data.toByteArray(); const unsigned char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * 3); + Land copy = record.get(); + copy.setDataLoaded(Land::DATA_VCLR); + for (int i = 0; i < array.count(); ++i) { - landData->mColours[i] = rawData[i]; + copy.getLandData()->mColours[i] = rawData[i]; } record.setModified(copy); @@ -165,29 +193,34 @@ namespace CSMWorld QVariant LandTexturesColumn::get(const Record& record) const { - const Land::LandData* landData = record.get().getLandData(); - assert(landData); + const int Size = Land::LAND_NUM_TEXTURES * sizeof(uint16_t); + const Land& land = record.get(); - // Note: original data is uint16_t - const char* rawData = reinterpret_cast(&landData->mTextures[0]); - return QByteArray(rawData, Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); + if (land.isDataLoaded(Land::DATA_VTEX)) + { + // Note: original data is uint16_t + const char* rawData = reinterpret_cast(&land.getLandData()->mTextures[0]); + return QByteArray(rawData, Size); + } + else + { + return QByteArray(Size, 0); + } } void LandTexturesColumn::set(Record& record, const QVariant& data) { - Land copy = record.get(); - Land::LandData* landData = copy.getLandData(); - assert (landData); - QByteArray array = data.toByteArray(); const uint16_t* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); + Land copy = record.get(); + copy.setDataLoaded(Land::DATA_VTEX); + int count = array.count() / sizeof(uint16_t); for (int i = 0; i < count; ++i) { - landData->mTextures[i] = rawData[i]; + copy.getLandData()->mTextures[i] = rawData[i]; } record.setModified(copy); diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 127ffde2c..b41eea8f8 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -356,6 +356,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import // Try a direct mapping to the current plugin first. Otherwise iterate until one is found. // Iteration is deterministic to avoid duplicates. + int startIndex = index; do { std::string newId = LandTexture::createUniqueRecordId(0, index); int newRow = idCollection()->searchId(newId); @@ -384,7 +385,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import size_t Prime = (1 << 13) - 1; // A mersenne prime index = (index + Prime) % MaxIndex; - } while (true); + } while (index != startIndex); } return results; diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 1c1d496bb..552a54ac2 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -26,6 +26,33 @@ #include "terrainstorage.hpp" #include "object.hpp" +namespace CSVRender +{ + class CellNodeContainer : public osg::Referenced + { + public: + + CellNodeContainer(Cell* cell) : mCell(cell) {} + + Cell* getCell(){ return mCell; } + + private: + + Cell* mCell; + }; + + class CellNodeCallback : public osg::NodeCallback + { + public: + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + CellNodeContainer* container = static_cast(node->getUserData()); + container->getCell()->updateLand(); + } + }; +} + bool CSVRender::Cell::removeObject (const std::string& id) { std::map::iterator iter = @@ -77,6 +104,11 @@ bool CSVRender::Cell::addObjects (int start, int end) void CSVRender::Cell::updateLand() { + if (!mUpdateLand || mLandDeleted) + return; + + mUpdateLand = false; + // Cell is deleted if (mDeleted) { @@ -116,6 +148,7 @@ void CSVRender::Cell::updateLand() } // No land data + mLandDeleted = true; unloadLand(); } @@ -131,7 +164,7 @@ void CSVRender::Cell::unloadLand() CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, bool deleted) : mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted), mSubMode (0), - mSubModeElementMask (0) + mSubModeElementMask (0), mUpdateLand(true), mLandDeleted(false) { std::pair result = CSMWorld::CellCoordinates::fromId (id); @@ -139,6 +172,8 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st mCoordinates = result.first; mCellNode = new osg::Group; + mCellNode->setUserData(new CellNodeContainer(this)); + mCellNode->setUpdateCallback(new CellNodeCallback); rootNode->addChild(mCellNode); setCellMarker(); @@ -325,32 +360,34 @@ void CSVRender::Cell::pathgridRemoved() void CSVRender::Cell::landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { - updateLand(); + mUpdateLand = true; } void CSVRender::Cell::landAboutToBeRemoved (const QModelIndex& parent, int start, int end) { - updateLand(); + mLandDeleted = true; + unloadLand(); } void CSVRender::Cell::landAdded (const QModelIndex& parent, int start, int end) { - updateLand(); + mUpdateLand = true; + mLandDeleted = false; } void CSVRender::Cell::landTextureChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { - updateLand(); + mUpdateLand = true; } void CSVRender::Cell::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end) { - updateLand(); + mUpdateLand = true; } void CSVRender::Cell::landTextureAdded (const QModelIndex& parent, int start, int end) { - updateLand(); + mUpdateLand = true; } void CSVRender::Cell::reloadAssets() diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 101aebd58..444608688 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -57,6 +57,7 @@ namespace CSVRender bool mDeleted; int mSubMode; unsigned int mSubModeElementMask; + bool mUpdateLand, mLandDeleted; /// Ignored if cell does not have an object with the given ID. /// @@ -160,6 +161,8 @@ namespace CSVRender /// Erase all overrides and restore the visual representation of the cell to its /// true state. void reset (unsigned int elementMask); + + friend class CellNodeCallback; }; } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index f597defd7..1d2cf7575 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -322,6 +322,15 @@ namespace ESM return mLandData && (mLandData->mDataLoaded & flags) == (flags & mDataTypes); } + void Land::setDataLoaded(int flags) + { + if (!mLandData) + mLandData = new LandData; + + mDataTypes |= flags; + mLandData->mDataLoaded |= flags; + } + Land::Land (const Land& land) : mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin), mContext (land.mContext), mDataTypes (land.mDataTypes), diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index d7b736f99..7be954b3e 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -135,6 +135,9 @@ struct Land /// @note We only check data types that *can* be loaded (present in mDataTypes) bool isDataLoaded(int flags) const; + /// Sets the flags and creates a LandData if needed + void setDataLoaded(int flags); + Land (const Land& land); Land& operator= (Land land); From 9503d6186640a3c578e424c98ccf65f5c8ca3a76 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 9 Sep 2017 23:22:16 +0300 Subject: [PATCH 029/505] Use const nodeMap in creature animation --- apps/openmw/mwrender/creatureanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 2ad362b33..735c0b66d 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -118,7 +118,7 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) osg::ref_ptr node = mResourceSystem->getSceneManager()->getInstance(item.getClass().getModel(item)); const NodeMap& nodeMap = getNodeMap(); - NodeMap::const_iterator found = getNodeMap().find(Misc::StringUtils::lowerCase(bonename)); + NodeMap::const_iterator found = nodeMap.find(Misc::StringUtils::lowerCase(bonename)); if (found == nodeMap.end()) throw std::runtime_error("Can't find attachment node " + bonename); osg::ref_ptr attached = SceneUtil::attach(node, mObjectRoot, bonename, found->second.get()); From de14e436803ac3ddb8ad9836d7ce5d90e9a13b68 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 10 Sep 2017 03:18:22 +0100 Subject: [PATCH 030/505] Seemingly fix everything by setting policies that were unset upon entering the macro --- cmake/OpenMWMacros.cmake | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 11f230ac6..6686ea131 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -163,13 +163,11 @@ macro (openmw_add_executable target) set(OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE EXCLUDE_FROM_ALL) endif (OMW_ADD_EXE_EXCLUDE_FROM_ALL) - message("Target: " ${target}) - message("WIN32: ${OMW_ADD_EXE_WIN32_VALUE}") - message("MACOSX_BUNDLE: ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE}") - message("EXCLUDE_FROM_ALL: ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE}") - message("Unparsed: ${OMW_ADD_EXE_UNPARSED_ARGUMENTS}") + # AnyOldName3 says: I have no idea why or if it's even supposed to happen, but somehow entering this macro confuses CMake about which policies should be set. They are restored here. + cmake_policy(SET CMP0003 NEW) + cmake_policy(SET CMP0020 NEW) - add_executable(${target} ${OMW_ADD_EXE_WIN32_VALUE} ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE} ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE} "${OMW_ADD_EXE_UNPARSED_ARGUMENTS}") + add_executable(${target} ${OMW_ADD_EXE_WIN32_VALUE} ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE} ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE} ${OMW_ADD_EXE_UNPARSED_ARGUMENTS}) if (MSVC) if (CMAKE_VERSION VERSION_GREATER 3.8 OR CMAKE_VERSION VERSION_EQUAL 3.8) From 09e645a0e094950891ec19a7a4dc210a0fd11ae5 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 9 Sep 2017 23:18:09 -0400 Subject: [PATCH 031/505] Fix careless mistake. --- components/esm/loadland.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 1d2cf7575..083f27cef 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -238,10 +238,9 @@ namespace ESM // Copy data to target if no file if (mContext.filename.empty()) { - if (mLandData) + // Make sure there is data, and that it doesn't point to the same object. + if (mLandData && mLandData != target) *target = *mLandData; - else - target = new LandData; return; } From 661232222f428598e5659f8a277a426434318551 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 10 Sep 2017 15:26:48 +0400 Subject: [PATCH 032/505] Allow guards to attack fighting creatures only in fAlarmRadius range --- apps/openmw/mwmechanics/actors.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ed510e616..d15e1a1a5 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -394,10 +394,15 @@ namespace MWMechanics aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2); } } - + // Make guards go aggressive with creatures that are in combat, unless the creature is a follower or escorter if (actor1.getClass().isClass(actor1, "Guard") && !actor2.getClass().isNpc()) { + // Check if the creature is too far + static const float fAlarmRadius = MWBase::Environment::get().getWorld()->getStore().get().find("fAlarmRadius")->getFloat(); + if (sqrDist > fAlarmRadius * fAlarmRadius) + return; + bool followerOrEscorter = false; for (std::list::const_iterator it = creatureStats2.getAiSequence().begin(); it != creatureStats2.getAiSequence().end(); ++it) { From afbdc27a34995e0bcef7386c4229cdedc3777f0c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 10 Sep 2017 18:30:10 +0100 Subject: [PATCH 033/505] Move calls to cmake_minimum_required as early in the CMake process as possible. --- CMakeLists.txt | 71 +++++++++++++++++++++------------------- cmake/OpenMWMacros.cmake | 4 --- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a78eac572..0050104cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,40 @@ +# Apps and tools +option(BUILD_OPENMW "build OpenMW" ON) +option(BUILD_BSATOOL "build BSA extractor" ON) +option(BUILD_ESMTOOL "build ESM inspector" ON) +option(BUILD_LAUNCHER "build Launcher" ON) +option(BUILD_MWINIIMPORTER "build MWiniImporter" ON) +option(BUILD_ESSIMPORTER "build ESS (Morrowind save game) importer" ON) +option(BUILD_OPENCS "build OpenMW Construction Set" ON) +option(BUILD_WIZARD "build Installation Wizard" ON) +option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) +option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF) +option(BUILD_NIFTEST "build nif file tester" OFF) +option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON) +option(BUILD_DOCS "build documentation." OFF ) + +if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD) + set(USE_QT FALSE) +else() + set(USE_QT TRUE) +endif() + +if (USE_QT) + set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") + set_property(CACHE DESIRED_QT_VERSION PROPERTY STRINGS 4 5) +endif() + +if (APPLE) + # OS X build process relies on this fix: https://github.com/Kitware/CMake/commit/3df5147043d83aa09acd5c9ce31d5c602efb99db + cmake_minimum_required(VERSION 3.1.0) +elseif (USE_QT AND DESIRED_QT_VERSION MATCHES 5) + # 2.8.11+ is required to make Qt5 happy and allow linking QtMain on Windows. + cmake_minimum_required(VERSION 2.8.11) +else() + # We probably support older versions than this. + cmake_minimum_required(VERSION 2.6) +endif() + project(OpenMW) # If the user doesn't supply a CMAKE_BUILD_TYPE via command line, choose one for them. @@ -59,21 +96,6 @@ option(QT_STATIC "Link static build of QT into the binaries" FALSE) option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE) -# Apps and tools -option(BUILD_OPENMW "build OpenMW" ON) -option(BUILD_BSATOOL "build BSA extractor" ON) -option(BUILD_ESMTOOL "build ESM inspector" ON) -option(BUILD_LAUNCHER "build Launcher" ON) -option(BUILD_MWINIIMPORTER "build MWiniImporter" ON) -option(BUILD_ESSIMPORTER "build ESS (Morrowind save game) importer" ON) -option(BUILD_OPENCS "build OpenMW Construction Set" ON) -option(BUILD_WIZARD "build Installation Wizard" ON) -option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) -option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF) -option(BUILD_NIFTEST "build nif file tester" OFF) -option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON) -option(BUILD_DOCS "build documentation." OFF ) - # what is necessary to build documentation IF( BUILD_DOCS ) # Builds the documentation. @@ -120,16 +142,8 @@ if (WIN32) option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON) endif() -if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD) - set(USE_QT FALSE) -else() - set(USE_QT TRUE) -endif() - # Dependencies if (USE_QT) - set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") - set_property(CACHE DESIRED_QT_VERSION PROPERTY STRINGS 4 5) message(STATUS "Using Qt${DESIRED_QT_VERSION}") if (DESIRED_QT_VERSION MATCHES 4) @@ -144,17 +158,6 @@ if (USE_QT) endif() endif() -if (APPLE) - # OS X build process relies on this fix: https://github.com/Kitware/CMake/commit/3df5147043d83aa09acd5c9ce31d5c602efb99db - cmake_minimum_required(VERSION 3.1.0) -elseif (USE_QT AND DESIRED_QT_VERSION MATCHES 5) - # 2.8.11+ is required to make Qt5 happy and allow linking QtMain on Windows. - cmake_minimum_required(VERSION 2.8.11) -else() - # We probably support older versions than this. - cmake_minimum_required(VERSION 2.6) -endif() - # Sound setup find_package(FFmpeg REQUIRED COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE) # Required for building the FFmpeg headers diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 6686ea131..6573265bd 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -163,10 +163,6 @@ macro (openmw_add_executable target) set(OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE EXCLUDE_FROM_ALL) endif (OMW_ADD_EXE_EXCLUDE_FROM_ALL) - # AnyOldName3 says: I have no idea why or if it's even supposed to happen, but somehow entering this macro confuses CMake about which policies should be set. They are restored here. - cmake_policy(SET CMP0003 NEW) - cmake_policy(SET CMP0020 NEW) - add_executable(${target} ${OMW_ADD_EXE_WIN32_VALUE} ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE} ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE} ${OMW_ADD_EXE_UNPARSED_ARGUMENTS}) if (MSVC) From 97ff24b8d6ffcbbb80b52725358ed8a683712c28 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 10 Sep 2017 20:48:09 +0300 Subject: [PATCH 034/505] Change ctl to ctrl in OpenMW-CS shortcut manager --- apps/opencs/model/prefs/shortcutmanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index 6ae778fff..c4b46958d 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -132,7 +132,7 @@ namespace CSMPrefs if (mods && i == 0) { if (mods & Qt::ControlModifier) - result.append("Ctl+"); + result.append("Ctrl+"); if (mods & Qt::ShiftModifier) result.append("Shift+"); if (mods & Qt::AltModifier) @@ -196,7 +196,7 @@ namespace CSMPrefs std::string name = value.substr(start, end - start); - if (name == "Ctl") + if (name == "Ctrl") { mods |= Qt::ControlModifier; } From c6fd75bf42cd3a167282107329e79bef5053d51a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 10 Sep 2017 14:21:05 +0400 Subject: [PATCH 035/505] Take in account elemental shields for GetResist and SetResist script commands (bug #4093) --- apps/openmw/mwscript/statsextensions.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 6b1953917..70910ec2f 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1189,6 +1189,14 @@ namespace MWScript if (mNegativeEffect != -1) currentValue -= effects.get(mNegativeEffect).getMagnitude(); + // GetResist* should take in account elemental shields + if (mPositiveEffect == ESM::MagicEffect::ResistFire) + currentValue += effects.get(ESM::MagicEffect::FireShield).getMagnitude(); + if (mPositiveEffect == ESM::MagicEffect::ResistShock) + currentValue += effects.get(ESM::MagicEffect::LightningShield).getMagnitude(); + if (mPositiveEffect == ESM::MagicEffect::ResistFrost) + currentValue += effects.get(ESM::MagicEffect::FrostShield).getMagnitude(); + int ret = static_cast(currentValue); runtime.push(ret); } @@ -1215,6 +1223,14 @@ namespace MWScript if (mNegativeEffect != -1) currentValue -= effects.get(mNegativeEffect).getMagnitude(); + // SetResist* should take in account elemental shields + if (mPositiveEffect == ESM::MagicEffect::ResistFire) + currentValue += effects.get(ESM::MagicEffect::FireShield).getMagnitude(); + if (mPositiveEffect == ESM::MagicEffect::ResistShock) + currentValue += effects.get(ESM::MagicEffect::LightningShield).getMagnitude(); + if (mPositiveEffect == ESM::MagicEffect::ResistFrost) + currentValue += effects.get(ESM::MagicEffect::FrostShield).getMagnitude(); + int arg = runtime[0].mInteger; runtime.pop(); effects.modifyBase(mPositiveEffect, (arg - static_cast(currentValue))); From 7760e4514c767e266bd72697567f4b9868653ed8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 10 Sep 2017 22:47:34 +0400 Subject: [PATCH 036/505] Allow to add levelup a description for levels > 20 --- apps/openmw/mwgui/levelupdialog.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 362ad3b1c..da8e93279 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -143,10 +143,10 @@ namespace MWGui mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + MyGUI::utility::toString(level)); std::string levelupdescription; - if(level > 20) + levelupdescription=world->getFallback()->getFallbackString("Level_Up_Level"+MyGUI::utility::toString(level)); + + if (levelupdescription == "") levelupdescription=world->getFallback()->getFallbackString("Level_Up_Default"); - else - levelupdescription=world->getFallback()->getFallbackString("Level_Up_Level"+MyGUI::utility::toString(level)); mLevelDescription->setCaption (levelupdescription); From 5904e5a267741c230cee1b2bb258693ed7781d48 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 11 Sep 2017 10:47:35 +0200 Subject: [PATCH 037/505] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index bb773c4ef..d9782ccf3 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -34,6 +34,7 @@ Programmers Ben Shealy (bentsherman) Bret Curtis (psi29a) Britt Mathis (galdor557) + Capostrophic cc9cii Chris Boyce (slothlife) Chris Robinson (KittyCat) From 7e83caab11c5ad3b1cc2935bf9fb71811b095c5c Mon Sep 17 00:00:00 2001 From: David Walley <31402617+loriel2@users.noreply.github.com> Date: Wed, 13 Sep 2017 12:11:01 +0100 Subject: [PATCH 038/505] Manual modding - extend mod installation instructions (#1448) Add section on .bsa files Extend plugins to include .esm files Fix typo propper->proper. --- docs/source/manuals/openmw-cs/tour.rst | 2 -- docs/source/reference/modding/mod-install.rst | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/source/manuals/openmw-cs/tour.rst b/docs/source/manuals/openmw-cs/tour.rst index bb1097e0c..b1b147992 100644 --- a/docs/source/manuals/openmw-cs/tour.rst +++ b/docs/source/manuals/openmw-cs/tour.rst @@ -219,5 +219,3 @@ Subsection to come... ===================== - - diff --git a/docs/source/reference/modding/mod-install.rst b/docs/source/reference/modding/mod-install.rst index a72678173..e62c27fc1 100644 --- a/docs/source/reference/modding/mod-install.rst +++ b/docs/source/reference/modding/mod-install.rst @@ -9,7 +9,7 @@ Install #. Your mod probably comes in some kind of archive, such as ``.zip``, ``.rar``, ``.7z``, or something along those lines. Unpack this archive into its own folder. #. Ensure the structure of this folder is correct. - #. Locate the plugin files, ``.esp`` or ``.omwaddon``. The folder containing the plugin files we will call your *data folder* + #. Locate the plugin files, ``.esp`` or ``.omwaddon``, or possibly ``.esm``. The folder containing the plugin files we will call your *data folder* #. Check that all resource folders (``Meshes``, ``Textures``, etc.) containing additional resource files (the actual meshes, textures, etc.) are in the *data folder*. .. note:: @@ -18,9 +18,10 @@ Install #. Open your ``openmw.cfg`` file in your preferred plain text editor. It is located as described in :doc:`paths` and *not* in your OpenMW root directory. #. Find or search for ``data=``. This is located very near the bottom of the file. If you are using Morrowind, this first entry should already point to your Morrowind data directory, ``Data Files``; otherwise it will point to your game file, ``.omwgame``. #. Create a new line underneath and type: ``data="path/to/your/data folder"`` Remember, the *data folder* is where your mod's plugin files are. The double quotes around this path name are *required*. +#. If your mod contains resources in a ``.bsa`` file, go to near the top of the file, locate the entries like ''fallback-archive=Morrowind.bsa'' and create a new line underneath and type: ``fallback-archive=.bsa''``. .. note:: - Some text editors, such as TextEdit on Mac, will autocorrect your double quotes to typographical "curly" quotes instead of leaving them as the propper neutral vertical quotes ``""``. + Some text editors, such as TextEdit on Mac, will autocorrect your double quotes to typographical "curly" quotes instead of leaving them as the proper neutral vertical quotes ``""``. #. Save your ``openmw.cfg`` file. From b9de4b1eac5b77708f36c71ca1185d89e7a9665a Mon Sep 17 00:00:00 2001 From: David Walley <31402617+loriel2@users.noreply.github.com> Date: Wed, 13 Sep 2017 12:27:51 +0100 Subject: [PATCH 039/505] Update tour.rst --- docs/source/manuals/openmw-cs/tour.rst | 85 ++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/docs/source/manuals/openmw-cs/tour.rst b/docs/source/manuals/openmw-cs/tour.rst index b1b147992..fedd42462 100644 --- a/docs/source/manuals/openmw-cs/tour.rst +++ b/docs/source/manuals/openmw-cs/tour.rst @@ -218,4 +218,89 @@ actually modify the contents of the game. Subsection to come... ===================== +Adding to an npc +**************** + +The simplest way is probably to add it to the inventory of a shopkeeper. +An obvious candidate is Arrille in Seyda Neen - he's quick to find in a new game +and he's easy to find in the CS as his name comes early alphabetically. + +.. figure:: _static/images/chapter-1/Ring_to_Arrille.png + :alt: Putting the ring into Arrille's inventory + +Open the CS and open the *Objects* table (*World* → *Objects*). +Scroll down to Arrille, or use a filter like !string("ID","arrille"). + +Open another pane to edit him - either right click and select edit or use the +shortcut (default is shift double-click). Scroll down to the inventory section +and right click to add a new row. Type in the id of the ring (or find it in the +object pane, and drag and drop). Set the number of rings for him to stock - with +a negative number indicating that he will restock again to maintain that level. + +However, it's an attractive item, so he will probably wear it rather than sell it. +So set his stock level too high for him to wear them all (3 works, 2 might do). + +Another possibilty, again in Seyda Neen making it easy to access, would be for +Fargoth to give it to the player in exchange for his healing ring. + +.. figure:: _static/images/chapter-1/Ring_to_Fargoth_1.png + :alt: Editing Fargoth to give ring to player + +Open the *Topicinfo* Table (*Characters* → *Topic Infos*). Use a filter !string(Topic,ring) +and select the row with a response starting with "You found it!". Edit the record, +firstly by adding a bit more to the response, then by adding a line to the script +to give the ring to the player - the same as used earlier in the console +.. code:: + + player->AddItem "ring_night_vision" 1 + +.. figure:: _static/images/chapter-1/Ring_to_Fargoth_2.png + :alt: Editing Fargoth to give ring to player + +Navigation in the CS +==================== +This is probably a suitable place to start talking about how navigation differs from TESCS +in vanilla Morrowind. + +There is advice in Scripting for Dummies, the definitive manual for Morrowind Scripting: +"If you give your scripts a common tag, that will make it easier to jump between the +different scripts of your project, e.g. start every script name with AA_Scriptname +this will put them right at the beginning of the list and keep them neatly together." + +This is valid for the rather poorer navigation facilities there, but it's not sensible for +the OpenMW CS. Some modders took it further, and started script names and object id with numbers, +typically "1", to bring the items even earlier in the default alphabetical sorts. In fact +the CS won't allow names/ids to start with numbers or to include ".". + +There are better options available: + +Filtering, which isn't available at all in TESCS - put in a filter like + +!string("ID",".*ring.*") + +to find all IDs which contain the string "ring" + +Sorting, which is available in some parts of TESCS, but not for scripts (other than script names being +sorted in ascending order)- hence the recommendation +Typically the "Modified" column is useful here - most items will have "Base" status, unchanged from +the base game. + +"Added" status" will cover those items added in this addon. + +"Modified" status will cover items from the base game which have been modified in this addon. + +Click on the top of the column to toggle between ascending and descending order - thus between "Added" +and "Modified" at the top. Or put your desired modified status into a filter then sort alpabetically +on a different column. + + + +Checking your new addon +======================= + +Launch OpenMW and in the launcher under *Data Files* check your addon, if it's not +already checked. Load a game and make your way to Seyda Neen - or start a new game. + +Check whether Arrille has one (or more) for sale, and whether Fargoth give you one +when you return his healing ring. From b26887ef9bd49cf2fc3dab700605e16aea0a0811 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 13 Sep 2017 13:52:05 +0200 Subject: [PATCH 040/505] add support for png and dds splashscreens to begin with. --- apps/openmw/mwgui/loadingscreen.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index c5836b653..946751f68 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -65,16 +65,26 @@ namespace MWGui const std::map& index = mVFS->getIndex(); std::string pattern = "Splash/"; mVFS->normalizeFilename(pattern); + std::list supported_extensions = {".tga", ".png", ".dds"}; /* priority given to the left */ - std::map::const_iterator found = index.lower_bound(pattern); + auto found = index.lower_bound(pattern); while (found != index.end()) { const std::string& name = found->first; if (name.size() >= pattern.size() && name.substr(0, pattern.size()) == pattern) { size_t pos = name.find_last_of('.'); - if (pos != std::string::npos && name.compare(pos, name.size()-pos, ".tga") == 0) - mSplashScreens.push_back(found->first); + if (pos != std::string::npos) + { + for(auto const extension: supported_extensions) + { + if (name.compare(pos, name.size() - pos, extension) == 0) + { + mSplashScreens.push_back(found->first); + break; /* based on priority */ + } + } + } } else break; From dff0a766a8b5435b5a01d3bc9771f6c62bf140d1 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 13 Sep 2017 15:30:22 +0200 Subject: [PATCH 041/505] adding 3 more extensions --- apps/openmw/mwgui/loadingscreen.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 946751f68..41d7efb41 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -65,7 +65,9 @@ namespace MWGui const std::map& index = mVFS->getIndex(); std::string pattern = "Splash/"; mVFS->normalizeFilename(pattern); - std::list supported_extensions = {".tga", ".png", ".dds"}; /* priority given to the left */ + + /* priority given to the left */ + std::list supported_extensions = {".tga", ".dds", ".png", ".bmp", ".jpeg", ".jpg"}; auto found = index.lower_bound(pattern); while (found != index.end()) From e517ad3f7b5630c342e60bcf2087da4165359baa Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Thu, 14 Sep 2017 10:06:36 +0200 Subject: [PATCH 042/505] add ktx support for splashscreens --- apps/openmw/mwgui/loadingscreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 41d7efb41..15d9d555f 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -67,7 +67,7 @@ namespace MWGui mVFS->normalizeFilename(pattern); /* priority given to the left */ - std::list supported_extensions = {".tga", ".dds", ".png", ".bmp", ".jpeg", ".jpg"}; + std::list supported_extensions = {".tga", ".dds", ".ktx", ".png", ".bmp", ".jpeg", ".jpg"}; auto found = index.lower_bound(pattern); while (found != index.end()) From 6e869c3123cd4879348b25d1167c62a6ea90bca4 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Tue, 12 Sep 2017 21:11:30 +0200 Subject: [PATCH 043/505] ESS-Importer: Convert ballistic projectiles (Feature #2320) --- apps/essimporter/CMakeLists.txt | 1 + apps/essimporter/converter.cpp | 84 ++++++++++++++++++++++++++-- apps/essimporter/converter.hpp | 12 ++++ apps/essimporter/importer.cpp | 14 +++++ apps/essimporter/importercontext.hpp | 10 ++++ apps/essimporter/importproj.cpp | 18 ++++++ apps/essimporter/importproj.h | 47 ++++++++++++++++ 7 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 apps/essimporter/importproj.cpp create mode 100644 apps/essimporter/importproj.h diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 82182b7fa..fc5fae72e 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -16,6 +16,7 @@ set(ESSIMPORTER_FILES importjour.cpp importscri.cpp importscpt.cpp + importproj.cpp importercontext.cpp converter.cpp convertacdt.cpp diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 68ee93c89..5c65332be 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "convertcrec.hpp" #include "convertcntc.hpp" @@ -53,6 +54,36 @@ namespace return true; return false; } + + void splitIndexedRefId(const std::string& indexedRefId, int& refIndex, std::string& refId) + { + std::stringstream stream; + stream << std::hex << indexedRefId.substr(indexedRefId.size()-8,8); + stream >> refIndex; + + refId = indexedRefId.substr(0,indexedRefId.size()-8); + } + + int convertActorId(const std::string& indexedRefId, ESSImport::Context& context) + { + if (isIndexedRefId(indexedRefId)) + { + int refIndex; + std::string refId; + splitIndexedRefId(indexedRefId, refIndex, refId); + + auto it = context.mActorIdMap.find(std::make_pair(refIndex, refId)); + if (it == context.mActorIdMap.end()) + return -1; + return it->second; + } + else if (indexedRefId == "PlayerSaveGame") + { + return context.mPlayer.mObject.mCreatureStats.mActorId; + } + + return -1; + } } namespace ESSImport @@ -322,12 +353,9 @@ namespace ESSImport } else { - std::stringstream stream; - stream << std::hex << cellref.mIndexedRefId.substr(cellref.mIndexedRefId.size()-8,8); int refIndex; - stream >> refIndex; + splitIndexedRefId(cellref.mIndexedRefId, refIndex, out.mRefID); - out.mRefID = cellref.mIndexedRefId.substr(0,cellref.mIndexedRefId.size()-8); std::string idLower = Misc::StringUtils::lowerCase(out.mRefID); std::map, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find( @@ -347,6 +375,10 @@ namespace ESSImport convertNpcData(cellref, objstate.mNpcStats); convertNPCC(npccIt->second, objstate); convertCellRef(cellref, objstate); + + objstate.mCreatureStats.mActorId = mContext->generateActorId(); + mContext->mActorIdMap.insert(std::make_pair(std::make_pair(refIndex, out.mRefID), objstate.mCreatureStats.mActorId)); + esm.writeHNT ("OBJE", ESM::REC_NPC_); objstate.save(esm); continue; @@ -383,6 +415,10 @@ namespace ESSImport convertACSC(cellref.mACSC, objstate.mCreatureStats); convertCREC(crecIt->second, objstate); convertCellRef(cellref, objstate); + + objstate.mCreatureStats.mActorId = mContext->generateActorId(); + mContext->mActorIdMap.insert(std::make_pair(std::make_pair(refIndex, out.mRefID), objstate.mCreatureStats.mActorId)); + esm.writeHNT ("OBJE", ESM::REC_CREA); objstate.save(esm); continue; @@ -413,4 +449,44 @@ namespace ESSImport } } + void ConvertPROJ::read(ESM::ESMReader& esm) + { + mProj.load(esm); + } + + void ConvertPROJ::write(ESM::ESMWriter& esm) + { + for (const PROJ::PNAM& pnam : mProj.mProjectiles) + { + if (!pnam.isMagic()) + { + ESM::ProjectileState out; + out.mId = pnam.mArrowId.toString(); + out.mPosition = pnam.mPosition; + out.mOrientation.mValues[0] = out.mOrientation.mValues[1] = out.mOrientation.mValues[2] = 0.0f; + out.mOrientation.mValues[3] = 1.0f; + out.mActorId = convertActorId(pnam.mActorId.toString(), *mContext); + + out.mBowId = pnam.mBowId.toString(); + out.mVelocity = pnam.mVelocity; + out.mAttackStrength = pnam.mAttackStrength; + + esm.startRecord(ESM::REC_PROJ); + out.save(esm); + esm.endRecord(ESM::REC_PROJ); + } + else + { + // TODO: Implement magic projectile conversion. + + /*esm.startRecord(ESM::REC_MPRJ); + out.save(esm); + esm.endRecord(ESM::REC_MPRJ);*/ + + std::cerr << "Warning: Skipped conversion for magic projectile \"" << pnam.mArrowId.toString() << "\" (not implemented)" << std::endl; + continue; + } + } + } + } diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index e4985f993..a640d6756 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -35,6 +35,7 @@ #include "importques.hpp" #include "importjour.hpp" #include "importscpt.hpp" +#include "importproj.h" #include "convertacdt.hpp" #include "convertnpcc.hpp" @@ -593,6 +594,17 @@ private: std::vector mScripts; }; +/// Projectile converter +class ConvertPROJ : public Converter +{ +public: + virtual int getStage() override { return 2; } + virtual void read(ESM::ESMReader& esm) override; + virtual void write(ESM::ESMWriter& esm) override; +private: + PROJ mProj; +}; + } #endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index d38069d89..4c8222c56 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -303,6 +303,7 @@ namespace ESSImport converters[ESM::REC_QUES] = std::shared_ptr(new ConvertQUES()); converters[recJOUR ] = std::shared_ptr(new ConvertJOUR()); converters[ESM::REC_SCPT] = std::shared_ptr(new ConvertSCPT()); + converters[ESM::REC_PROJ] = std::shared_ptr(new ConvertPROJ()); // TODO: // - REGN (weather in certain regions?) @@ -420,6 +421,19 @@ namespace ESSImport context.mPlayer.save(writer); writer.endRecord(ESM::REC_PLAY); + writer.startRecord(ESM::REC_ACTC); + writer.writeHNT("COUN", context.mNextActorId); + writer.endRecord(ESM::REC_ACTC); + + // Stage 2 requires cell references to be written / actors IDs assigned + for (std::map >::const_iterator it = converters.begin(); + it != converters.end(); ++it) + { + if (it->second->getStage() != 2) + continue; + it->second->write(writer); + } + writer.startRecord (ESM::REC_DIAS); context.mDialogueState.save(writer); writer.endRecord(ESM::REC_DIAS); diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 0ad73c267..eb6ca9336 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -48,6 +48,9 @@ namespace ESSImport std::map, NPCC> mNpcChanges; std::map, CNTC> mContainerChanges; + std::map, int> mActorIdMap; + int mNextActorId; + std::map mCreatures; std::map mNpcs; @@ -56,6 +59,7 @@ namespace ESSImport , mMonth(0) , mYear(0) , mHour(0.f) + , mNextActorId(0) { mPlayer.mAutoMove = 0; ESM::CellId playerCellId; @@ -71,12 +75,18 @@ namespace ESSImport mPlayer.mObject.blank(); mPlayer.mObject.mEnabled = true; mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame + mPlayer.mObject.mCreatureStats.mActorId = generateActorId(); mGlobalMapState.mBounds.mMinX = 0; mGlobalMapState.mBounds.mMaxX = 0; mGlobalMapState.mBounds.mMinY = 0; mGlobalMapState.mBounds.mMaxY = 0; } + + int generateActorId() + { + return mNextActorId++; + } }; } diff --git a/apps/essimporter/importproj.cpp b/apps/essimporter/importproj.cpp new file mode 100644 index 000000000..b2dcf4e7d --- /dev/null +++ b/apps/essimporter/importproj.cpp @@ -0,0 +1,18 @@ +#include "importproj.h" + +#include + +namespace ESSImport +{ + +void ESSImport::PROJ::load(ESM::ESMReader& esm) +{ + while (esm.isNextSub("PNAM")) + { + PNAM pnam; + esm.getHT(pnam); + mProjectiles.push_back(pnam); + } +} + +} diff --git a/apps/essimporter/importproj.h b/apps/essimporter/importproj.h new file mode 100644 index 000000000..b8abab5fa --- /dev/null +++ b/apps/essimporter/importproj.h @@ -0,0 +1,47 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTPROJ_H +#define OPENMW_ESSIMPORT_IMPORTPROJ_H + +#include +#include +#include + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + +struct PROJ +{ + +#pragma pack(push) +#pragma pack(1) + struct PNAM // 184 bytes + { + float mAttackStrength; + float mSpeed; + unsigned char mUnknown[4*2]; + float mFlightTime; + int mSplmIndex; // reference to a SPLM record (0 for ballistic projectiles) + unsigned char mUnknown2[4]; + ESM::Vector3 mVelocity; + ESM::Vector3 mPosition; + unsigned char mUnknown3[4*9]; + ESM::NAME32 mActorId; // indexed refID (with the exception of "PlayerSaveGame") + ESM::NAME32 mArrowId; + ESM::NAME32 mBowId; + + bool isMagic() const { return mSplmIndex != 0; } + }; +#pragma pack(pop) + + std::vector mProjectiles; + + void load(ESM::ESMReader& esm); +}; + +} + +#endif From a66d310a1d1d266da479b3e4fe7a3d35b94ce325 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Fri, 15 Sep 2017 00:21:02 +0200 Subject: [PATCH 044/505] ESS-Importer: Fix uninitialized paid crime ID --- apps/essimporter/importercontext.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index eb6ca9336..4896f5594 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -71,7 +71,8 @@ namespace ESSImport = mPlayer.mLastKnownExteriorPosition[2] = 0.0f; mPlayer.mHasMark = 0; - mPlayer.mCurrentCrimeId = 0; // TODO + mPlayer.mCurrentCrimeId = -1; // TODO + mPlayer.mPaidCrimeId = -1; mPlayer.mObject.blank(); mPlayer.mObject.mEnabled = true; mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame From 1fe60dd8e23ffe34c6ddad66b4829f3a4253e38f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 11 Sep 2017 21:33:18 -0700 Subject: [PATCH 045/505] Replace some shared_ptrs with pointers to deque entries --- apps/openmw/mwbase/soundmanager.hpp | 29 ++-- apps/openmw/mwsound/movieaudiofactory.cpp | 12 +- apps/openmw/mwsound/openal_output.cpp | 26 +-- apps/openmw/mwsound/openal_output.hpp | 33 ++-- apps/openmw/mwsound/sound.hpp | 46 +++-- apps/openmw/mwsound/sound_output.hpp | 29 ++-- apps/openmw/mwsound/soundmanagerimp.cpp | 202 ++++++++++++++-------- apps/openmw/mwsound/soundmanagerimp.hpp | 44 +++-- apps/openmw/mwworld/projectilemanager.cpp | 6 +- apps/openmw/mwworld/projectilemanager.hpp | 2 +- apps/openmw/mwworld/weather.cpp | 8 +- apps/openmw/mwworld/weather.hpp | 2 +- 12 files changed, 262 insertions(+), 177 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 9aa4bafdf..9986564cd 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -22,8 +22,8 @@ namespace MWSound namespace MWBase { - typedef std::shared_ptr SoundPtr; - typedef std::shared_ptr SoundStreamPtr; + using Sound = MWSound::Sound; + using SoundStream = MWSound::Stream; /// \brief Interface for sound manager (implemented in MWSound) class SoundManager @@ -106,34 +106,35 @@ namespace MWBase /// and get an average loudness value (scale [0,1]) at the current time position. /// If the actor is not saying anything, returns 0. - virtual SoundStreamPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; + virtual SoundStream *playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; ///< Play a 2D audio track, using a custom decoder - virtual void stopTrack(SoundStreamPtr stream) = 0; + virtual void stopTrack(SoundStream *stream) = 0; ///< Stop the given audio track from playing - virtual double getTrackTimeDelay(SoundStreamPtr stream) = 0; + virtual double getTrackTimeDelay(SoundStream *stream) = 0; ///< Retives the time delay, in seconds, of the audio track (must be a sound /// returned by \ref playTrack). Only intended to be called by the track /// decoder's read method. - virtual SoundPtr playSound(const std::string& soundId, float volume, float pitch, - PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, - float offset=0) = 0; + virtual Sound *playSound(const std::string& soundId, float volume, float pitch, + PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, + float offset=0) = 0; ///< Play a sound, independently of 3D-position ///< @param offset Number of seconds into the sound to start playback. - virtual MWBase::SoundPtr playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, - float volume, float pitch, PlayType type=Play_TypeSfx, - PlayMode mode=Play_Normal, float offset=0) = 0; + virtual Sound *playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, + float volume, float pitch, PlayType type=Play_TypeSfx, + PlayMode mode=Play_Normal, float offset=0) = 0; ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. ///< @param offset Number of seconds into the sound to start playback. - virtual MWBase::SoundPtr playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, - float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0; + virtual Sound *playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, + float volume, float pitch, PlayType type=Play_TypeSfx, + PlayMode mode=Play_Normal, float offset=0) = 0; ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. - virtual void stopSound(SoundPtr sound) = 0; + virtual void stopSound(Sound *sound) = 0; ///< Stop the given sound from playing virtual void stopSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId) = 0; diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 2d7f3a969..9c9b442c7 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -37,7 +37,7 @@ namespace MWSound { public: MovieAudioDecoder(Video::VideoState *videoState) - : Video::MovieAudioDecoder(videoState) + : Video::MovieAudioDecoder(videoState), mAudioTrack(nullptr) { mDecoderBridge.reset(new MWSoundDecoderBridge(this)); } @@ -85,13 +85,13 @@ namespace MWSound public: ~MovieAudioDecoder() { - if(mAudioTrack.get()) + if(mAudioTrack) MWBase::Environment::get().getSoundManager()->stopTrack(mAudioTrack); - mAudioTrack.reset(); + mAudioTrack = nullptr; mDecoderBridge.reset(); } - MWBase::SoundStreamPtr mAudioTrack; + MWBase::SoundStream *mAudioTrack; std::shared_ptr mDecoderBridge; }; @@ -162,8 +162,8 @@ namespace MWSound decoder->setupFormat(); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - MWBase::SoundStreamPtr sound = sndMgr->playTrack(decoder->mDecoderBridge, MWBase::SoundManager::Play_TypeMovie); - if (!sound.get()) + MWBase::SoundStream *sound = sndMgr->playTrack(decoder->mDecoderBridge, MWBase::SoundManager::Play_TypeMovie); + if (!sound) { decoder.reset(); return decoder; diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 042795a8c..0e000f8d8 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -841,7 +841,7 @@ void OpenAL_Output::updateCommon(ALuint source, const osg::Vec3f& pos, ALfloat m } -void OpenAL_Output::playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset) +void OpenAL_Output::playSound(Sound *sound, Sound_Handle data, float offset) { ALuint source; @@ -871,7 +871,7 @@ void OpenAL_Output::playSound(MWBase::SoundPtr sound, Sound_Handle data, float o sound->mHandle = MAKE_PTRID(source); } -void OpenAL_Output::playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset) +void OpenAL_Output::playSound3D(Sound *sound, Sound_Handle data, float offset) { ALuint source; @@ -902,7 +902,7 @@ void OpenAL_Output::playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float sound->mHandle = MAKE_PTRID(source); } -void OpenAL_Output::finishSound(MWBase::SoundPtr sound) +void OpenAL_Output::finishSound(Sound *sound) { if(!sound->mHandle) return; ALuint source = GET_PTRID(sound->mHandle); @@ -918,7 +918,7 @@ void OpenAL_Output::finishSound(MWBase::SoundPtr sound) mActiveSounds.erase(std::find(mActiveSounds.begin(), mActiveSounds.end(), sound)); } -bool OpenAL_Output::isSoundPlaying(MWBase::SoundPtr sound) +bool OpenAL_Output::isSoundPlaying(Sound *sound) { if(!sound->mHandle) return false; ALuint source = GET_PTRID(sound->mHandle); @@ -930,7 +930,7 @@ bool OpenAL_Output::isSoundPlaying(MWBase::SoundPtr sound) return state == AL_PLAYING || state == AL_PAUSED; } -void OpenAL_Output::updateSound(MWBase::SoundPtr sound) +void OpenAL_Output::updateSound(Sound *sound) { if(!sound->mHandle) return; ALuint source = GET_PTRID(sound->mHandle); @@ -940,7 +940,7 @@ void OpenAL_Output::updateSound(MWBase::SoundPtr sound) } -void OpenAL_Output::streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound) +void OpenAL_Output::streamSound(DecoderPtr decoder, Stream *sound) { OpenAL_SoundStream *stream = 0; ALuint source; @@ -971,7 +971,7 @@ void OpenAL_Output::streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound sound->mHandle = stream; } -void OpenAL_Output::streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound, bool getLoudnessData) +void OpenAL_Output::streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData) { OpenAL_SoundStream *stream = 0; ALuint source; @@ -1002,7 +1002,7 @@ void OpenAL_Output::streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sou sound->mHandle = stream; } -void OpenAL_Output::finishStream(MWBase::SoundStreamPtr sound) +void OpenAL_Output::finishStream(Stream *sound) { if(!sound->mHandle) return; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); @@ -1023,14 +1023,14 @@ void OpenAL_Output::finishStream(MWBase::SoundStreamPtr sound) delete stream; } -double OpenAL_Output::getStreamDelay(MWBase::SoundStreamPtr sound) +double OpenAL_Output::getStreamDelay(Stream *sound) { if(!sound->mHandle) return 0.0; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); return stream->getStreamDelay(); } -double OpenAL_Output::getStreamOffset(MWBase::SoundStreamPtr sound) +double OpenAL_Output::getStreamOffset(Stream *sound) { if(!sound->mHandle) return 0.0; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); @@ -1038,7 +1038,7 @@ double OpenAL_Output::getStreamOffset(MWBase::SoundStreamPtr sound) return stream->getStreamOffset(); } -float OpenAL_Output::getStreamLoudness(MWBase::SoundStreamPtr sound) +float OpenAL_Output::getStreamLoudness(Stream *sound) { if(!sound->mHandle) return 0.0; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); @@ -1046,7 +1046,7 @@ float OpenAL_Output::getStreamLoudness(MWBase::SoundStreamPtr sound) return stream->getCurrentLoudness(); } -bool OpenAL_Output::isStreamPlaying(MWBase::SoundStreamPtr sound) +bool OpenAL_Output::isStreamPlaying(Stream *sound) { if(!sound->mHandle) return false; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); @@ -1054,7 +1054,7 @@ bool OpenAL_Output::isStreamPlaying(MWBase::SoundStreamPtr sound) return stream->isPlaying(); } -void OpenAL_Output::updateStream(MWBase::SoundStreamPtr sound) +void OpenAL_Output::updateStream(Stream *sound) { if(!sound->mHandle) return; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index ea3f393ff..cb943d87e 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -15,6 +15,7 @@ namespace MWSound { class SoundManager; class Sound; + class Stream; class OpenAL_Output : public Sound_Output { @@ -24,9 +25,9 @@ namespace MWSound typedef std::deque IDDq; IDDq mFreeSources; - typedef std::vector SoundVec; + typedef std::vector SoundVec; SoundVec mActiveSounds; - typedef std::vector StreamVec; + typedef std::vector StreamVec; StreamVec mActiveStreams; osg::Vec3f mListenerPos; @@ -56,20 +57,20 @@ namespace MWSound virtual void unloadSound(Sound_Handle data); virtual size_t getSoundDataSize(Sound_Handle data) const; - virtual void playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset); - virtual void playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset); - virtual void finishSound(MWBase::SoundPtr sound); - virtual bool isSoundPlaying(MWBase::SoundPtr sound); - virtual void updateSound(MWBase::SoundPtr sound); - - virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound); - virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound, bool getLoudnessData); - virtual void finishStream(MWBase::SoundStreamPtr sound); - virtual double getStreamDelay(MWBase::SoundStreamPtr sound); - virtual double getStreamOffset(MWBase::SoundStreamPtr sound); - virtual float getStreamLoudness(MWBase::SoundStreamPtr sound); - virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound); - virtual void updateStream(MWBase::SoundStreamPtr sound); + virtual void playSound(Sound *sound, Sound_Handle data, float offset); + virtual void playSound3D(Sound *sound, Sound_Handle data, float offset); + virtual void finishSound(Sound *sound); + virtual bool isSoundPlaying(Sound *sound); + virtual void updateSound(Sound *sound); + + virtual void streamSound(DecoderPtr decoder, Stream *sound); + virtual void streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData); + virtual void finishStream(Stream *sound); + virtual double getStreamDelay(Stream *sound); + virtual double getStreamOffset(Stream *sound); + virtual float getStreamLoudness(Stream *sound); + virtual bool isStreamPlaying(Stream *sound); + virtual void updateStream(Stream *sound); virtual void startUpdate(); virtual void finishUpdate(); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 8c663fb1e..9a3fc4e75 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -54,15 +54,36 @@ namespace MWSound bool getDistanceCull() const { return mFlags&MWBase::SoundManager::Play_RemoveAtDistance; } bool getIs3D() const { return mFlags&Play_3D; } - Sound(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) - : mPos(pos), mVolume(vol), mBaseVolume(basevol), mPitch(pitch) - , mMinDistance(mindist), mMaxDistance(maxdist), mFlags(flags) - , mFadeOutTime(0.0f), mHandle(0) - { } - Sound(float vol, float basevol, float pitch, int flags) - : mPos(0.0f, 0.0f, 0.0f), mVolume(vol), mBaseVolume(basevol), mPitch(pitch) - , mMinDistance(1.0f), mMaxDistance(1000.0f), mFlags(flags) - , mFadeOutTime(0.0f), mHandle(0) + void init(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) + { + mPos = pos; + mVolume = vol; + mBaseVolume = basevol; + mPitch = pitch; + mMinDistance = mindist; + mMaxDistance = maxdist; + mFlags = flags; + mFadeOutTime = 0.0f; + mHandle = nullptr; + } + + void init(float vol, float basevol, float pitch, int flags) + { + mPos = osg::Vec3f(0.0f, 0.0f, 0.0f); + mVolume = vol; + mBaseVolume = basevol; + mPitch = pitch; + mMinDistance = 1.0f; + mMaxDistance = 1000.0f; + mFlags = flags; + mFadeOutTime = 0.0f; + mHandle = nullptr; + } + + Sound() + : mPos(0.0f, 0.0f, 0.0f), mVolume(1.0f), mBaseVolume(1.0f), mPitch(1.0f) + , mMinDistance(1.0f), mMaxDistance(1000.0f), mFlags(0), mFadeOutTime(0.0f) + , mHandle(0) { } }; @@ -72,12 +93,7 @@ namespace MWSound Stream(const Stream &rhs); public: - Stream(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) - : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) - { } - Stream(float vol, float basevol, float pitch, int flags) - : Sound(vol, basevol, pitch, flags) - { } + Stream() { } }; } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index e34d888ee..907a601b5 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -12,6 +12,7 @@ namespace MWSound class SoundManager; struct Sound_Decoder; class Sound; + class Stream; // An opaque handle for the implementation's sound buffers. typedef void *Sound_Handle; @@ -34,20 +35,20 @@ namespace MWSound virtual void unloadSound(Sound_Handle data) = 0; virtual size_t getSoundDataSize(Sound_Handle data) const = 0; - virtual void playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset) = 0; - virtual void playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset) = 0; - virtual void finishSound(MWBase::SoundPtr sound) = 0; - virtual bool isSoundPlaying(MWBase::SoundPtr sound) = 0; - virtual void updateSound(MWBase::SoundPtr sound) = 0; - - virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound) = 0; - virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound, bool getLoudnessData) = 0; - virtual void finishStream(MWBase::SoundStreamPtr sound) = 0; - virtual double getStreamDelay(MWBase::SoundStreamPtr sound) = 0; - virtual double getStreamOffset(MWBase::SoundStreamPtr sound) = 0; - virtual float getStreamLoudness(MWBase::SoundStreamPtr sound) = 0; - virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound) = 0; - virtual void updateStream(MWBase::SoundStreamPtr sound) = 0; + virtual void playSound(Sound *sound, Sound_Handle data, float offset) = 0; + virtual void playSound3D(Sound *sound, Sound_Handle data, float offset) = 0; + virtual void finishSound(Sound *sound) = 0; + virtual bool isSoundPlaying(Sound *sound) = 0; + virtual void updateSound(Sound *sound) = 0; + + virtual void streamSound(DecoderPtr decoder, Stream *sound) = 0; + virtual void streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData) = 0; + virtual void finishStream(Stream *sound) = 0; + virtual double getStreamDelay(Stream *sound) = 0; + virtual double getStreamOffset(Stream *sound) = 0; + virtual float getStreamLoudness(Stream *sound) = 0; + virtual bool isStreamPlaying(Stream *sound) = 0; + virtual void updateStream(Stream *sound) = 0; virtual void startUpdate() = 0; virtual void finishUpdate() = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 15b95b233..f8b753a18 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -46,11 +46,16 @@ namespace MWSound , mFootstepsVolume(1.0f) , mSoundBuffers(new SoundBufferList::element_type()) , mBufferCacheSize(0) + , mSounds(new std::deque()) + , mStreams(new std::deque()) + , mMusic(nullptr) , mListenerUnderwater(false) , mListenerPos(0,0,0) , mListenerDir(1,0,0) , mListenerUp(0,0,1) , mPausedSoundTypes(0) + , mUnderwaterSound(nullptr) + , mNearWaterSound(nullptr) { mMasterVolume = Settings::Manager::getFloat("master volume", "Sound"); mMasterVolume = std::min(std::max(mMasterVolume, 0.0f), 1.0f); @@ -246,7 +251,39 @@ namespace MWSound return decoder; } - MWBase::SoundStreamPtr SoundManager::playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal) + Sound *SoundManager::getSoundRef() + { + Sound *ret; + if(!mUnusedSounds.empty()) + { + ret = mUnusedSounds.back(); + mUnusedSounds.pop_back(); + } + else + { + mSounds->emplace_back(); + ret = &mSounds->back(); + } + return ret; + } + + Stream *SoundManager::getStreamRef() + { + Stream *ret; + if(!mUnusedStreams.empty()) + { + ret = mUnusedStreams.back(); + mUnusedStreams.pop_back(); + } + else + { + mStreams->emplace_back(); + ret = &mStreams->back(); + } + return ret; + } + + Stream *SoundManager::playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal) { MWBase::World* world = MWBase::Environment::get().getWorld(); static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); @@ -256,17 +293,17 @@ namespace MWSound static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f); static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); - MWBase::SoundStreamPtr sound; float basevol = volumeFromType(Play_TypeVoice); + Stream *sound = getStreamRef(); if(playlocal) { - sound.reset(new Stream(1.0f, basevol, 1.0f, Play_NoEnv|Play_TypeVoice|Play_2D)); + sound->init(1.0f, basevol, 1.0f, Play_NoEnv|Play_TypeVoice|Play_2D); mOutput->streamSound(decoder, sound); } else { - sound.reset(new Stream(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance, - Play_Normal|Play_TypeVoice|Play_3D)); + sound->init(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance, + Play_Normal|Play_TypeVoice|Play_3D); mOutput->streamSound3D(decoder, sound, true); } return sound; @@ -301,8 +338,11 @@ namespace MWSound void SoundManager::stopMusic() { if(mMusic) + { mOutput->finishStream(mMusic); - mMusic.reset(); + mUnusedStreams.push_back(mMusic); + mMusic = nullptr; + } } void SoundManager::streamMusicFull(const std::string& filename) @@ -317,13 +357,16 @@ namespace MWSound DecoderPtr decoder = getDecoder(); decoder->open(filename); - mMusic.reset(new Stream(1.0f, volumeFromType(Play_TypeMusic), 1.0f, - Play_NoEnv|Play_TypeMusic|Play_2D)); + mMusic = getStreamRef(); + mMusic->init(1.0f, volumeFromType(Play_TypeMusic), 1.0f, + Play_NoEnv|Play_TypeMusic|Play_2D); mOutput->streamSound(decoder, mMusic); } catch(std::exception &e) { std::cout << "Music Error: " << e.what() << "\n"; - mMusic.reset(); + if(mMusic) + mUnusedStreams.push_back(mMusic); + mMusic = nullptr; } } @@ -421,15 +464,8 @@ namespace MWSound MWBase::World *world = MWBase::Environment::get().getWorld(); const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); - SaySoundMap::iterator oldIt = mActiveSaySounds.find(ptr); - if (oldIt != mActiveSaySounds.end()) - { - mOutput->finishStream(oldIt->second); - mActiveSaySounds.erase(oldIt); - } - - MWBase::SoundStreamPtr sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); - + stopSay(ptr); + Stream *sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); mActiveSaySounds.insert(std::make_pair(ptr, sound)); } catch(std::exception &e) @@ -443,7 +479,7 @@ namespace MWSound SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) { - MWBase::SoundStreamPtr sound = snditer->second; + Stream *sound = snditer->second; return mOutput->getStreamLoudness(sound); } @@ -461,13 +497,7 @@ namespace MWSound mVFS->normalizeFilename(voicefile); DecoderPtr decoder = loadVoice(voicefile); - SaySoundMap::iterator oldIt = mActiveSaySounds.find(MWWorld::ConstPtr()); - if (oldIt != mActiveSaySounds.end()) - { - mOutput->finishStream(oldIt->second); - mActiveSaySounds.erase(oldIt); - } - + stopSay(MWWorld::ConstPtr()); mActiveSaySounds.insert(std::make_pair(MWWorld::ConstPtr(), playVoice(decoder, osg::Vec3f(), true))); } @@ -495,19 +525,20 @@ namespace MWSound if(snditer != mActiveSaySounds.end()) { mOutput->finishStream(snditer->second); + mUnusedStreams.push_back(snditer->second); mActiveSaySounds.erase(snditer); } } - MWBase::SoundStreamPtr SoundManager::playTrack(const DecoderPtr& decoder, PlayType type) + Stream *SoundManager::playTrack(const DecoderPtr& decoder, PlayType type) { - MWBase::SoundStreamPtr track; if(!mOutput->isInitialized()) - return track; + return nullptr; + Stream *track = getStreamRef(); try { - track.reset(new Stream(1.0f, volumeFromType(type), 1.0f, Play_NoEnv|type|Play_2D)); + track->init(1.0f, volumeFromType(type), 1.0f, Play_NoEnv|type|Play_2D); mOutput->streamSound(decoder, track); TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), track); @@ -516,35 +547,40 @@ namespace MWSound catch(std::exception &e) { std::cout <<"Sound Error: "<finishStream(stream); TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), stream); if(iter != mActiveTracks.end() && *iter == stream) mActiveTracks.erase(iter); + mUnusedStreams.push_back(stream); } - double SoundManager::getTrackTimeDelay(MWBase::SoundStreamPtr stream) + double SoundManager::getTrackTimeDelay(Stream *stream) { return mOutput->getStreamDelay(stream); } - MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) + Sound *SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) { - MWBase::SoundPtr sound; if(!mOutput->isInitialized()) - return sound; + return nullptr; + Sound *sound = nullptr; try { Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - sound.reset(new Sound(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D)); + sound = getSoundRef(); + sound->init(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D); mOutput->playSound(sound, sfx->mHandle, offset); if(sfx->mUses++ == 0) { @@ -557,17 +593,20 @@ namespace MWSound catch(std::exception&) { //std::cout <<"Sound Error: "<isInitialized()) - return sound; + return nullptr; + Sound *sound = nullptr; try { // Look up the sound in the ESM data @@ -577,20 +616,21 @@ namespace MWSound const osg::Vec3f objpos(pos.asVec3()); if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) - return MWBase::SoundPtr(); + return nullptr; // Only one copy of given sound can be played at time on ptr, so stop previous copy stopSound3D(ptr, soundId); + sound = getSoundRef(); if(!(mode&Play_NoPlayerLocal) && ptr == MWMechanics::getPlayer()) { - sound.reset(new Sound(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D)); + sound->init(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D); mOutput->playSound(sound, sfx->mHandle, offset); } else { - sound.reset(new Sound(objpos, volume * sfx->mVolume, basevol, pitch, - sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D)); + sound->init(objpos, volume * sfx->mVolume, basevol, pitch, + sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D); mOutput->playSound3D(sound, sfx->mHandle, offset); } if(sfx->mUses++ == 0) @@ -604,25 +644,29 @@ namespace MWSound catch(std::exception&) { //std::cout <<"Sound Error: "<isInitialized()) - return sound; + return nullptr; + Sound *sound = nullptr; try { // Look up the sound in the ESM data Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - sound.reset(new Sound(initialPos, volume * sfx->mVolume, basevol, pitch, - sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D)); + sound = getSoundRef(); + sound->init(initialPos, volume * sfx->mVolume, basevol, pitch, + sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D); mOutput->playSound3D(sound, sfx->mHandle, offset); if(sfx->mUses++ == 0) { @@ -635,14 +679,16 @@ namespace MWSound catch(std::exception &) { //std::cout <<"Sound Error: "<finishSound(sound); } @@ -675,7 +721,7 @@ namespace MWSound void SoundManager::stopSound(const MWWorld::CellStore *cell) { SoundMap::iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + for(;snditer != mActiveSounds.end();++snditer) { if(snditer->first != MWWorld::ConstPtr() && snditer->first != MWMechanics::getPlayer() && @@ -685,18 +731,14 @@ namespace MWSound for(;sndidx != snditer->second.end();++sndidx) mOutput->finishSound(sndidx->first); } - ++snditer; } SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); - while(sayiter != mActiveSaySounds.end()) + for(;sayiter != mActiveSaySounds.end();++sayiter) { if(sayiter->first != MWWorld::ConstPtr() && sayiter->first != MWMechanics::getPlayer() && sayiter->first.getCell() == cell) - { mOutput->finishStream(sayiter->second); - } - ++sayiter; } } @@ -885,7 +927,7 @@ namespace MWSound if (volume == 0.0f) { mOutput->finishSound(mNearWaterSound); - mNearWaterSound.reset(); + mNearWaterSound = nullptr; } else { @@ -939,7 +981,7 @@ namespace MWSound else if(mUnderwaterSound) { mOutput->finishSound(mUnderwaterSound); - mUnderwaterSound.reset(); + mUnderwaterSound = nullptr; } mOutput->startUpdate(); @@ -960,7 +1002,7 @@ namespace MWSound while(sndidx != snditer->second.end()) { MWWorld::ConstPtr ptr = snditer->first; - MWBase::SoundPtr sound = sndidx->first; + Sound *sound = sndidx->first; if(!ptr.isEmpty() && sound->getIs3D()) { const ESM::Position &pos = ptr.getRefData().getPosition(); @@ -977,6 +1019,11 @@ namespace MWSound if(!mOutput->isSoundPlaying(sound)) { mOutput->finishSound(sound); + mUnusedSounds.push_back(sound); + if(sound == mUnderwaterSound) + mUnderwaterSound = nullptr; + if(sound == mNearWaterSound) + mNearWaterSound = nullptr; Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sfx); @@ -1000,7 +1047,7 @@ namespace MWSound while(sayiter != mActiveSaySounds.end()) { MWWorld::ConstPtr ptr = sayiter->first; - MWBase::SoundStreamPtr sound = sayiter->second; + Stream *sound = sayiter->second; if(!ptr.isEmpty() && sound->getIs3D()) { MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -1017,6 +1064,7 @@ namespace MWSound if(!mOutput->isStreamPlaying(sound)) { mOutput->finishStream(sound); + mUnusedStreams.push_back(sound); mActiveSaySounds.erase(sayiter++); } else @@ -1031,10 +1079,11 @@ namespace MWSound TrackList::iterator trkiter = mActiveTracks.begin(); for(;trkiter != mActiveTracks.end();++trkiter) { - MWBase::SoundStreamPtr sound = *trkiter; + Stream *sound = *trkiter; if(!mOutput->isStreamPlaying(sound)) { mOutput->finishStream(sound); + mUnusedStreams.push_back(sound); trkiter = mActiveTracks.erase(trkiter); } else @@ -1049,7 +1098,7 @@ namespace MWSound if(mListenerUnderwater) { // Play underwater sound (after updating sounds) - if(!(mUnderwaterSound && mOutput->isSoundPlaying(mUnderwaterSound))) + if(!mUnderwaterSound) mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv); } mOutput->finishUpdate(); @@ -1105,7 +1154,7 @@ namespace MWSound SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - MWBase::SoundPtr sound = sndidx->first; + Sound *sound = sndidx->first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); mOutput->updateSound(sound); } @@ -1113,14 +1162,14 @@ namespace MWSound SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); for(;sayiter != mActiveSaySounds.end();++sayiter) { - MWBase::SoundStreamPtr sound = sayiter->second; + Stream *sound = sayiter->second; sound->setBaseVolume(volumeFromType(sound->getPlayType())); mOutput->updateStream(sound); } TrackList::iterator trkiter = mActiveTracks.begin(); for(;trkiter != mActiveTracks.end();++trkiter) { - MWBase::SoundStreamPtr sound = *trkiter; + Stream *sound = *trkiter; sound->setBaseVolume(volumeFromType(sound->getPlayType())); mOutput->updateStream(sound); } @@ -1153,7 +1202,7 @@ namespace MWSound SaySoundMap::iterator sayiter = mActiveSaySounds.find(old); if(sayiter != mActiveSaySounds.end()) { - MWBase::SoundStreamPtr stream = sayiter->second; + Stream *stream = sayiter->second; mActiveSaySounds.erase(sayiter); mActiveSaySounds[updated] = stream; } @@ -1233,6 +1282,7 @@ namespace MWSound for(;sndidx != snditer->second.end();++sndidx) { mOutput->finishSound(sndidx->first); + mUnusedSounds.push_back(sndidx->first); Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sfx); @@ -1241,14 +1291,20 @@ namespace MWSound mActiveSounds.clear(); SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); for(;sayiter != mActiveSaySounds.end();++sayiter) + { mOutput->finishStream(sayiter->second); + mUnusedStreams.push_back(sayiter->second); + } mActiveSaySounds.clear(); TrackList::iterator trkiter = mActiveTracks.begin(); for(;trkiter != mActiveTracks.end();++trkiter) + { mOutput->finishStream(*trkiter); + mUnusedStreams.push_back(*trkiter); + } mActiveTracks.clear(); - mUnderwaterSound.reset(); - mNearWaterSound.reset(); + mUnderwaterSound = nullptr; + mNearWaterSound = nullptr; stopMusic(); } } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 691e52932..836c3f228 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -29,6 +29,7 @@ namespace MWSound class Sound_Output; struct Sound_Decoder; class Sound; + class Stream; class Sound_Buffer; enum Environment { @@ -81,18 +82,24 @@ namespace MWSound typedef std::deque SoundList; SoundList mUnusedBuffers; - typedef std::pair SoundBufferRefPair; + std::unique_ptr> mSounds; + std::vector mUnusedSounds; + + std::unique_ptr> mStreams; + std::vector mUnusedStreams; + + typedef std::pair SoundBufferRefPair; typedef std::vector SoundBufferRefPairList; typedef std::map SoundMap; SoundMap mActiveSounds; - typedef std::map SaySoundMap; + typedef std::map SaySoundMap; SaySoundMap mActiveSaySounds; - typedef std::vector TrackList; + typedef std::vector TrackList; TrackList mActiveTracks; - MWBase::SoundStreamPtr mMusic; + Stream *mMusic; std::string mCurrentPlaylist; bool mListenerUnderwater; @@ -102,8 +109,8 @@ namespace MWSound int mPausedSoundTypes; - MWBase::SoundPtr mUnderwaterSound; - MWBase::SoundPtr mNearWaterSound; + Sound *mUnderwaterSound; + Sound *mNearWaterSound; Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound); @@ -113,7 +120,10 @@ namespace MWSound // returns a decoder to start streaming DecoderPtr loadVoice(const std::string &voicefile); - MWBase::SoundStreamPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal); + Sound *getSoundRef(); + Stream *getStreamRef(); + + Stream *playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal); void streamMusicFull(const std::string& filename); void advanceMusic(const std::string& filename); @@ -176,33 +186,33 @@ namespace MWSound /// and get an average loudness value (scale [0,1]) at the current time position. /// If the actor is not saying anything, returns 0. - virtual MWBase::SoundStreamPtr playTrack(const DecoderPtr& decoder, PlayType type); + virtual Stream *playTrack(const DecoderPtr& decoder, PlayType type); ///< Play a 2D audio track, using a custom decoder - virtual void stopTrack(MWBase::SoundStreamPtr stream); + virtual void stopTrack(Stream *stream); ///< Stop the given audio track from playing - virtual double getTrackTimeDelay(MWBase::SoundStreamPtr stream); + virtual double getTrackTimeDelay(Stream *stream); ///< Retives the time delay, in seconds, of the audio track (must be a sound /// returned by \ref playTrack). Only intended to be called by the track /// decoder's read method. - virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0); + virtual Sound *playSound(const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0); ///< Play a sound, independently of 3D-position ///< @param offset Number of seconds into the sound to start playback. - virtual MWBase::SoundPtr playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, - float volume, float pitch, PlayType type=Play_TypeSfx, - PlayMode mode=Play_Normal, float offset=0); + virtual Sound *playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, + float volume, float pitch, PlayType type=Play_TypeSfx, + PlayMode mode=Play_Normal, float offset=0); ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. ///< @param offset Number of seconds into the sound to start playback. - virtual MWBase::SoundPtr playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, - float volume, float pitch, PlayType type, PlayMode mode, float offset=0); + virtual Sound *playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, + float volume, float pitch, PlayType type, PlayMode mode, float offset=0); ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. ///< @param offset Number of seconds into the sound to start playback. - virtual void stopSound(MWBase::SoundPtr sound); + virtual void stopSound(Sound *sound); ///< Stop the given sound from playing /// @note no-op if \a sound is null diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 5afdce700..64d601563 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -283,7 +283,7 @@ namespace MWWorld MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); for (size_t it = 0; it != state.mSoundIds.size(); it++) { - MWBase::SoundPtr sound = sndMgr->playSound3D(pos, state.mSoundIds.at(it), 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); + MWBase::Sound *sound = sndMgr->playSound3D(pos, state.mSoundIds.at(it), 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); if (sound) state.mSounds.push_back(sound); } @@ -584,8 +584,8 @@ namespace MWWorld for (size_t soundIter = 0; soundIter != state.mSoundIds.size(); soundIter++) { - MWBase::SoundPtr sound = sndMgr->playSound3D(esm.mPosition, state.mSoundIds.at(soundIter), 1.0f, 1.0f, - MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); + MWBase::Sound *sound = sndMgr->playSound3D(esm.mPosition, state.mSoundIds.at(soundIter), 1.0f, 1.0f, + MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); if (sound) state.mSounds.push_back(sound); } diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index bfa4980e9..c7025a3a0 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -103,7 +103,7 @@ namespace MWWorld bool mStack; - std::vector mSounds; + std::vector mSounds; std::vector mSoundIds; }; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index eaf88d45a..c4b46961c 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -531,7 +531,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const Fall , mQueuedWeather(0) , mRegions() , mResult() - , mAmbientSound() + , mAmbientSound(nullptr) , mPlayingSoundID() { mTimeSettings.mNightStart = mSunsetTime + mSunsetDuration; @@ -735,15 +735,15 @@ void WeatherManager::update(float duration, bool paused) mPlayingSoundID = mResult.mAmbientLoopSoundID; } - if (mAmbientSound.get()) + else if (mAmbientSound) mAmbientSound->setVolume(mResult.mAmbientSoundVolume); } void WeatherManager::stopSounds() { - if (mAmbientSound.get()) + if (mAmbientSound) MWBase::Environment::get().getSoundManager()->stopSound(mAmbientSound); - mAmbientSound.reset(); + mAmbientSound = nullptr; mPlayingSoundID.clear(); } diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 044200757..84a6c5105 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -288,7 +288,7 @@ namespace MWWorld std::map mRegions; MWRender::WeatherResult mResult; - MWBase::SoundPtr mAmbientSound; + MWBase::Sound *mAmbientSound; std::string mPlayingSoundID; void addWeather(const std::string& name, From 9e7a49f66eb73599a871823b10a07f7014cc554f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 11 Sep 2017 22:17:36 -0700 Subject: [PATCH 046/505] Include alext.h to get OpenAL extension definitions --- apps/openmw/CMakeLists.txt | 3 +- apps/openmw/mwsound/alext.h | 466 ++++++++++++++++ apps/openmw/mwsound/efx-presets.h | 402 ++++++++++++++ apps/openmw/mwsound/efx.h | 761 ++++++++++++++++++++++++++ apps/openmw/mwsound/openal_output.cpp | 22 - apps/openmw/mwsound/openal_output.hpp | 1 + 6 files changed, 1632 insertions(+), 23 deletions(-) create mode 100644 apps/openmw/mwsound/alext.h create mode 100644 apps/openmw/mwsound/efx-presets.h create mode 100644 apps/openmw/mwsound/efx.h diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 134953f3d..00ae2fa4a 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -57,7 +57,8 @@ add_openmw_dir (mwscript ) add_openmw_dir (mwsound - soundmanagerimp openal_output ffmpeg_decoder sound sound_buffer sound_decoder sound_output loudness movieaudiofactory + soundmanagerimp openal_output ffmpeg_decoder sound sound_buffer sound_decoder sound_output + loudness movieaudiofactory alext efx efx-presets ) add_openmw_dir (mwworld diff --git a/apps/openmw/mwsound/alext.h b/apps/openmw/mwsound/alext.h new file mode 100644 index 000000000..4b9a15537 --- /dev/null +++ b/apps/openmw/mwsound/alext.h @@ -0,0 +1,466 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2008 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#ifndef AL_ALEXT_H +#define AL_ALEXT_H + +#include +/* Define int64_t and uint64_t types */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#elif defined(_WIN32) && defined(__GNUC__) +#include +#elif defined(_WIN32) +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* Fallback if nothing above works */ +#include +#endif + +#include "alc.h" +#include "al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef AL_LOKI_IMA_ADPCM_format +#define AL_LOKI_IMA_ADPCM_format 1 +#define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000 +#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001 +#endif + +#ifndef AL_LOKI_WAVE_format +#define AL_LOKI_WAVE_format 1 +#define AL_FORMAT_WAVE_EXT 0x10002 +#endif + +#ifndef AL_EXT_vorbis +#define AL_EXT_vorbis 1 +#define AL_FORMAT_VORBIS_EXT 0x10003 +#endif + +#ifndef AL_LOKI_quadriphonic +#define AL_LOKI_quadriphonic 1 +#define AL_FORMAT_QUAD8_LOKI 0x10004 +#define AL_FORMAT_QUAD16_LOKI 0x10005 +#endif + +#ifndef AL_EXT_float32 +#define AL_EXT_float32 1 +#define AL_FORMAT_MONO_FLOAT32 0x10010 +#define AL_FORMAT_STEREO_FLOAT32 0x10011 +#endif + +#ifndef AL_EXT_double +#define AL_EXT_double 1 +#define AL_FORMAT_MONO_DOUBLE_EXT 0x10012 +#define AL_FORMAT_STEREO_DOUBLE_EXT 0x10013 +#endif + +#ifndef AL_EXT_MULAW +#define AL_EXT_MULAW 1 +#define AL_FORMAT_MONO_MULAW_EXT 0x10014 +#define AL_FORMAT_STEREO_MULAW_EXT 0x10015 +#endif + +#ifndef AL_EXT_ALAW +#define AL_EXT_ALAW 1 +#define AL_FORMAT_MONO_ALAW_EXT 0x10016 +#define AL_FORMAT_STEREO_ALAW_EXT 0x10017 +#endif + +#ifndef ALC_LOKI_audio_channel +#define ALC_LOKI_audio_channel 1 +#define ALC_CHAN_MAIN_LOKI 0x500001 +#define ALC_CHAN_PCM_LOKI 0x500002 +#define ALC_CHAN_CD_LOKI 0x500003 +#endif + +#ifndef AL_EXT_MCFORMATS +#define AL_EXT_MCFORMATS 1 +#define AL_FORMAT_QUAD8 0x1204 +#define AL_FORMAT_QUAD16 0x1205 +#define AL_FORMAT_QUAD32 0x1206 +#define AL_FORMAT_REAR8 0x1207 +#define AL_FORMAT_REAR16 0x1208 +#define AL_FORMAT_REAR32 0x1209 +#define AL_FORMAT_51CHN8 0x120A +#define AL_FORMAT_51CHN16 0x120B +#define AL_FORMAT_51CHN32 0x120C +#define AL_FORMAT_61CHN8 0x120D +#define AL_FORMAT_61CHN16 0x120E +#define AL_FORMAT_61CHN32 0x120F +#define AL_FORMAT_71CHN8 0x1210 +#define AL_FORMAT_71CHN16 0x1211 +#define AL_FORMAT_71CHN32 0x1212 +#endif + +#ifndef AL_EXT_MULAW_MCFORMATS +#define AL_EXT_MULAW_MCFORMATS 1 +#define AL_FORMAT_MONO_MULAW 0x10014 +#define AL_FORMAT_STEREO_MULAW 0x10015 +#define AL_FORMAT_QUAD_MULAW 0x10021 +#define AL_FORMAT_REAR_MULAW 0x10022 +#define AL_FORMAT_51CHN_MULAW 0x10023 +#define AL_FORMAT_61CHN_MULAW 0x10024 +#define AL_FORMAT_71CHN_MULAW 0x10025 +#endif + +#ifndef AL_EXT_IMA4 +#define AL_EXT_IMA4 1 +#define AL_FORMAT_MONO_IMA4 0x1300 +#define AL_FORMAT_STEREO_IMA4 0x1301 +#endif + +#ifndef AL_EXT_STATIC_BUFFER +#define AL_EXT_STATIC_BUFFER 1 +typedef ALvoid (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei); +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alBufferDataStatic(const ALint buffer, ALenum format, ALvoid *data, ALsizei len, ALsizei freq); +#endif +#endif + +#ifndef ALC_EXT_EFX +#define ALC_EXT_EFX 1 +#include "efx.h" +#endif + +#ifndef ALC_EXT_disconnect +#define ALC_EXT_disconnect 1 +#define ALC_CONNECTED 0x313 +#endif + +#ifndef ALC_EXT_thread_local_context +#define ALC_EXT_thread_local_context 1 +typedef ALCboolean (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context); +typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context); +ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void); +#endif +#endif + +#ifndef AL_EXT_source_distance_model +#define AL_EXT_source_distance_model 1 +#define AL_SOURCE_DISTANCE_MODEL 0x200 +#endif + +#ifndef AL_SOFT_buffer_sub_data +#define AL_SOFT_buffer_sub_data 1 +#define AL_BYTE_RW_OFFSETS_SOFT 0x1031 +#define AL_SAMPLE_RW_OFFSETS_SOFT 0x1032 +typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei); +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length); +#endif +#endif + +#ifndef AL_SOFT_loop_points +#define AL_SOFT_loop_points 1 +#define AL_LOOP_POINTS_SOFT 0x2015 +#endif + +#ifndef AL_EXT_FOLDBACK +#define AL_EXT_FOLDBACK 1 +#define AL_EXT_FOLDBACK_NAME "AL_EXT_FOLDBACK" +#define AL_FOLDBACK_EVENT_BLOCK 0x4112 +#define AL_FOLDBACK_EVENT_START 0x4111 +#define AL_FOLDBACK_EVENT_STOP 0x4113 +#define AL_FOLDBACK_MODE_MONO 0x4101 +#define AL_FOLDBACK_MODE_STEREO 0x4102 +typedef void (AL_APIENTRY*LPALFOLDBACKCALLBACK)(ALenum,ALsizei); +typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTART)(ALenum,ALsizei,ALsizei,ALfloat*,LPALFOLDBACKCALLBACK); +typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTOP)(void); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alRequestFoldbackStart(ALenum mode,ALsizei count,ALsizei length,ALfloat *mem,LPALFOLDBACKCALLBACK callback); +AL_API void AL_APIENTRY alRequestFoldbackStop(void); +#endif +#endif + +#ifndef ALC_EXT_DEDICATED +#define ALC_EXT_DEDICATED 1 +#define AL_DEDICATED_GAIN 0x0001 +#define AL_EFFECT_DEDICATED_DIALOGUE 0x9001 +#define AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT 0x9000 +#endif + +#ifndef AL_SOFT_buffer_samples +#define AL_SOFT_buffer_samples 1 +/* Channel configurations */ +#define AL_MONO_SOFT 0x1500 +#define AL_STEREO_SOFT 0x1501 +#define AL_REAR_SOFT 0x1502 +#define AL_QUAD_SOFT 0x1503 +#define AL_5POINT1_SOFT 0x1504 +#define AL_6POINT1_SOFT 0x1505 +#define AL_7POINT1_SOFT 0x1506 + +/* Sample types */ +#define AL_BYTE_SOFT 0x1400 +#define AL_UNSIGNED_BYTE_SOFT 0x1401 +#define AL_SHORT_SOFT 0x1402 +#define AL_UNSIGNED_SHORT_SOFT 0x1403 +#define AL_INT_SOFT 0x1404 +#define AL_UNSIGNED_INT_SOFT 0x1405 +#define AL_FLOAT_SOFT 0x1406 +#define AL_DOUBLE_SOFT 0x1407 +#define AL_BYTE3_SOFT 0x1408 +#define AL_UNSIGNED_BYTE3_SOFT 0x1409 + +/* Storage formats */ +#define AL_MONO8_SOFT 0x1100 +#define AL_MONO16_SOFT 0x1101 +#define AL_MONO32F_SOFT 0x10010 +#define AL_STEREO8_SOFT 0x1102 +#define AL_STEREO16_SOFT 0x1103 +#define AL_STEREO32F_SOFT 0x10011 +#define AL_QUAD8_SOFT 0x1204 +#define AL_QUAD16_SOFT 0x1205 +#define AL_QUAD32F_SOFT 0x1206 +#define AL_REAR8_SOFT 0x1207 +#define AL_REAR16_SOFT 0x1208 +#define AL_REAR32F_SOFT 0x1209 +#define AL_5POINT1_8_SOFT 0x120A +#define AL_5POINT1_16_SOFT 0x120B +#define AL_5POINT1_32F_SOFT 0x120C +#define AL_6POINT1_8_SOFT 0x120D +#define AL_6POINT1_16_SOFT 0x120E +#define AL_6POINT1_32F_SOFT 0x120F +#define AL_7POINT1_8_SOFT 0x1210 +#define AL_7POINT1_16_SOFT 0x1211 +#define AL_7POINT1_32F_SOFT 0x1212 + +/* Buffer attributes */ +#define AL_INTERNAL_FORMAT_SOFT 0x2008 +#define AL_BYTE_LENGTH_SOFT 0x2009 +#define AL_SAMPLE_LENGTH_SOFT 0x200A +#define AL_SEC_LENGTH_SOFT 0x200B + +typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*); +typedef void (AL_APIENTRY*LPALBUFFERSUBSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,const ALvoid*); +typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*); +typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); +AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); +AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data); +AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); +#endif +#endif + +#ifndef AL_SOFT_direct_channels +#define AL_SOFT_direct_channels 1 +#define AL_DIRECT_CHANNELS_SOFT 0x1033 +#endif + +#ifndef ALC_SOFT_loopback +#define ALC_SOFT_loopback 1 +#define ALC_FORMAT_CHANNELS_SOFT 0x1990 +#define ALC_FORMAT_TYPE_SOFT 0x1991 + +/* Sample types */ +#define ALC_BYTE_SOFT 0x1400 +#define ALC_UNSIGNED_BYTE_SOFT 0x1401 +#define ALC_SHORT_SOFT 0x1402 +#define ALC_UNSIGNED_SHORT_SOFT 0x1403 +#define ALC_INT_SOFT 0x1404 +#define ALC_UNSIGNED_INT_SOFT 0x1405 +#define ALC_FLOAT_SOFT 0x1406 + +/* Channel configurations */ +#define ALC_MONO_SOFT 0x1500 +#define ALC_STEREO_SOFT 0x1501 +#define ALC_QUAD_SOFT 0x1503 +#define ALC_5POINT1_SOFT 0x1504 +#define ALC_6POINT1_SOFT 0x1505 +#define ALC_7POINT1_SOFT 0x1506 + +typedef ALCdevice* (ALC_APIENTRY*LPALCLOOPBACKOPENDEVICESOFT)(const ALCchar*); +typedef ALCboolean (ALC_APIENTRY*LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice*,ALCsizei,ALCenum,ALCenum); +typedef void (ALC_APIENTRY*LPALCRENDERSAMPLESSOFT)(ALCdevice*,ALCvoid*,ALCsizei); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName); +ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type); +ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); +#endif +#endif + +#ifndef AL_EXT_STEREO_ANGLES +#define AL_EXT_STEREO_ANGLES 1 +#define AL_STEREO_ANGLES 0x1030 +#endif + +#ifndef AL_EXT_SOURCE_RADIUS +#define AL_EXT_SOURCE_RADIUS 1 +#define AL_SOURCE_RADIUS 0x1031 +#endif + +#ifndef AL_SOFT_source_latency +#define AL_SOFT_source_latency 1 +#define AL_SAMPLE_OFFSET_LATENCY_SOFT 0x1200 +#define AL_SEC_OFFSET_LATENCY_SOFT 0x1201 +typedef int64_t ALint64SOFT; +typedef uint64_t ALuint64SOFT; +typedef void (AL_APIENTRY*LPALSOURCEDSOFT)(ALuint,ALenum,ALdouble); +typedef void (AL_APIENTRY*LPALSOURCE3DSOFT)(ALuint,ALenum,ALdouble,ALdouble,ALdouble); +typedef void (AL_APIENTRY*LPALSOURCEDVSOFT)(ALuint,ALenum,const ALdouble*); +typedef void (AL_APIENTRY*LPALGETSOURCEDSOFT)(ALuint,ALenum,ALdouble*); +typedef void (AL_APIENTRY*LPALGETSOURCE3DSOFT)(ALuint,ALenum,ALdouble*,ALdouble*,ALdouble*); +typedef void (AL_APIENTRY*LPALGETSOURCEDVSOFT)(ALuint,ALenum,ALdouble*); +typedef void (AL_APIENTRY*LPALSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT); +typedef void (AL_APIENTRY*LPALSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT,ALint64SOFT,ALint64SOFT); +typedef void (AL_APIENTRY*LPALSOURCEI64VSOFT)(ALuint,ALenum,const ALint64SOFT*); +typedef void (AL_APIENTRY*LPALGETSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT*); +typedef void (AL_APIENTRY*LPALGETSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT*,ALint64SOFT*,ALint64SOFT*); +typedef void (AL_APIENTRY*LPALGETSOURCEI64VSOFT)(ALuint,ALenum,ALint64SOFT*); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value); +AL_API void AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3); +AL_API void AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values); +AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value); +AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3); +AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values); +AL_API void AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value); +AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3); +AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values); +AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value); +AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3); +AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values); +#endif +#endif + +#ifndef ALC_EXT_DEFAULT_FILTER_ORDER +#define ALC_EXT_DEFAULT_FILTER_ORDER 1 +#define ALC_DEFAULT_FILTER_ORDER 0x1100 +#endif + +#ifndef AL_SOFT_deferred_updates +#define AL_SOFT_deferred_updates 1 +#define AL_DEFERRED_UPDATES_SOFT 0xC002 +typedef ALvoid (AL_APIENTRY*LPALDEFERUPDATESSOFT)(void); +typedef ALvoid (AL_APIENTRY*LPALPROCESSUPDATESSOFT)(void); +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void); +AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void); +#endif +#endif + +#ifndef AL_SOFT_block_alignment +#define AL_SOFT_block_alignment 1 +#define AL_UNPACK_BLOCK_ALIGNMENT_SOFT 0x200C +#define AL_PACK_BLOCK_ALIGNMENT_SOFT 0x200D +#endif + +#ifndef AL_SOFT_MSADPCM +#define AL_SOFT_MSADPCM 1 +#define AL_FORMAT_MONO_MSADPCM_SOFT 0x1302 +#define AL_FORMAT_STEREO_MSADPCM_SOFT 0x1303 +#endif + +#ifndef AL_SOFT_source_length +#define AL_SOFT_source_length 1 +/*#define AL_BYTE_LENGTH_SOFT 0x2009*/ +/*#define AL_SAMPLE_LENGTH_SOFT 0x200A*/ +/*#define AL_SEC_LENGTH_SOFT 0x200B*/ +#endif + +#ifndef ALC_SOFT_pause_device +#define ALC_SOFT_pause_device 1 +typedef void (ALC_APIENTRY*LPALCDEVICEPAUSESOFT)(ALCdevice *device); +typedef void (ALC_APIENTRY*LPALCDEVICERESUMESOFT)(ALCdevice *device); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device); +ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device); +#endif +#endif + +#ifndef AL_EXT_BFORMAT +#define AL_EXT_BFORMAT 1 +#define AL_FORMAT_BFORMAT2D_8 0x20021 +#define AL_FORMAT_BFORMAT2D_16 0x20022 +#define AL_FORMAT_BFORMAT2D_FLOAT32 0x20023 +#define AL_FORMAT_BFORMAT3D_8 0x20031 +#define AL_FORMAT_BFORMAT3D_16 0x20032 +#define AL_FORMAT_BFORMAT3D_FLOAT32 0x20033 +#endif + +#ifndef AL_EXT_MULAW_BFORMAT +#define AL_EXT_MULAW_BFORMAT 1 +#define AL_FORMAT_BFORMAT2D_MULAW 0x10031 +#define AL_FORMAT_BFORMAT3D_MULAW 0x10032 +#endif + +#ifndef ALC_SOFT_HRTF +#define ALC_SOFT_HRTF 1 +#define ALC_HRTF_SOFT 0x1992 +#define ALC_DONT_CARE_SOFT 0x0002 +#define ALC_HRTF_STATUS_SOFT 0x1993 +#define ALC_HRTF_DISABLED_SOFT 0x0000 +#define ALC_HRTF_ENABLED_SOFT 0x0001 +#define ALC_HRTF_DENIED_SOFT 0x0002 +#define ALC_HRTF_REQUIRED_SOFT 0x0003 +#define ALC_HRTF_HEADPHONES_DETECTED_SOFT 0x0004 +#define ALC_HRTF_UNSUPPORTED_FORMAT_SOFT 0x0005 +#define ALC_NUM_HRTF_SPECIFIERS_SOFT 0x1994 +#define ALC_HRTF_SPECIFIER_SOFT 0x1995 +#define ALC_HRTF_ID_SOFT 0x1996 +typedef const ALCchar* (ALC_APIENTRY*LPALCGETSTRINGISOFT)(ALCdevice *device, ALCenum paramName, ALCsizei index); +typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index); +ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs); +#endif +#endif + +#ifndef AL_SOFT_gain_clamp_ex +#define AL_SOFT_gain_clamp_ex 1 +#define AL_GAIN_LIMIT_SOFT 0x200E +#endif + +#ifndef AL_SOFT_source_resampler +#define AL_SOFT_source_resampler +#define AL_NUM_RESAMPLERS_SOFT 0x1210 +#define AL_DEFAULT_RESAMPLER_SOFT 0x1211 +#define AL_SOURCE_RESAMPLER_SOFT 0x1212 +#define AL_RESAMPLER_NAME_SOFT 0x1213 +typedef const ALchar* (AL_APIENTRY*LPALGETSTRINGISOFT)(ALenum pname, ALsizei index); +#ifdef AL_ALEXT_PROTOTYPES +AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index); +#endif +#endif + +#ifndef AL_SOFT_source_spatialize +#define AL_SOFT_source_spatialize +#define AL_SOURCE_SPATIALIZE_SOFT 0x1214 +#define AL_AUTO_SOFT 0x0002 +#endif + +#ifndef ALC_SOFT_output_limiter +#define ALC_SOFT_output_limiter +#define ALC_OUTPUT_LIMITER_SOFT 0x199A +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/apps/openmw/mwsound/efx-presets.h b/apps/openmw/mwsound/efx-presets.h new file mode 100644 index 000000000..8539fd517 --- /dev/null +++ b/apps/openmw/mwsound/efx-presets.h @@ -0,0 +1,402 @@ +/* Reverb presets for EFX */ + +#ifndef EFX_PRESETS_H +#define EFX_PRESETS_H + +#ifndef EFXEAXREVERBPROPERTIES_DEFINED +#define EFXEAXREVERBPROPERTIES_DEFINED +typedef struct { + float flDensity; + float flDiffusion; + float flGain; + float flGainHF; + float flGainLF; + float flDecayTime; + float flDecayHFRatio; + float flDecayLFRatio; + float flReflectionsGain; + float flReflectionsDelay; + float flReflectionsPan[3]; + float flLateReverbGain; + float flLateReverbDelay; + float flLateReverbPan[3]; + float flEchoTime; + float flEchoDepth; + float flModulationTime; + float flModulationDepth; + float flAirAbsorptionGainHF; + float flHFReference; + float flLFReference; + float flRoomRolloffFactor; + int iDecayHFLimit; +} EFXEAXREVERBPROPERTIES, *LPEFXEAXREVERBPROPERTIES; +#endif + +/* Default Presets */ + +#define EFX_REVERB_PRESET_GENERIC \ + { 1.0000f, 1.0000f, 0.3162f, 0.8913f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PADDEDCELL \ + { 0.1715f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.1700f, 0.1000f, 1.0000f, 0.2500f, 0.0010f, { 0.0000f, 0.0000f, 0.0000f }, 1.2691f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ROOM \ + { 0.4287f, 1.0000f, 0.3162f, 0.5929f, 1.0000f, 0.4000f, 0.8300f, 1.0000f, 0.1503f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.0629f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_BATHROOM \ + { 0.1715f, 1.0000f, 0.3162f, 0.2512f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.6531f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 3.2734f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_LIVINGROOM \ + { 0.9766f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.5000f, 0.1000f, 1.0000f, 0.2051f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2805f, 0.0040f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_STONEROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 2.3100f, 0.6400f, 1.0000f, 0.4411f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1003f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_AUDITORIUM \ + { 1.0000f, 1.0000f, 0.3162f, 0.5781f, 1.0000f, 4.3200f, 0.5900f, 1.0000f, 0.4032f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7170f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CONCERTHALL \ + { 1.0000f, 1.0000f, 0.3162f, 0.5623f, 1.0000f, 3.9200f, 0.7000f, 1.0000f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.9977f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CAVE \ + { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 2.9100f, 1.3000f, 1.0000f, 0.5000f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.7063f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_ARENA \ + { 1.0000f, 1.0000f, 0.3162f, 0.4477f, 1.0000f, 7.2400f, 0.3300f, 1.0000f, 0.2612f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.0186f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_HANGAR \ + { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 10.0500f, 0.2300f, 1.0000f, 0.5000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2560f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CARPETEDHALLWAY \ + { 0.4287f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 0.3000f, 0.1000f, 1.0000f, 0.1215f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.1531f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_HALLWAY \ + { 0.3645f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 1.4900f, 0.5900f, 1.0000f, 0.2458f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.6615f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_STONECORRIDOR \ + { 1.0000f, 1.0000f, 0.3162f, 0.7612f, 1.0000f, 2.7000f, 0.7900f, 1.0000f, 0.2472f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 1.5758f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ALLEY \ + { 1.0000f, 0.3000f, 0.3162f, 0.7328f, 1.0000f, 1.4900f, 0.8600f, 1.0000f, 0.2500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.9954f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.9500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FOREST \ + { 1.0000f, 0.3000f, 0.3162f, 0.0224f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.0525f, 0.1620f, { 0.0000f, 0.0000f, 0.0000f }, 0.7682f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY \ + { 1.0000f, 0.5000f, 0.3162f, 0.3981f, 1.0000f, 1.4900f, 0.6700f, 1.0000f, 0.0730f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1427f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_MOUNTAINS \ + { 1.0000f, 0.2700f, 0.3162f, 0.0562f, 1.0000f, 1.4900f, 0.2100f, 1.0000f, 0.0407f, 0.3000f, { 0.0000f, 0.0000f, 0.0000f }, 0.1919f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_QUARRY \ + { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0000f, 0.0610f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.7000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PLAIN \ + { 1.0000f, 0.2100f, 0.3162f, 0.1000f, 1.0000f, 1.4900f, 0.5000f, 1.0000f, 0.0585f, 0.1790f, { 0.0000f, 0.0000f, 0.0000f }, 0.1089f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PARKINGLOT \ + { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 1.6500f, 1.5000f, 1.0000f, 0.2082f, 0.0080f, { 0.0000f, 0.0000f, 0.0000f }, 0.2652f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_SEWERPIPE \ + { 0.3071f, 0.8000f, 0.3162f, 0.3162f, 1.0000f, 2.8100f, 0.1400f, 1.0000f, 1.6387f, 0.0140f, { 0.0000f, 0.0000f, 0.0000f }, 3.2471f, 0.0210f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_UNDERWATER \ + { 0.3645f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 1.4900f, 0.1000f, 1.0000f, 0.5963f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 7.0795f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 1.1800f, 0.3480f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRUGGED \ + { 0.4287f, 0.5000f, 0.3162f, 1.0000f, 1.0000f, 8.3900f, 1.3900f, 1.0000f, 0.8760f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 3.1081f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DIZZY \ + { 0.3645f, 0.6000f, 0.3162f, 0.6310f, 1.0000f, 17.2300f, 0.5600f, 1.0000f, 0.1392f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4937f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.8100f, 0.3100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PSYCHOTIC \ + { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +/* Castle Presets */ + +#define EFX_REVERB_PRESET_CASTLE_SMALLROOM \ + { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 1.2200f, 0.8300f, 0.3100f, 0.8913f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_SHORTPASSAGE \ + { 1.0000f, 0.8900f, 0.3162f, 0.3162f, 0.1000f, 2.3200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_MEDIUMROOM \ + { 1.0000f, 0.9300f, 0.3162f, 0.2818f, 0.1000f, 2.0400f, 0.8300f, 0.4600f, 0.6310f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1550f, 0.0300f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_LARGEROOM \ + { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.1259f, 2.5300f, 0.8300f, 0.5000f, 0.4467f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1850f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_LONGPASSAGE \ + { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 3.4200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_HALL \ + { 1.0000f, 0.8100f, 0.3162f, 0.2818f, 0.1778f, 3.1400f, 0.7900f, 0.6200f, 0.1778f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_CUPBOARD \ + { 1.0000f, 0.8900f, 0.3162f, 0.2818f, 0.1000f, 0.6700f, 0.8700f, 0.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 3.5481f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_COURTYARD \ + { 1.0000f, 0.4200f, 0.3162f, 0.4467f, 0.1995f, 2.1300f, 0.6100f, 0.2300f, 0.2239f, 0.1600f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3700f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_CASTLE_ALCOVE \ + { 1.0000f, 0.8900f, 0.3162f, 0.5012f, 0.1000f, 1.6400f, 0.8700f, 0.3100f, 1.0000f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +/* Factory Presets */ + +#define EFX_REVERB_PRESET_FACTORY_SMALLROOM \ + { 0.3645f, 0.8200f, 0.3162f, 0.7943f, 0.5012f, 1.7200f, 0.6500f, 1.3100f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.1190f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE \ + { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 2.5300f, 0.6500f, 1.3100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_MEDIUMROOM \ + { 0.4287f, 0.8200f, 0.2512f, 0.7943f, 0.5012f, 2.7600f, 0.6500f, 1.3100f, 0.2818f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1740f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_LARGEROOM \ + { 0.4287f, 0.7500f, 0.2512f, 0.7079f, 0.6310f, 4.2400f, 0.5100f, 1.3100f, 0.1778f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2310f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_LONGPASSAGE \ + { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 4.0600f, 0.6500f, 1.3100f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_HALL \ + { 0.4287f, 0.7500f, 0.3162f, 0.7079f, 0.6310f, 7.4300f, 0.5100f, 1.3100f, 0.0631f, 0.0730f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_CUPBOARD \ + { 0.3071f, 0.6300f, 0.2512f, 0.7943f, 0.5012f, 0.4900f, 0.6500f, 1.3100f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.1070f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_COURTYARD \ + { 0.3071f, 0.5700f, 0.3162f, 0.3162f, 0.6310f, 2.3200f, 0.2900f, 0.5600f, 0.2239f, 0.1400f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2900f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_ALCOVE \ + { 0.3645f, 0.5900f, 0.2512f, 0.7943f, 0.5012f, 3.1400f, 0.6500f, 1.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1140f, 0.1000f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +/* Ice Palace Presets */ + +#define EFX_REVERB_PRESET_ICEPALACE_SMALLROOM \ + { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 1.5100f, 1.5300f, 0.2700f, 0.8913f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1640f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_SHORTPASSAGE \ + { 1.0000f, 0.7500f, 0.3162f, 0.5623f, 0.2818f, 1.7900f, 1.4600f, 0.2800f, 0.5012f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_MEDIUMROOM \ + { 1.0000f, 0.8700f, 0.3162f, 0.5623f, 0.4467f, 2.2200f, 1.5300f, 0.3200f, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_LARGEROOM \ + { 1.0000f, 0.8100f, 0.3162f, 0.5623f, 0.4467f, 3.1400f, 1.5300f, 0.3200f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_LONGPASSAGE \ + { 1.0000f, 0.7700f, 0.3162f, 0.5623f, 0.3981f, 3.0100f, 1.4600f, 0.2800f, 0.7943f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.0400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_HALL \ + { 1.0000f, 0.7600f, 0.3162f, 0.4467f, 0.5623f, 5.4900f, 1.5300f, 0.3800f, 0.1122f, 0.0540f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0520f, { 0.0000f, 0.0000f, 0.0000f }, 0.2260f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_CUPBOARD \ + { 1.0000f, 0.8300f, 0.3162f, 0.5012f, 0.2239f, 0.7600f, 1.5300f, 0.2600f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1430f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_COURTYARD \ + { 1.0000f, 0.5900f, 0.3162f, 0.2818f, 0.3162f, 2.0400f, 1.2000f, 0.3800f, 0.3162f, 0.1730f, { 0.0000f, 0.0000f, 0.0000f }, 0.3162f, 0.0430f, { 0.0000f, 0.0000f, 0.0000f }, 0.2350f, 0.4800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_ALCOVE \ + { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 2.7600f, 1.4600f, 0.2800f, 1.1220f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1610f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +/* Space Station Presets */ + +#define EFX_REVERB_PRESET_SPACESTATION_SMALLROOM \ + { 0.2109f, 0.7000f, 0.3162f, 0.7079f, 0.8913f, 1.7200f, 0.8200f, 0.5500f, 0.7943f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 0.1880f, 0.2600f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_SHORTPASSAGE \ + { 0.2109f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 3.5700f, 0.5000f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1720f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM \ + { 0.2109f, 0.7500f, 0.3162f, 0.6310f, 0.8913f, 3.0100f, 0.5000f, 0.5500f, 0.3981f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2090f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_LARGEROOM \ + { 0.3645f, 0.8100f, 0.3162f, 0.6310f, 0.8913f, 3.8900f, 0.3800f, 0.6100f, 0.3162f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2330f, 0.2800f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE \ + { 0.4287f, 0.8200f, 0.3162f, 0.6310f, 0.8913f, 4.6200f, 0.6200f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_HALL \ + { 0.4287f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 7.1100f, 0.3800f, 0.6100f, 0.1778f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2500f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_CUPBOARD \ + { 0.1715f, 0.5600f, 0.3162f, 0.7079f, 0.8913f, 0.7900f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1810f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_ALCOVE \ + { 0.2109f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.1600f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1920f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +/* Wooden Galleon Presets */ + +#define EFX_REVERB_PRESET_WOODEN_SMALLROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.1122f, 0.3162f, 0.7900f, 0.3200f, 0.8700f, 1.0000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_SHORTPASSAGE \ + { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.7500f, 0.5000f, 0.8700f, 0.8913f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_MEDIUMROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.2818f, 1.4700f, 0.4200f, 0.8200f, 0.8913f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_LARGEROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.2818f, 2.6500f, 0.3300f, 0.8200f, 0.8913f, 0.0660f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_LONGPASSAGE \ + { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.3162f, 1.9900f, 0.4000f, 0.7900f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4467f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_HALL \ + { 1.0000f, 1.0000f, 0.3162f, 0.0794f, 0.2818f, 3.4500f, 0.3000f, 0.8200f, 0.8913f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_CUPBOARD \ + { 1.0000f, 1.0000f, 0.3162f, 0.1413f, 0.3162f, 0.5600f, 0.4600f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_COURTYARD \ + { 1.0000f, 0.6500f, 0.3162f, 0.0794f, 0.3162f, 1.7900f, 0.3500f, 0.7900f, 0.5623f, 0.1230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_ALCOVE \ + { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.2200f, 0.6200f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +/* Sports Presets */ + +#define EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM \ + { 1.0000f, 1.0000f, 0.3162f, 0.4467f, 0.7943f, 6.2600f, 0.5100f, 1.1000f, 0.0631f, 0.1830f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_SQUASHCOURT \ + { 1.0000f, 0.7500f, 0.3162f, 0.3162f, 0.7943f, 2.2200f, 0.9100f, 1.1600f, 0.4467f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1260f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_SMALLSWIMMINGPOOL \ + { 1.0000f, 0.7000f, 0.3162f, 0.7943f, 0.8913f, 2.7600f, 1.2500f, 1.1400f, 0.6310f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_SPORT_LARGESWIMMINGPOOL \ + { 1.0000f, 0.8200f, 0.3162f, 0.7943f, 1.0000f, 5.4900f, 1.3100f, 1.1400f, 0.4467f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2220f, 0.5500f, 1.1590f, 0.2100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_SPORT_GYMNASIUM \ + { 1.0000f, 0.8100f, 0.3162f, 0.4467f, 0.8913f, 3.1400f, 1.0600f, 1.3500f, 0.3981f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0450f, { 0.0000f, 0.0000f, 0.0000f }, 0.1460f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_FULLSTADIUM \ + { 1.0000f, 1.0000f, 0.3162f, 0.0708f, 0.7943f, 5.2500f, 0.1700f, 0.8000f, 0.1000f, 0.1880f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_STADIUMTANNOY \ + { 1.0000f, 0.7800f, 0.3162f, 0.5623f, 0.5012f, 2.5300f, 0.8800f, 0.6800f, 0.2818f, 0.2300f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +/* Prefab Presets */ + +#define EFX_REVERB_PRESET_PREFAB_WORKSHOP \ + { 0.4287f, 1.0000f, 0.3162f, 0.1413f, 0.3981f, 0.7600f, 1.0000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PREFAB_SCHOOLROOM \ + { 0.4022f, 0.6900f, 0.3162f, 0.6310f, 0.5012f, 0.9800f, 0.4500f, 0.1800f, 1.4125f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PREFAB_PRACTISEROOM \ + { 0.4022f, 0.8700f, 0.3162f, 0.3981f, 0.5012f, 1.1200f, 0.5600f, 0.1800f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PREFAB_OUTHOUSE \ + { 1.0000f, 0.8200f, 0.3162f, 0.1122f, 0.1585f, 1.3800f, 0.3800f, 0.3500f, 0.8913f, 0.0240f, { 0.0000f, 0.0000f, -0.0000f }, 0.6310f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.1210f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PREFAB_CARAVAN \ + { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.1259f, 0.4300f, 1.5000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +/* Dome and Pipe Presets */ + +#define EFX_REVERB_PRESET_DOME_TOMB \ + { 1.0000f, 0.7900f, 0.3162f, 0.3548f, 0.2239f, 4.1800f, 0.2100f, 0.1000f, 0.3868f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 1.6788f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PIPE_SMALL \ + { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 5.0400f, 0.1000f, 0.1000f, 0.5012f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 2.5119f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DOME_SAINTPAULS \ + { 1.0000f, 0.8700f, 0.3162f, 0.3548f, 0.2239f, 10.4800f, 0.1900f, 0.1000f, 0.1778f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0420f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PIPE_LONGTHIN \ + { 0.2560f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 9.2100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PIPE_LARGE \ + { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 8.4500f, 0.1000f, 0.1000f, 0.3981f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PIPE_RESONANT \ + { 0.1373f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 6.8100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } + +/* Outdoors Presets */ + +#define EFX_REVERB_PRESET_OUTDOORS_BACKYARD \ + { 1.0000f, 0.4500f, 0.3162f, 0.2512f, 0.5012f, 1.1200f, 0.3400f, 0.4600f, 0.4467f, 0.0690f, { 0.0000f, 0.0000f, -0.0000f }, 0.7079f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS \ + { 1.0000f, 0.0000f, 0.3162f, 0.0112f, 0.6310f, 2.1300f, 0.2100f, 0.4600f, 0.1778f, 0.3000f, { 0.0000f, 0.0000f, -0.0000f }, 0.4467f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON \ + { 1.0000f, 0.7400f, 0.3162f, 0.1778f, 0.6310f, 3.8900f, 0.2100f, 0.4600f, 0.3162f, 0.2230f, { 0.0000f, 0.0000f, -0.0000f }, 0.3548f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_CREEK \ + { 1.0000f, 0.3500f, 0.3162f, 0.1778f, 0.5012f, 2.1300f, 0.2100f, 0.4600f, 0.3981f, 0.1150f, { 0.0000f, 0.0000f, -0.0000f }, 0.1995f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_VALLEY \ + { 1.0000f, 0.2800f, 0.3162f, 0.0282f, 0.1585f, 2.8800f, 0.2600f, 0.3500f, 0.1413f, 0.2630f, { 0.0000f, 0.0000f, -0.0000f }, 0.3981f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +/* Mood Presets */ + +#define EFX_REVERB_PRESET_MOOD_HEAVEN \ + { 1.0000f, 0.9400f, 0.3162f, 0.7943f, 0.4467f, 5.0400f, 1.1200f, 0.5600f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0800f, 2.7420f, 0.0500f, 0.9977f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_MOOD_HELL \ + { 1.0000f, 0.5700f, 0.3162f, 0.3548f, 0.4467f, 3.5700f, 0.4900f, 2.0000f, 0.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1100f, 0.0400f, 2.1090f, 0.5200f, 0.9943f, 5000.0000f, 139.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_MOOD_MEMORY \ + { 1.0000f, 0.8500f, 0.3162f, 0.6310f, 0.3548f, 4.0600f, 0.8200f, 0.5600f, 0.0398f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.4740f, 0.4500f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +/* Driving Presets */ + +#define EFX_REVERB_PRESET_DRIVING_COMMENTATOR \ + { 1.0000f, 0.0000f, 0.3162f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_PITGARAGE \ + { 0.4287f, 0.5900f, 0.3162f, 0.7079f, 0.5623f, 1.7200f, 0.9300f, 0.8700f, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DRIVING_INCAR_RACER \ + { 0.0832f, 0.8000f, 0.3162f, 1.0000f, 0.7943f, 0.1700f, 2.0000f, 0.4100f, 1.7783f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS \ + { 0.0832f, 0.8000f, 0.3162f, 0.6310f, 1.0000f, 0.1700f, 0.7500f, 0.4100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY \ + { 0.2560f, 1.0000f, 0.3162f, 0.1000f, 0.5012f, 0.1300f, 0.4100f, 0.4600f, 0.7943f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_FULLGRANDSTAND \ + { 1.0000f, 1.0000f, 0.3162f, 0.2818f, 0.6310f, 3.0100f, 1.3700f, 1.2800f, 0.3548f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.1778f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DRIVING_EMPTYGRANDSTAND \ + { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 0.7943f, 4.6200f, 1.7500f, 1.4000f, 0.2082f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DRIVING_TUNNEL \ + { 1.0000f, 0.8100f, 0.3162f, 0.3981f, 0.8913f, 3.4200f, 0.9400f, 1.3100f, 0.7079f, 0.0510f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.0500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 155.3000f, 0.0000f, 0x1 } + +/* City Presets */ + +#define EFX_REVERB_PRESET_CITY_STREETS \ + { 1.0000f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.7900f, 1.1200f, 0.9100f, 0.2818f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 0.1995f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY_SUBWAY \ + { 1.0000f, 0.7400f, 0.3162f, 0.7079f, 0.8913f, 3.0100f, 1.2300f, 0.9100f, 0.7079f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY_MUSEUM \ + { 1.0000f, 0.8200f, 0.3162f, 0.1778f, 0.1778f, 3.2800f, 1.4000f, 0.5700f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_CITY_LIBRARY \ + { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.0891f, 2.7600f, 0.8900f, 0.4100f, 0.3548f, 0.0290f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_CITY_UNDERPASS \ + { 1.0000f, 0.8200f, 0.3162f, 0.4467f, 0.8913f, 3.5700f, 1.1200f, 0.9100f, 0.3981f, 0.0590f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1400f, 0.2500f, 0.0000f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY_ABANDONED \ + { 1.0000f, 0.6900f, 0.3162f, 0.7943f, 0.8913f, 3.2800f, 1.1700f, 0.9100f, 0.4467f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9966f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +/* Misc. Presets */ + +#define EFX_REVERB_PRESET_DUSTYROOM \ + { 0.3645f, 0.5600f, 0.3162f, 0.7943f, 0.7079f, 1.7900f, 0.3800f, 0.2100f, 0.5012f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0060f, { 0.0000f, 0.0000f, 0.0000f }, 0.2020f, 0.0500f, 0.2500f, 0.0000f, 0.9886f, 13046.0000f, 163.3000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CHAPEL \ + { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 1.0000f, 4.6200f, 0.6400f, 1.2300f, 0.4467f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.1100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SMALLWATERROOM \ + { 1.0000f, 0.7000f, 0.3162f, 0.4477f, 1.0000f, 1.5100f, 1.2500f, 1.1400f, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#endif /* EFX_PRESETS_H */ diff --git a/apps/openmw/mwsound/efx.h b/apps/openmw/mwsound/efx.h new file mode 100644 index 000000000..57766983f --- /dev/null +++ b/apps/openmw/mwsound/efx.h @@ -0,0 +1,761 @@ +#ifndef AL_EFX_H +#define AL_EFX_H + + +#include "alc.h" +#include "al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ALC_EXT_EFX_NAME "ALC_EXT_EFX" + +#define ALC_EFX_MAJOR_VERSION 0x20001 +#define ALC_EFX_MINOR_VERSION 0x20002 +#define ALC_MAX_AUXILIARY_SENDS 0x20003 + + +/* Listener properties. */ +#define AL_METERS_PER_UNIT 0x20004 + +/* Source properties. */ +#define AL_DIRECT_FILTER 0x20005 +#define AL_AUXILIARY_SEND_FILTER 0x20006 +#define AL_AIR_ABSORPTION_FACTOR 0x20007 +#define AL_ROOM_ROLLOFF_FACTOR 0x20008 +#define AL_CONE_OUTER_GAINHF 0x20009 +#define AL_DIRECT_FILTER_GAINHF_AUTO 0x2000A +#define AL_AUXILIARY_SEND_FILTER_GAIN_AUTO 0x2000B +#define AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO 0x2000C + + +/* Effect properties. */ + +/* Reverb effect parameters */ +#define AL_REVERB_DENSITY 0x0001 +#define AL_REVERB_DIFFUSION 0x0002 +#define AL_REVERB_GAIN 0x0003 +#define AL_REVERB_GAINHF 0x0004 +#define AL_REVERB_DECAY_TIME 0x0005 +#define AL_REVERB_DECAY_HFRATIO 0x0006 +#define AL_REVERB_REFLECTIONS_GAIN 0x0007 +#define AL_REVERB_REFLECTIONS_DELAY 0x0008 +#define AL_REVERB_LATE_REVERB_GAIN 0x0009 +#define AL_REVERB_LATE_REVERB_DELAY 0x000A +#define AL_REVERB_AIR_ABSORPTION_GAINHF 0x000B +#define AL_REVERB_ROOM_ROLLOFF_FACTOR 0x000C +#define AL_REVERB_DECAY_HFLIMIT 0x000D + +/* EAX Reverb effect parameters */ +#define AL_EAXREVERB_DENSITY 0x0001 +#define AL_EAXREVERB_DIFFUSION 0x0002 +#define AL_EAXREVERB_GAIN 0x0003 +#define AL_EAXREVERB_GAINHF 0x0004 +#define AL_EAXREVERB_GAINLF 0x0005 +#define AL_EAXREVERB_DECAY_TIME 0x0006 +#define AL_EAXREVERB_DECAY_HFRATIO 0x0007 +#define AL_EAXREVERB_DECAY_LFRATIO 0x0008 +#define AL_EAXREVERB_REFLECTIONS_GAIN 0x0009 +#define AL_EAXREVERB_REFLECTIONS_DELAY 0x000A +#define AL_EAXREVERB_REFLECTIONS_PAN 0x000B +#define AL_EAXREVERB_LATE_REVERB_GAIN 0x000C +#define AL_EAXREVERB_LATE_REVERB_DELAY 0x000D +#define AL_EAXREVERB_LATE_REVERB_PAN 0x000E +#define AL_EAXREVERB_ECHO_TIME 0x000F +#define AL_EAXREVERB_ECHO_DEPTH 0x0010 +#define AL_EAXREVERB_MODULATION_TIME 0x0011 +#define AL_EAXREVERB_MODULATION_DEPTH 0x0012 +#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF 0x0013 +#define AL_EAXREVERB_HFREFERENCE 0x0014 +#define AL_EAXREVERB_LFREFERENCE 0x0015 +#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016 +#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017 + +/* Chorus effect parameters */ +#define AL_CHORUS_WAVEFORM 0x0001 +#define AL_CHORUS_PHASE 0x0002 +#define AL_CHORUS_RATE 0x0003 +#define AL_CHORUS_DEPTH 0x0004 +#define AL_CHORUS_FEEDBACK 0x0005 +#define AL_CHORUS_DELAY 0x0006 + +/* Distortion effect parameters */ +#define AL_DISTORTION_EDGE 0x0001 +#define AL_DISTORTION_GAIN 0x0002 +#define AL_DISTORTION_LOWPASS_CUTOFF 0x0003 +#define AL_DISTORTION_EQCENTER 0x0004 +#define AL_DISTORTION_EQBANDWIDTH 0x0005 + +/* Echo effect parameters */ +#define AL_ECHO_DELAY 0x0001 +#define AL_ECHO_LRDELAY 0x0002 +#define AL_ECHO_DAMPING 0x0003 +#define AL_ECHO_FEEDBACK 0x0004 +#define AL_ECHO_SPREAD 0x0005 + +/* Flanger effect parameters */ +#define AL_FLANGER_WAVEFORM 0x0001 +#define AL_FLANGER_PHASE 0x0002 +#define AL_FLANGER_RATE 0x0003 +#define AL_FLANGER_DEPTH 0x0004 +#define AL_FLANGER_FEEDBACK 0x0005 +#define AL_FLANGER_DELAY 0x0006 + +/* Frequency shifter effect parameters */ +#define AL_FREQUENCY_SHIFTER_FREQUENCY 0x0001 +#define AL_FREQUENCY_SHIFTER_LEFT_DIRECTION 0x0002 +#define AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION 0x0003 + +/* Vocal morpher effect parameters */ +#define AL_VOCAL_MORPHER_PHONEMEA 0x0001 +#define AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING 0x0002 +#define AL_VOCAL_MORPHER_PHONEMEB 0x0003 +#define AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING 0x0004 +#define AL_VOCAL_MORPHER_WAVEFORM 0x0005 +#define AL_VOCAL_MORPHER_RATE 0x0006 + +/* Pitchshifter effect parameters */ +#define AL_PITCH_SHIFTER_COARSE_TUNE 0x0001 +#define AL_PITCH_SHIFTER_FINE_TUNE 0x0002 + +/* Ringmodulator effect parameters */ +#define AL_RING_MODULATOR_FREQUENCY 0x0001 +#define AL_RING_MODULATOR_HIGHPASS_CUTOFF 0x0002 +#define AL_RING_MODULATOR_WAVEFORM 0x0003 + +/* Autowah effect parameters */ +#define AL_AUTOWAH_ATTACK_TIME 0x0001 +#define AL_AUTOWAH_RELEASE_TIME 0x0002 +#define AL_AUTOWAH_RESONANCE 0x0003 +#define AL_AUTOWAH_PEAK_GAIN 0x0004 + +/* Compressor effect parameters */ +#define AL_COMPRESSOR_ONOFF 0x0001 + +/* Equalizer effect parameters */ +#define AL_EQUALIZER_LOW_GAIN 0x0001 +#define AL_EQUALIZER_LOW_CUTOFF 0x0002 +#define AL_EQUALIZER_MID1_GAIN 0x0003 +#define AL_EQUALIZER_MID1_CENTER 0x0004 +#define AL_EQUALIZER_MID1_WIDTH 0x0005 +#define AL_EQUALIZER_MID2_GAIN 0x0006 +#define AL_EQUALIZER_MID2_CENTER 0x0007 +#define AL_EQUALIZER_MID2_WIDTH 0x0008 +#define AL_EQUALIZER_HIGH_GAIN 0x0009 +#define AL_EQUALIZER_HIGH_CUTOFF 0x000A + +/* Effect type */ +#define AL_EFFECT_FIRST_PARAMETER 0x0000 +#define AL_EFFECT_LAST_PARAMETER 0x8000 +#define AL_EFFECT_TYPE 0x8001 + +/* Effect types, used with the AL_EFFECT_TYPE property */ +#define AL_EFFECT_NULL 0x0000 +#define AL_EFFECT_REVERB 0x0001 +#define AL_EFFECT_CHORUS 0x0002 +#define AL_EFFECT_DISTORTION 0x0003 +#define AL_EFFECT_ECHO 0x0004 +#define AL_EFFECT_FLANGER 0x0005 +#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006 +#define AL_EFFECT_VOCAL_MORPHER 0x0007 +#define AL_EFFECT_PITCH_SHIFTER 0x0008 +#define AL_EFFECT_RING_MODULATOR 0x0009 +#define AL_EFFECT_AUTOWAH 0x000A +#define AL_EFFECT_COMPRESSOR 0x000B +#define AL_EFFECT_EQUALIZER 0x000C +#define AL_EFFECT_EAXREVERB 0x8000 + +/* Auxiliary Effect Slot properties. */ +#define AL_EFFECTSLOT_EFFECT 0x0001 +#define AL_EFFECTSLOT_GAIN 0x0002 +#define AL_EFFECTSLOT_AUXILIARY_SEND_AUTO 0x0003 + +/* NULL Auxiliary Slot ID to disable a source send. */ +#define AL_EFFECTSLOT_NULL 0x0000 + + +/* Filter properties. */ + +/* Lowpass filter parameters */ +#define AL_LOWPASS_GAIN 0x0001 +#define AL_LOWPASS_GAINHF 0x0002 + +/* Highpass filter parameters */ +#define AL_HIGHPASS_GAIN 0x0001 +#define AL_HIGHPASS_GAINLF 0x0002 + +/* Bandpass filter parameters */ +#define AL_BANDPASS_GAIN 0x0001 +#define AL_BANDPASS_GAINLF 0x0002 +#define AL_BANDPASS_GAINHF 0x0003 + +/* Filter type */ +#define AL_FILTER_FIRST_PARAMETER 0x0000 +#define AL_FILTER_LAST_PARAMETER 0x8000 +#define AL_FILTER_TYPE 0x8001 + +/* Filter types, used with the AL_FILTER_TYPE property */ +#define AL_FILTER_NULL 0x0000 +#define AL_FILTER_LOWPASS 0x0001 +#define AL_FILTER_HIGHPASS 0x0002 +#define AL_FILTER_BANDPASS 0x0003 + + +/* Effect object function types. */ +typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, const ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint); +typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, const ALint*); +typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, const ALfloat*); +typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*); + +/* Filter object function types. */ +typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, const ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint); +typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, const ALint*); +typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, const ALfloat*); +typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*); + +/* Auxiliary Effect Slot object function types. */ +typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, const ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, const ALint*); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, const ALfloat*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*); + +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects); +AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects); +AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect); +AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *piValues); +AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues); + +AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters); +AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters); +AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter); +AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *piValues); +AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues); + +AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots); +AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots); +AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues); +#endif + +/* Filter ranges and defaults. */ + +/* Lowpass filter */ +#define AL_LOWPASS_MIN_GAIN (0.0f) +#define AL_LOWPASS_MAX_GAIN (1.0f) +#define AL_LOWPASS_DEFAULT_GAIN (1.0f) + +#define AL_LOWPASS_MIN_GAINHF (0.0f) +#define AL_LOWPASS_MAX_GAINHF (1.0f) +#define AL_LOWPASS_DEFAULT_GAINHF (1.0f) + +/* Highpass filter */ +#define AL_HIGHPASS_MIN_GAIN (0.0f) +#define AL_HIGHPASS_MAX_GAIN (1.0f) +#define AL_HIGHPASS_DEFAULT_GAIN (1.0f) + +#define AL_HIGHPASS_MIN_GAINLF (0.0f) +#define AL_HIGHPASS_MAX_GAINLF (1.0f) +#define AL_HIGHPASS_DEFAULT_GAINLF (1.0f) + +/* Bandpass filter */ +#define AL_BANDPASS_MIN_GAIN (0.0f) +#define AL_BANDPASS_MAX_GAIN (1.0f) +#define AL_BANDPASS_DEFAULT_GAIN (1.0f) + +#define AL_BANDPASS_MIN_GAINHF (0.0f) +#define AL_BANDPASS_MAX_GAINHF (1.0f) +#define AL_BANDPASS_DEFAULT_GAINHF (1.0f) + +#define AL_BANDPASS_MIN_GAINLF (0.0f) +#define AL_BANDPASS_MAX_GAINLF (1.0f) +#define AL_BANDPASS_DEFAULT_GAINLF (1.0f) + + +/* Effect parameter ranges and defaults. */ + +/* Standard reverb effect */ +#define AL_REVERB_MIN_DENSITY (0.0f) +#define AL_REVERB_MAX_DENSITY (1.0f) +#define AL_REVERB_DEFAULT_DENSITY (1.0f) + +#define AL_REVERB_MIN_DIFFUSION (0.0f) +#define AL_REVERB_MAX_DIFFUSION (1.0f) +#define AL_REVERB_DEFAULT_DIFFUSION (1.0f) + +#define AL_REVERB_MIN_GAIN (0.0f) +#define AL_REVERB_MAX_GAIN (1.0f) +#define AL_REVERB_DEFAULT_GAIN (0.32f) + +#define AL_REVERB_MIN_GAINHF (0.0f) +#define AL_REVERB_MAX_GAINHF (1.0f) +#define AL_REVERB_DEFAULT_GAINHF (0.89f) + +#define AL_REVERB_MIN_DECAY_TIME (0.1f) +#define AL_REVERB_MAX_DECAY_TIME (20.0f) +#define AL_REVERB_DEFAULT_DECAY_TIME (1.49f) + +#define AL_REVERB_MIN_DECAY_HFRATIO (0.1f) +#define AL_REVERB_MAX_DECAY_HFRATIO (2.0f) +#define AL_REVERB_DEFAULT_DECAY_HFRATIO (0.83f) + +#define AL_REVERB_MIN_REFLECTIONS_GAIN (0.0f) +#define AL_REVERB_MAX_REFLECTIONS_GAIN (3.16f) +#define AL_REVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) + +#define AL_REVERB_MIN_REFLECTIONS_DELAY (0.0f) +#define AL_REVERB_MAX_REFLECTIONS_DELAY (0.3f) +#define AL_REVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) + +#define AL_REVERB_MIN_LATE_REVERB_GAIN (0.0f) +#define AL_REVERB_MAX_LATE_REVERB_GAIN (10.0f) +#define AL_REVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) + +#define AL_REVERB_MIN_LATE_REVERB_DELAY (0.0f) +#define AL_REVERB_MAX_LATE_REVERB_DELAY (0.1f) +#define AL_REVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) + +#define AL_REVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) +#define AL_REVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) +#define AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) + +#define AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_REVERB_MIN_DECAY_HFLIMIT AL_FALSE +#define AL_REVERB_MAX_DECAY_HFLIMIT AL_TRUE +#define AL_REVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE + +/* EAX reverb effect */ +#define AL_EAXREVERB_MIN_DENSITY (0.0f) +#define AL_EAXREVERB_MAX_DENSITY (1.0f) +#define AL_EAXREVERB_DEFAULT_DENSITY (1.0f) + +#define AL_EAXREVERB_MIN_DIFFUSION (0.0f) +#define AL_EAXREVERB_MAX_DIFFUSION (1.0f) +#define AL_EAXREVERB_DEFAULT_DIFFUSION (1.0f) + +#define AL_EAXREVERB_MIN_GAIN (0.0f) +#define AL_EAXREVERB_MAX_GAIN (1.0f) +#define AL_EAXREVERB_DEFAULT_GAIN (0.32f) + +#define AL_EAXREVERB_MIN_GAINHF (0.0f) +#define AL_EAXREVERB_MAX_GAINHF (1.0f) +#define AL_EAXREVERB_DEFAULT_GAINHF (0.89f) + +#define AL_EAXREVERB_MIN_GAINLF (0.0f) +#define AL_EAXREVERB_MAX_GAINLF (1.0f) +#define AL_EAXREVERB_DEFAULT_GAINLF (1.0f) + +#define AL_EAXREVERB_MIN_DECAY_TIME (0.1f) +#define AL_EAXREVERB_MAX_DECAY_TIME (20.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_TIME (1.49f) + +#define AL_EAXREVERB_MIN_DECAY_HFRATIO (0.1f) +#define AL_EAXREVERB_MAX_DECAY_HFRATIO (2.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_HFRATIO (0.83f) + +#define AL_EAXREVERB_MIN_DECAY_LFRATIO (0.1f) +#define AL_EAXREVERB_MAX_DECAY_LFRATIO (2.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_LFRATIO (1.0f) + +#define AL_EAXREVERB_MIN_REFLECTIONS_GAIN (0.0f) +#define AL_EAXREVERB_MAX_REFLECTIONS_GAIN (3.16f) +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) + +#define AL_EAXREVERB_MIN_REFLECTIONS_DELAY (0.0f) +#define AL_EAXREVERB_MAX_REFLECTIONS_DELAY (0.3f) +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) + +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ (0.0f) + +#define AL_EAXREVERB_MIN_LATE_REVERB_GAIN (0.0f) +#define AL_EAXREVERB_MAX_LATE_REVERB_GAIN (10.0f) +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) + +#define AL_EAXREVERB_MIN_LATE_REVERB_DELAY (0.0f) +#define AL_EAXREVERB_MAX_LATE_REVERB_DELAY (0.1f) +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) + +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ (0.0f) + +#define AL_EAXREVERB_MIN_ECHO_TIME (0.075f) +#define AL_EAXREVERB_MAX_ECHO_TIME (0.25f) +#define AL_EAXREVERB_DEFAULT_ECHO_TIME (0.25f) + +#define AL_EAXREVERB_MIN_ECHO_DEPTH (0.0f) +#define AL_EAXREVERB_MAX_ECHO_DEPTH (1.0f) +#define AL_EAXREVERB_DEFAULT_ECHO_DEPTH (0.0f) + +#define AL_EAXREVERB_MIN_MODULATION_TIME (0.04f) +#define AL_EAXREVERB_MAX_MODULATION_TIME (4.0f) +#define AL_EAXREVERB_DEFAULT_MODULATION_TIME (0.25f) + +#define AL_EAXREVERB_MIN_MODULATION_DEPTH (0.0f) +#define AL_EAXREVERB_MAX_MODULATION_DEPTH (1.0f) +#define AL_EAXREVERB_DEFAULT_MODULATION_DEPTH (0.0f) + +#define AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) +#define AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) +#define AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) + +#define AL_EAXREVERB_MIN_HFREFERENCE (1000.0f) +#define AL_EAXREVERB_MAX_HFREFERENCE (20000.0f) +#define AL_EAXREVERB_DEFAULT_HFREFERENCE (5000.0f) + +#define AL_EAXREVERB_MIN_LFREFERENCE (20.0f) +#define AL_EAXREVERB_MAX_LFREFERENCE (1000.0f) +#define AL_EAXREVERB_DEFAULT_LFREFERENCE (250.0f) + +#define AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_EAXREVERB_MIN_DECAY_HFLIMIT AL_FALSE +#define AL_EAXREVERB_MAX_DECAY_HFLIMIT AL_TRUE +#define AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE + +/* Chorus effect */ +#define AL_CHORUS_WAVEFORM_SINUSOID (0) +#define AL_CHORUS_WAVEFORM_TRIANGLE (1) + +#define AL_CHORUS_MIN_WAVEFORM (0) +#define AL_CHORUS_MAX_WAVEFORM (1) +#define AL_CHORUS_DEFAULT_WAVEFORM (1) + +#define AL_CHORUS_MIN_PHASE (-180) +#define AL_CHORUS_MAX_PHASE (180) +#define AL_CHORUS_DEFAULT_PHASE (90) + +#define AL_CHORUS_MIN_RATE (0.0f) +#define AL_CHORUS_MAX_RATE (10.0f) +#define AL_CHORUS_DEFAULT_RATE (1.1f) + +#define AL_CHORUS_MIN_DEPTH (0.0f) +#define AL_CHORUS_MAX_DEPTH (1.0f) +#define AL_CHORUS_DEFAULT_DEPTH (0.1f) + +#define AL_CHORUS_MIN_FEEDBACK (-1.0f) +#define AL_CHORUS_MAX_FEEDBACK (1.0f) +#define AL_CHORUS_DEFAULT_FEEDBACK (0.25f) + +#define AL_CHORUS_MIN_DELAY (0.0f) +#define AL_CHORUS_MAX_DELAY (0.016f) +#define AL_CHORUS_DEFAULT_DELAY (0.016f) + +/* Distortion effect */ +#define AL_DISTORTION_MIN_EDGE (0.0f) +#define AL_DISTORTION_MAX_EDGE (1.0f) +#define AL_DISTORTION_DEFAULT_EDGE (0.2f) + +#define AL_DISTORTION_MIN_GAIN (0.01f) +#define AL_DISTORTION_MAX_GAIN (1.0f) +#define AL_DISTORTION_DEFAULT_GAIN (0.05f) + +#define AL_DISTORTION_MIN_LOWPASS_CUTOFF (80.0f) +#define AL_DISTORTION_MAX_LOWPASS_CUTOFF (24000.0f) +#define AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF (8000.0f) + +#define AL_DISTORTION_MIN_EQCENTER (80.0f) +#define AL_DISTORTION_MAX_EQCENTER (24000.0f) +#define AL_DISTORTION_DEFAULT_EQCENTER (3600.0f) + +#define AL_DISTORTION_MIN_EQBANDWIDTH (80.0f) +#define AL_DISTORTION_MAX_EQBANDWIDTH (24000.0f) +#define AL_DISTORTION_DEFAULT_EQBANDWIDTH (3600.0f) + +/* Echo effect */ +#define AL_ECHO_MIN_DELAY (0.0f) +#define AL_ECHO_MAX_DELAY (0.207f) +#define AL_ECHO_DEFAULT_DELAY (0.1f) + +#define AL_ECHO_MIN_LRDELAY (0.0f) +#define AL_ECHO_MAX_LRDELAY (0.404f) +#define AL_ECHO_DEFAULT_LRDELAY (0.1f) + +#define AL_ECHO_MIN_DAMPING (0.0f) +#define AL_ECHO_MAX_DAMPING (0.99f) +#define AL_ECHO_DEFAULT_DAMPING (0.5f) + +#define AL_ECHO_MIN_FEEDBACK (0.0f) +#define AL_ECHO_MAX_FEEDBACK (1.0f) +#define AL_ECHO_DEFAULT_FEEDBACK (0.5f) + +#define AL_ECHO_MIN_SPREAD (-1.0f) +#define AL_ECHO_MAX_SPREAD (1.0f) +#define AL_ECHO_DEFAULT_SPREAD (-1.0f) + +/* Flanger effect */ +#define AL_FLANGER_WAVEFORM_SINUSOID (0) +#define AL_FLANGER_WAVEFORM_TRIANGLE (1) + +#define AL_FLANGER_MIN_WAVEFORM (0) +#define AL_FLANGER_MAX_WAVEFORM (1) +#define AL_FLANGER_DEFAULT_WAVEFORM (1) + +#define AL_FLANGER_MIN_PHASE (-180) +#define AL_FLANGER_MAX_PHASE (180) +#define AL_FLANGER_DEFAULT_PHASE (0) + +#define AL_FLANGER_MIN_RATE (0.0f) +#define AL_FLANGER_MAX_RATE (10.0f) +#define AL_FLANGER_DEFAULT_RATE (0.27f) + +#define AL_FLANGER_MIN_DEPTH (0.0f) +#define AL_FLANGER_MAX_DEPTH (1.0f) +#define AL_FLANGER_DEFAULT_DEPTH (1.0f) + +#define AL_FLANGER_MIN_FEEDBACK (-1.0f) +#define AL_FLANGER_MAX_FEEDBACK (1.0f) +#define AL_FLANGER_DEFAULT_FEEDBACK (-0.5f) + +#define AL_FLANGER_MIN_DELAY (0.0f) +#define AL_FLANGER_MAX_DELAY (0.004f) +#define AL_FLANGER_DEFAULT_DELAY (0.002f) + +/* Frequency shifter effect */ +#define AL_FREQUENCY_SHIFTER_MIN_FREQUENCY (0.0f) +#define AL_FREQUENCY_SHIFTER_MAX_FREQUENCY (24000.0f) +#define AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY (0.0f) + +#define AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION (0) +#define AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION (2) +#define AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION (0) + +#define AL_FREQUENCY_SHIFTER_DIRECTION_DOWN (0) +#define AL_FREQUENCY_SHIFTER_DIRECTION_UP (1) +#define AL_FREQUENCY_SHIFTER_DIRECTION_OFF (2) + +#define AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION (0) +#define AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION (2) +#define AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION (0) + +/* Vocal morpher effect */ +#define AL_VOCAL_MORPHER_MIN_PHONEMEA (0) +#define AL_VOCAL_MORPHER_MAX_PHONEMEA (29) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA (0) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING (-24) +#define AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING (24) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING (0) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEB (0) +#define AL_VOCAL_MORPHER_MAX_PHONEMEB (29) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB (10) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING (-24) +#define AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING (24) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING (0) + +#define AL_VOCAL_MORPHER_PHONEME_A (0) +#define AL_VOCAL_MORPHER_PHONEME_E (1) +#define AL_VOCAL_MORPHER_PHONEME_I (2) +#define AL_VOCAL_MORPHER_PHONEME_O (3) +#define AL_VOCAL_MORPHER_PHONEME_U (4) +#define AL_VOCAL_MORPHER_PHONEME_AA (5) +#define AL_VOCAL_MORPHER_PHONEME_AE (6) +#define AL_VOCAL_MORPHER_PHONEME_AH (7) +#define AL_VOCAL_MORPHER_PHONEME_AO (8) +#define AL_VOCAL_MORPHER_PHONEME_EH (9) +#define AL_VOCAL_MORPHER_PHONEME_ER (10) +#define AL_VOCAL_MORPHER_PHONEME_IH (11) +#define AL_VOCAL_MORPHER_PHONEME_IY (12) +#define AL_VOCAL_MORPHER_PHONEME_UH (13) +#define AL_VOCAL_MORPHER_PHONEME_UW (14) +#define AL_VOCAL_MORPHER_PHONEME_B (15) +#define AL_VOCAL_MORPHER_PHONEME_D (16) +#define AL_VOCAL_MORPHER_PHONEME_F (17) +#define AL_VOCAL_MORPHER_PHONEME_G (18) +#define AL_VOCAL_MORPHER_PHONEME_J (19) +#define AL_VOCAL_MORPHER_PHONEME_K (20) +#define AL_VOCAL_MORPHER_PHONEME_L (21) +#define AL_VOCAL_MORPHER_PHONEME_M (22) +#define AL_VOCAL_MORPHER_PHONEME_N (23) +#define AL_VOCAL_MORPHER_PHONEME_P (24) +#define AL_VOCAL_MORPHER_PHONEME_R (25) +#define AL_VOCAL_MORPHER_PHONEME_S (26) +#define AL_VOCAL_MORPHER_PHONEME_T (27) +#define AL_VOCAL_MORPHER_PHONEME_V (28) +#define AL_VOCAL_MORPHER_PHONEME_Z (29) + +#define AL_VOCAL_MORPHER_WAVEFORM_SINUSOID (0) +#define AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE (1) +#define AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH (2) + +#define AL_VOCAL_MORPHER_MIN_WAVEFORM (0) +#define AL_VOCAL_MORPHER_MAX_WAVEFORM (2) +#define AL_VOCAL_MORPHER_DEFAULT_WAVEFORM (0) + +#define AL_VOCAL_MORPHER_MIN_RATE (0.0f) +#define AL_VOCAL_MORPHER_MAX_RATE (10.0f) +#define AL_VOCAL_MORPHER_DEFAULT_RATE (1.41f) + +/* Pitch shifter effect */ +#define AL_PITCH_SHIFTER_MIN_COARSE_TUNE (-12) +#define AL_PITCH_SHIFTER_MAX_COARSE_TUNE (12) +#define AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE (12) + +#define AL_PITCH_SHIFTER_MIN_FINE_TUNE (-50) +#define AL_PITCH_SHIFTER_MAX_FINE_TUNE (50) +#define AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE (0) + +/* Ring modulator effect */ +#define AL_RING_MODULATOR_MIN_FREQUENCY (0.0f) +#define AL_RING_MODULATOR_MAX_FREQUENCY (8000.0f) +#define AL_RING_MODULATOR_DEFAULT_FREQUENCY (440.0f) + +#define AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF (0.0f) +#define AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF (24000.0f) +#define AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF (800.0f) + +#define AL_RING_MODULATOR_SINUSOID (0) +#define AL_RING_MODULATOR_SAWTOOTH (1) +#define AL_RING_MODULATOR_SQUARE (2) + +#define AL_RING_MODULATOR_MIN_WAVEFORM (0) +#define AL_RING_MODULATOR_MAX_WAVEFORM (2) +#define AL_RING_MODULATOR_DEFAULT_WAVEFORM (0) + +/* Autowah effect */ +#define AL_AUTOWAH_MIN_ATTACK_TIME (0.0001f) +#define AL_AUTOWAH_MAX_ATTACK_TIME (1.0f) +#define AL_AUTOWAH_DEFAULT_ATTACK_TIME (0.06f) + +#define AL_AUTOWAH_MIN_RELEASE_TIME (0.0001f) +#define AL_AUTOWAH_MAX_RELEASE_TIME (1.0f) +#define AL_AUTOWAH_DEFAULT_RELEASE_TIME (0.06f) + +#define AL_AUTOWAH_MIN_RESONANCE (2.0f) +#define AL_AUTOWAH_MAX_RESONANCE (1000.0f) +#define AL_AUTOWAH_DEFAULT_RESONANCE (1000.0f) + +#define AL_AUTOWAH_MIN_PEAK_GAIN (0.00003f) +#define AL_AUTOWAH_MAX_PEAK_GAIN (31621.0f) +#define AL_AUTOWAH_DEFAULT_PEAK_GAIN (11.22f) + +/* Compressor effect */ +#define AL_COMPRESSOR_MIN_ONOFF (0) +#define AL_COMPRESSOR_MAX_ONOFF (1) +#define AL_COMPRESSOR_DEFAULT_ONOFF (1) + +/* Equalizer effect */ +#define AL_EQUALIZER_MIN_LOW_GAIN (0.126f) +#define AL_EQUALIZER_MAX_LOW_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_LOW_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_LOW_CUTOFF (50.0f) +#define AL_EQUALIZER_MAX_LOW_CUTOFF (800.0f) +#define AL_EQUALIZER_DEFAULT_LOW_CUTOFF (200.0f) + +#define AL_EQUALIZER_MIN_MID1_GAIN (0.126f) +#define AL_EQUALIZER_MAX_MID1_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_MID1_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_MID1_CENTER (200.0f) +#define AL_EQUALIZER_MAX_MID1_CENTER (3000.0f) +#define AL_EQUALIZER_DEFAULT_MID1_CENTER (500.0f) + +#define AL_EQUALIZER_MIN_MID1_WIDTH (0.01f) +#define AL_EQUALIZER_MAX_MID1_WIDTH (1.0f) +#define AL_EQUALIZER_DEFAULT_MID1_WIDTH (1.0f) + +#define AL_EQUALIZER_MIN_MID2_GAIN (0.126f) +#define AL_EQUALIZER_MAX_MID2_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_MID2_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_MID2_CENTER (1000.0f) +#define AL_EQUALIZER_MAX_MID2_CENTER (8000.0f) +#define AL_EQUALIZER_DEFAULT_MID2_CENTER (3000.0f) + +#define AL_EQUALIZER_MIN_MID2_WIDTH (0.01f) +#define AL_EQUALIZER_MAX_MID2_WIDTH (1.0f) +#define AL_EQUALIZER_DEFAULT_MID2_WIDTH (1.0f) + +#define AL_EQUALIZER_MIN_HIGH_GAIN (0.126f) +#define AL_EQUALIZER_MAX_HIGH_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_HIGH_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_HIGH_CUTOFF (4000.0f) +#define AL_EQUALIZER_MAX_HIGH_CUTOFF (16000.0f) +#define AL_EQUALIZER_DEFAULT_HIGH_CUTOFF (6000.0f) + + +/* Source parameter value ranges and defaults. */ +#define AL_MIN_AIR_ABSORPTION_FACTOR (0.0f) +#define AL_MAX_AIR_ABSORPTION_FACTOR (10.0f) +#define AL_DEFAULT_AIR_ABSORPTION_FACTOR (0.0f) + +#define AL_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_MIN_CONE_OUTER_GAINHF (0.0f) +#define AL_MAX_CONE_OUTER_GAINHF (1.0f) +#define AL_DEFAULT_CONE_OUTER_GAINHF (1.0f) + +#define AL_MIN_DIRECT_FILTER_GAINHF_AUTO AL_FALSE +#define AL_MAX_DIRECT_FILTER_GAINHF_AUTO AL_TRUE +#define AL_DEFAULT_DIRECT_FILTER_GAINHF_AUTO AL_TRUE + +#define AL_MIN_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_FALSE +#define AL_MAX_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE +#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE + +#define AL_MIN_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_FALSE +#define AL_MAX_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE +#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE + + +/* Listener parameter value ranges and defaults. */ +#define AL_MIN_METERS_PER_UNIT FLT_MIN +#define AL_MAX_METERS_PER_UNIT FLT_MAX +#define AL_DEFAULT_METERS_PER_UNIT (1.0f) + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* AL_EFX_H */ diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 0e000f8d8..f2e8bad5c 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -24,28 +24,6 @@ #define ALC_ALL_DEVICES_SPECIFIER 0x1013 #endif -#ifndef ALC_SOFT_HRTF -#define ALC_SOFT_HRTF 1 -#define ALC_HRTF_SOFT 0x1992 -#define ALC_DONT_CARE_SOFT 0x0002 -#define ALC_HRTF_STATUS_SOFT 0x1993 -#define ALC_HRTF_DISABLED_SOFT 0x0000 -#define ALC_HRTF_ENABLED_SOFT 0x0001 -#define ALC_HRTF_DENIED_SOFT 0x0002 -#define ALC_HRTF_REQUIRED_SOFT 0x0003 -#define ALC_HRTF_HEADPHONES_DETECTED_SOFT 0x0004 -#define ALC_HRTF_UNSUPPORTED_FORMAT_SOFT 0x0005 -#define ALC_NUM_HRTF_SPECIFIERS_SOFT 0x1994 -#define ALC_HRTF_SPECIFIER_SOFT 0x1995 -#define ALC_HRTF_ID_SOFT 0x1996 -typedef const ALCchar* (ALC_APIENTRY*LPALCGETSTRINGISOFT)(ALCdevice *device, ALCenum paramName, ALCsizei index); -typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs); -#ifdef AL_ALEXT_PROTOTYPES -ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index); -ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs); -#endif -#endif - #define MAKE_PTRID(id) ((void*)(uintptr_t)id) #define GET_PTRID(ptr) ((ALuint)(uintptr_t)ptr) diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index cb943d87e..c35c1b2a2 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -8,6 +8,7 @@ #include "alc.h" #include "al.h" +#include "alext.h" #include "sound_output.hpp" From 9e45f6d05f95c9c5566d26ed147214b345456b1f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 01:02:08 -0700 Subject: [PATCH 047/505] Make a note that stopTrack needs to be called for a stopping track --- apps/openmw/mwbase/soundmanager.hpp | 3 ++- apps/openmw/mwsound/soundmanagerimp.cpp | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 9986564cd..4439fe8f3 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -107,7 +107,8 @@ namespace MWBase /// If the actor is not saying anything, returns 0. virtual SoundStream *playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; - ///< Play a 2D audio track, using a custom decoder + ///< Play a 2D audio track, using a custom decoder. The caller is expected to call + /// stopTrack with the returned handle when done. virtual void stopTrack(SoundStream *stream) = 0; ///< Stop the given audio track from playing diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index f8b753a18..0dd3ef754 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -1083,7 +1083,6 @@ namespace MWSound if(!mOutput->isStreamPlaying(sound)) { mOutput->finishStream(sound); - mUnusedStreams.push_back(sound); trkiter = mActiveTracks.erase(trkiter); } else From 617c05f5571a64fc09ebeb8407abecf8cec30010 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 01:19:26 -0700 Subject: [PATCH 048/505] Make Sound and Stream sibling types To avoid being able to accidentally cast a Stream* to a Sound*, or vice-versa. --- apps/openmw/mwsound/sound.hpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 9a3fc4e75..1389835db 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -7,9 +7,10 @@ namespace MWSound { - class Sound { - Sound& operator=(const Sound &rhs); - Sound(const Sound &rhs); + class SoundBase { + SoundBase& operator=(const SoundBase&) = delete; + SoundBase(const SoundBase&) = delete; + SoundBase(SoundBase&&) = delete; osg::Vec3f mPos; float mVolume; /* NOTE: Real volume = mVolume*mBaseVolume */ @@ -80,17 +81,26 @@ namespace MWSound mHandle = nullptr; } - Sound() + SoundBase() : mPos(0.0f, 0.0f, 0.0f), mVolume(1.0f), mBaseVolume(1.0f), mPitch(1.0f) , mMinDistance(1.0f), mMaxDistance(1000.0f), mFlags(0), mFadeOutTime(0.0f) - , mHandle(0) + , mHandle(nullptr) { } }; - // Same as above, but it's a different type since the output handles them differently - class Stream : public Sound { - Stream& operator=(const Stream &rhs); - Stream(const Stream &rhs); + class Sound : public SoundBase { + Sound& operator=(const Sound&) = delete; + Sound(const Sound&) = delete; + Sound(Sound&&) = delete; + + public: + Sound() { } + }; + + class Stream : public SoundBase { + Stream& operator=(const Stream&) = delete; + Stream(const Stream&) = delete; + Stream(Stream&&) = delete; public: Stream() { } From c5a3fb7ccdcf3f9dd780b8d76e4df65b8a451489 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 02:48:10 -0700 Subject: [PATCH 049/505] Simplify checking for near water sfx change Rather than checking every frame you're near the water, only check when the current cell changed (the sfx will only change when moving between interior and exterior). It also doesn't need to look through all playing sounds, as it's a local one not attached to a Ptr. --- apps/openmw/mwsound/soundmanagerimp.cpp | 36 ++++++++++++++----------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 0dd3ef754..67c7f77e4 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -72,8 +72,8 @@ namespace MWSound mNearWaterPoints = mFallback.getFallbackInt("Water_NearWaterPoints"); mNearWaterIndoorTolerance = mFallback.getFallbackFloat("Water_NearWaterIndoorTolerance"); mNearWaterOutdoorTolerance = mFallback.getFallbackFloat("Water_NearWaterOutdoorTolerance"); - mNearWaterIndoorID = mFallback.getFallbackString("Water_NearWaterIndoorID"); - mNearWaterOutdoorID = mFallback.getFallbackString("Water_NearWaterOutdoorID"); + mNearWaterIndoorID = Misc::StringUtils::lowerCase(mFallback.getFallbackString("Water_NearWaterIndoorID")); + mNearWaterOutdoorID = Misc::StringUtils::lowerCase(mFallback.getFallbackString("Water_NearWaterOutdoorID")); mBufferCacheMin = std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1); mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1); @@ -873,16 +873,18 @@ namespace MWSound void SoundManager::updateWaterSound(float /*duration*/) { + static const ESM::Cell *LastCell; MWBase::World* world = MWBase::Environment::get().getWorld(); const MWWorld::ConstPtr player = world->getPlayerPtr(); osg::Vec3f pos = player.getRefData().getPosition().asVec3(); + const ESM::Cell *curcell = player.getCell()->getCell(); float volume = 0.0f; const std::string& soundId = player.getCell()->isExterior() ? mNearWaterOutdoorID : mNearWaterIndoorID; if (!mListenerUnderwater) { - if (player.getCell()->getCell()->hasWater()) + if (curcell->hasWater()) { float dist = std::abs(player.getCell()->getWaterLevel() - pos.z()); @@ -929,25 +931,24 @@ namespace MWSound mOutput->finishSound(mNearWaterSound); mNearWaterSound = nullptr; } - else + else if(LastCell != curcell) { bool soundIdChanged = false; - Sound_Buffer* sfx = lookupSound(Misc::StringUtils::lowerCase(soundId)); - - for (SoundMap::const_iterator snditer = mActiveSounds.begin(); snditer != mActiveSounds.end(); ++snditer) + Sound_Buffer* sfx = lookupSound(soundId); + SoundMap::const_iterator snditer = mActiveSounds.find(MWWorld::Ptr()); + if(snditer != mActiveSounds.end()) { - for (SoundBufferRefPairList::const_iterator pairiter = snditer->second.begin(); pairiter != snditer->second.end(); ++pairiter) - { - if (pairiter->first == mNearWaterSound) - { - if (pairiter->second != sfx) - soundIdChanged = true; - break; - } - } + SoundBufferRefPairList::const_iterator pairiter = std::find_if( + snditer->second.begin(), snditer->second.end(), + [this](const SoundBufferRefPairList::value_type &item) -> bool + { return mNearWaterSound == item.first; } + ); + if (pairiter != snditer->second.end() && pairiter->second != sfx) + soundIdChanged = true; } + LastCell = curcell; if (soundIdChanged) { mOutput->finishSound(mNearWaterSound); @@ -958,7 +959,10 @@ namespace MWSound } } else if (volume > 0.0f) + { + LastCell = curcell; mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop); + } } void SoundManager::updateSounds(float duration) From 3d37cb3cf6cd77f4e0c620e914ff97af4dcbdd7d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 03:06:58 -0700 Subject: [PATCH 050/505] Load EFX functions when available --- apps/openmw/mwsound/openal_output.cpp | 93 +++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index f2e8bad5c..993000edb 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -41,12 +41,56 @@ void convertPointer(T& dest, R src) } template -void getFunc(T& func, ALCdevice *device, const char *name) +void getALCFunc(T& func, ALCdevice *device, const char *name) { void* funcPtr = alcGetProcAddress(device, name); convertPointer(func, funcPtr); } +template +void getALFunc(T& func, const char *name) +{ + void* funcPtr = alGetProcAddress(name); + convertPointer(func, funcPtr); +} + +// Effect objects +LPALGENEFFECTS alGenEffects; +LPALDELETEEFFECTS alDeleteEffects; +LPALISEFFECT alIsEffect; +LPALEFFECTI alEffecti; +LPALEFFECTIV alEffectiv; +LPALEFFECTF alEffectf; +LPALEFFECTFV alEffectfv; +LPALGETEFFECTI alGetEffecti; +LPALGETEFFECTIV alGetEffectiv; +LPALGETEFFECTF alGetEffectf; +LPALGETEFFECTFV alGetEffectfv; +// Filter objects +LPALGENFILTERS alGenFilters; +LPALDELETEFILTERS alDeleteFilters; +LPALISFILTER alIsFilter; +LPALFILTERI alFilteri; +LPALFILTERIV alFilteriv; +LPALFILTERF alFilterf; +LPALFILTERFV alFilterfv; +LPALGETFILTERI alGetFilteri; +LPALGETFILTERIV alGetFilteriv; +LPALGETFILTERF alGetFilterf; +LPALGETFILTERFV alGetFilterfv; +// Auxiliary slot objects +LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots; +LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots; +LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot; +LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti; +LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv; +LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf; +LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv; +LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti; +LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv; +LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf; +LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv; + } namespace MWSound @@ -549,6 +593,45 @@ void OpenAL_Output::init(const std::string &devname) if(mFreeSources.empty()) fail("Could not allocate any sources"); + if(alcIsExtensionPresent(mDevice, "ALC_EXT_EFX")) + { +#define LOAD_FUNC(x) getALFunc(x, #x) + LOAD_FUNC(alGenEffects); + LOAD_FUNC(alDeleteEffects); + LOAD_FUNC(alIsEffect); + LOAD_FUNC(alEffecti); + LOAD_FUNC(alEffectiv); + LOAD_FUNC(alEffectf); + LOAD_FUNC(alEffectfv); + LOAD_FUNC(alGetEffecti); + LOAD_FUNC(alGetEffectiv); + LOAD_FUNC(alGetEffectf); + LOAD_FUNC(alGetEffectfv); + LOAD_FUNC(alGenFilters); + LOAD_FUNC(alDeleteFilters); + LOAD_FUNC(alIsFilter); + LOAD_FUNC(alFilteri); + LOAD_FUNC(alFilteriv); + LOAD_FUNC(alFilterf); + LOAD_FUNC(alFilterfv); + LOAD_FUNC(alGetFilteri); + LOAD_FUNC(alGetFilteriv); + LOAD_FUNC(alGetFilterf); + LOAD_FUNC(alGetFilterfv); + LOAD_FUNC(alGenAuxiliaryEffectSlots); + LOAD_FUNC(alDeleteAuxiliaryEffectSlots); + LOAD_FUNC(alIsAuxiliaryEffectSlot); + LOAD_FUNC(alAuxiliaryEffectSloti); + LOAD_FUNC(alAuxiliaryEffectSlotiv); + LOAD_FUNC(alAuxiliaryEffectSlotf); + LOAD_FUNC(alAuxiliaryEffectSlotfv); + LOAD_FUNC(alGetAuxiliaryEffectSloti); + LOAD_FUNC(alGetAuxiliaryEffectSlotiv); + LOAD_FUNC(alGetAuxiliaryEffectSlotf); + LOAD_FUNC(alGetAuxiliaryEffectSlotfv); +#undef LOAD_FUNC + } + mInitialized = true; } @@ -582,7 +665,7 @@ std::vector OpenAL_Output::enumerateHrtf() return ret; LPALCGETSTRINGISOFT alcGetStringiSOFT = 0; - getFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT"); + getALCFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT"); ALCint num_hrtf; alcGetIntegerv(mDevice, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf); @@ -606,10 +689,10 @@ void OpenAL_Output::enableHrtf(const std::string &hrtfname, bool auto_enable) LPALCGETSTRINGISOFT alcGetStringiSOFT = 0; - getFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT"); + getALCFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT"); LPALCRESETDEVICESOFT alcResetDeviceSOFT = 0; - getFunc(alcResetDeviceSOFT, mDevice, "alcResetDeviceSOFT"); + getALCFunc(alcResetDeviceSOFT, mDevice, "alcResetDeviceSOFT"); std::vector attrs; attrs.push_back(ALC_HRTF_SOFT); @@ -660,7 +743,7 @@ void OpenAL_Output::disableHrtf() } LPALCRESETDEVICESOFT alcResetDeviceSOFT = 0; - getFunc(alcResetDeviceSOFT, mDevice, "alcResetDeviceSOFT"); + getALCFunc(alcResetDeviceSOFT, mDevice, "alcResetDeviceSOFT"); std::vector attrs; attrs.push_back(ALC_HRTF_SOFT); From c790fedd3f7e6610c61003d926cd6842a7cf09e4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 03:53:53 -0700 Subject: [PATCH 051/505] Load an effect and filter for underwater --- apps/openmw/mwsound/openal_output.cpp | 102 +++++++++++++++++++++++++- apps/openmw/mwsound/openal_output.hpp | 8 ++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 993000edb..1dd78f5ce 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -20,6 +20,8 @@ #include "soundmanagerimp.hpp" #include "loudness.hpp" +#include "efx-presets.h" + #ifndef ALC_ALL_DEVICES_SPECIFIER #define ALC_ALL_DEVICES_SPECIFIER 0x1013 #endif @@ -91,6 +93,56 @@ LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv; LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf; LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv; + +void LoadEffect(ALuint effect, const EFXEAXREVERBPROPERTIES &props) +{ + ALint type = AL_NONE; + alGetEffecti(effect, AL_EFFECT_TYPE, &type); + if(type == AL_EFFECT_EAXREVERB) + { + alEffectf(effect, AL_EAXREVERB_DIFFUSION, props.flDiffusion); + alEffectf(effect, AL_EAXREVERB_DENSITY, props.flDensity); + alEffectf(effect, AL_EAXREVERB_GAIN, props.flGain); + alEffectf(effect, AL_EAXREVERB_GAINHF, props.flGainHF); + alEffectf(effect, AL_EAXREVERB_GAINLF, props.flGainLF); + alEffectf(effect, AL_EAXREVERB_DECAY_TIME, props.flDecayTime); + alEffectf(effect, AL_EAXREVERB_DECAY_HFRATIO, props.flDecayHFRatio); + alEffectf(effect, AL_EAXREVERB_DECAY_LFRATIO, props.flDecayLFRatio); + alEffectf(effect, AL_EAXREVERB_REFLECTIONS_GAIN, props.flReflectionsGain); + alEffectf(effect, AL_EAXREVERB_REFLECTIONS_DELAY, props.flReflectionsDelay); + alEffectfv(effect, AL_EAXREVERB_REFLECTIONS_PAN, props.flReflectionsPan); + alEffectf(effect, AL_EAXREVERB_LATE_REVERB_GAIN, props.flLateReverbGain); + alEffectf(effect, AL_EAXREVERB_LATE_REVERB_DELAY, props.flLateReverbDelay); + alEffectfv(effect, AL_EAXREVERB_LATE_REVERB_PAN, props.flLateReverbPan); + alEffectf(effect, AL_EAXREVERB_ECHO_TIME, props.flEchoTime); + alEffectf(effect, AL_EAXREVERB_ECHO_DEPTH, props.flEchoDepth); + alEffectf(effect, AL_EAXREVERB_MODULATION_TIME, props.flModulationTime); + alEffectf(effect, AL_EAXREVERB_MODULATION_DEPTH, props.flModulationDepth); + alEffectf(effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, props.flAirAbsorptionGainHF); + alEffectf(effect, AL_EAXREVERB_HFREFERENCE, props.flHFReference); + alEffectf(effect, AL_EAXREVERB_LFREFERENCE, props.flLFReference); + alEffectf(effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, props.flRoomRolloffFactor); + alEffecti(effect, AL_EAXREVERB_DECAY_HFLIMIT, props.iDecayHFLimit ? AL_TRUE : AL_FALSE); + } + else if(type == AL_EFFECT_REVERB) + { + alEffectf(effect, AL_REVERB_DIFFUSION, props.flDiffusion); + alEffectf(effect, AL_REVERB_DENSITY, props.flDensity); + alEffectf(effect, AL_REVERB_GAIN, props.flGain); + alEffectf(effect, AL_REVERB_GAINHF, props.flGainHF); + alEffectf(effect, AL_REVERB_DECAY_TIME, props.flDecayTime); + alEffectf(effect, AL_REVERB_DECAY_HFRATIO, props.flDecayHFRatio); + alEffectf(effect, AL_REVERB_REFLECTIONS_GAIN, props.flReflectionsGain); + alEffectf(effect, AL_REVERB_REFLECTIONS_DELAY, props.flReflectionsDelay); + alEffectf(effect, AL_REVERB_LATE_REVERB_GAIN, props.flLateReverbGain); + alEffectf(effect, AL_REVERB_LATE_REVERB_DELAY, props.flLateReverbDelay); + alEffectf(effect, AL_REVERB_AIR_ABSORPTION_GAINHF, props.flAirAbsorptionGainHF); + alEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, props.flRoomRolloffFactor); + alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, props.iDecayHFLimit ? AL_TRUE : AL_FALSE); + } + alGetError(); +} + } namespace MWSound @@ -565,6 +617,8 @@ void OpenAL_Output::init(const std::string &devname) fail(std::string("Failed to setup context: ")+alcGetString(mDevice, alcGetError(mDevice))); } + ALC.EXT_EFX = !!alcIsExtensionPresent(mDevice, "ALC_EXT_EFX"); + alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); throwALerror(); @@ -593,7 +647,7 @@ void OpenAL_Output::init(const std::string &devname) if(mFreeSources.empty()) fail("Could not allocate any sources"); - if(alcIsExtensionPresent(mDevice, "ALC_EXT_EFX")) + if(ALC.EXT_EFX) { #define LOAD_FUNC(x) getALFunc(x, #x) LOAD_FUNC(alGenEffects); @@ -630,6 +684,41 @@ void OpenAL_Output::init(const std::string &devname) LOAD_FUNC(alGetAuxiliaryEffectSlotf); LOAD_FUNC(alGetAuxiliaryEffectSlotfv); #undef LOAD_FUNC + throwALerror(); + + alGenFilters(1, &mWaterFilter); + if(alGetError() == AL_NO_ERROR) + { + alFilteri(mWaterFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS); + if(alGetError() == AL_NO_ERROR) + { + std::cout<< "Low-pass filter supported" < IDDq; IDDq mFreeSources; @@ -34,6 +38,10 @@ namespace MWSound osg::Vec3f mListenerPos; Environment mListenerEnv; + ALuint mWaterFilter; + ALuint mWaterEffect; + ALuint mEffectSlot; + struct StreamThread; std::unique_ptr mStreamThread; From 0b720cd90c66b4f978819295abeffefe9a2c5b2b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 15:22:01 -0700 Subject: [PATCH 052/505] Set the appropriate meter/unit scale for sound --- apps/openmw/mwsound/openal_output.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 1dd78f5ce..596646a74 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -33,6 +33,10 @@ namespace { +// The game uses 64 units per yard, or approximately 69.99125109 units per meter. +// Should this be defined publically somewhere? +const float UnitsPerMeter = 69.99125109f; + const int sLoudnessFPS = 20; // loudness values per second of audio // Helper to get an OpenAL extension function @@ -719,7 +723,13 @@ void OpenAL_Output::init(const std::string &devname) } LoadEffect(mWaterEffect, EFX_REVERB_PRESET_UNDERWATER); } + + alListenerf(AL_METERS_PER_UNIT, 1.0f / UnitsPerMeter); } + // Speed of sound is in units per second. Given the default speed of sound is 343.3 (assumed + // meters per second), multiply by the units per meter to get the speed in u/s. + alSpeedOfSound(343.3f * UnitsPerMeter); + alGetError(); mInitialized = true; } @@ -1246,6 +1256,11 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi }; alListenerfv(AL_POSITION, pos.ptr()); alListenerfv(AL_ORIENTATION, orient); + if(env != mListenerEnv) + { + // Speed of sound in water is 1484m/s, and in air is 343.3m/s (roughly) + alSpeedOfSound(((env == Env_Underwater) ? 1484.0f : 343.3f) * UnitsPerMeter); + } throwALerror(); } From 033303b91164ffac09d05eb5bd2cb7b5fd63cc0c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 17:00:39 -0700 Subject: [PATCH 053/505] Properly update the near water sound volume --- apps/openmw/mwsound/soundmanagerimp.cpp | 29 ++++++++++++++----------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 67c7f77e4..9a5963308 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -931,25 +931,28 @@ namespace MWSound mOutput->finishSound(mNearWaterSound); mNearWaterSound = nullptr; } - else if(LastCell != curcell) + else { bool soundIdChanged = false; - Sound_Buffer* sfx = lookupSound(soundId); - SoundMap::const_iterator snditer = mActiveSounds.find(MWWorld::Ptr()); - if(snditer != mActiveSounds.end()) + Sound_Buffer *sfx = lookupSound(soundId); + if(LastCell != curcell) { - SoundBufferRefPairList::const_iterator pairiter = std::find_if( - snditer->second.begin(), snditer->second.end(), - [this](const SoundBufferRefPairList::value_type &item) -> bool - { return mNearWaterSound == item.first; } - ); - if (pairiter != snditer->second.end() && pairiter->second != sfx) - soundIdChanged = true; + LastCell = curcell; + SoundMap::const_iterator snditer = mActiveSounds.find(MWWorld::Ptr()); + if(snditer != mActiveSounds.end()) + { + SoundBufferRefPairList::const_iterator pairiter = std::find_if( + snditer->second.begin(), snditer->second.end(), + [this](const SoundBufferRefPairList::value_type &item) -> bool + { return mNearWaterSound == item.first; } + ); + if (pairiter != snditer->second.end() && pairiter->second != sfx) + soundIdChanged = true; + } } - LastCell = curcell; - if (soundIdChanged) + if(soundIdChanged) { mOutput->finishSound(mNearWaterSound); mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop); From ec01b89e59edc34de7b9c9eaba8ce2a46b96535d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 17:17:02 -0700 Subject: [PATCH 054/505] Increase the default buffer cache sizes --- files/settings-default.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index a0460326b..aec667a9c 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -313,11 +313,11 @@ voice volume = 0.8 # Minimum size to use for the sound buffer cache, in MB. When the cache is # filled, old buffers will be unloaded until it's using no more than this much # memory. Must be less than or equal to 'buffer cache max'. -buffer cache min = 14 +buffer cache min = 56 # Maximum size to use for the sound buffer cache, in MB. The cache can use up # to this much memory until old buffers get purged. -buffer cache max = 16 +buffer cache max = 64 # Specifies whether to enable HRTF processing. Valid values are: -1 = auto, # 0 = off, 1 = on. From 27eeaf90d0c5b5c43b92928d7f8103046bf04dbe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 19:03:17 -0700 Subject: [PATCH 055/505] Use unordered_map for the music playlist and sound buffer caches --- apps/openmw/mwsound/soundmanagerimp.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 836c3f228..e5889e36d 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -50,7 +50,7 @@ namespace MWSound std::unique_ptr mOutput; // Caches available music tracks by - std::map > mMusicFiles; + std::unordered_map> mMusicFiles; std::unordered_map> mMusicToPlay; // A list with music files not yet played std::string mLastPlayedMusic; // The music file that was last played @@ -75,7 +75,7 @@ namespace MWSound size_t mBufferCacheMax; size_t mBufferCacheSize; - typedef std::map NameBufferMap; + typedef std::unordered_map NameBufferMap; NameBufferMap mBufferNameMap; // NOTE: unused buffers are stored in front-newest order. From edfba68eb583948db714d2144be261a8800f65f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 20:20:23 -0700 Subject: [PATCH 056/505] Apply reverb and a low-pass filter when underwater This replaces the pitch-shift effect when available. --- apps/openmw/mwsound/openal_output.cpp | 104 +++++++++++++++++++++++--- apps/openmw/mwsound/openal_output.hpp | 1 + 2 files changed, 93 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 596646a74..1b6b435f2 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -698,7 +698,7 @@ void OpenAL_Output::init(const std::string &devname) { std::cout<< "Low-pass filter supported" < maxdist*maxdist) gain = 0.0f; - if(useenv && mListenerEnv == Env_Underwater) + if(useenv) { - gain *= 0.9f; - pitch *= 0.7f; + if(mWaterFilter) + alSourcei(source, AL_DIRECT_FILTER, + (mListenerEnv == Env_Underwater) ? mWaterFilter : AL_FILTER_NULL + ); + else if(mListenerEnv == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + if(mEffectSlot) + alSource3i(source, AL_AUXILIARY_SEND_FILTER, mEffectSlot, 0, AL_FILTER_NULL); + } + else + { + if(mWaterFilter) + alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); + if(mEffectSlot) + alSource3i(source, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL); } alSourcef(source, AL_GAIN, gain); @@ -997,7 +1048,7 @@ void OpenAL_Output::updateCommon(ALuint source, const osg::Vec3f& pos, ALfloat m if((pos - mListenerPos).length2() > maxdist*maxdist) gain = 0.0f; } - if(useenv && mListenerEnv == Env_Underwater) + if(useenv && mListenerEnv == Env_Underwater && !mWaterFilter) { gain *= 0.9f; pitch *= 0.7f; @@ -1256,10 +1307,39 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi }; alListenerfv(AL_POSITION, pos.ptr()); alListenerfv(AL_ORIENTATION, orient); + if(env != mListenerEnv) { // Speed of sound in water is 1484m/s, and in air is 343.3m/s (roughly) alSpeedOfSound(((env == Env_Underwater) ? 1484.0f : 343.3f) * UnitsPerMeter); + + // Update active sources with the environment's direct filter + if(mWaterFilter) + { + ALuint filter = (env == Env_Underwater) ? mWaterFilter : AL_FILTER_NULL; + std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(), + [filter](const SoundVec::value_type &item) -> void + { + if(item->getUseEnv()) + alSourcei(GET_PTRID(item->mHandle), AL_DIRECT_FILTER, filter); + } + ); + std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(), + [filter](const StreamVec::value_type &item) -> void + { + if(item->getUseEnv()) + alSourcei( + reinterpret_cast(item->mHandle)->mSource, + AL_DIRECT_FILTER, filter + ); + } + ); + } + // Update the environment effect + if(mEffectSlot) + alAuxiliaryEffectSloti(mEffectSlot, AL_EFFECTSLOT_EFFECT, + (env == Env_Underwater) ? mWaterEffect : mDefaultEffect + ); } throwALerror(); } @@ -1323,7 +1403,7 @@ void OpenAL_Output::resumeSounds(int types) OpenAL_Output::OpenAL_Output(SoundManager &mgr) : Sound_Output(mgr), mDevice(0), mContext(0) , mListenerPos(0.0f, 0.0f, 0.0f), mListenerEnv(Env_Normal) - , mWaterFilter(0), mWaterEffect(0), mEffectSlot(0) + , mWaterFilter(0), mWaterEffect(0), mDefaultEffect(0), mEffectSlot(0) , mStreamThread(new StreamThread) { } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index d92f99a84..fb832abc6 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -40,6 +40,7 @@ namespace MWSound ALuint mWaterFilter; ALuint mWaterEffect; + ALuint mDefaultEffect; ALuint mEffectSlot; struct StreamThread; From 6f57233ba167e757fd5057066556aa175410288d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 13 Sep 2017 02:47:26 -0700 Subject: [PATCH 057/505] Avoid copying the same Ptr with each iteration --- apps/openmw/mwsound/soundmanagerimp.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 9a5963308..36617f3b2 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -1005,11 +1005,14 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { + MWWorld::ConstPtr ptr = snditer->first; SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); while(sndidx != snditer->second.end()) { - MWWorld::ConstPtr ptr = snditer->first; - Sound *sound = sndidx->first; + Sound *sound; + Sound_Buffer *sfx; + + std::tie(sound, sfx) = *sndidx; if(!ptr.isEmpty() && sound->getIs3D()) { const ESM::Position &pos = ptr.getRefData().getPosition(); @@ -1031,7 +1034,6 @@ namespace MWSound mUnderwaterSound = nullptr; if(sound == mNearWaterSound) mNearWaterSound = nullptr; - Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sfx); sndidx = snditer->second.erase(sndidx); @@ -1045,7 +1047,7 @@ namespace MWSound } } if(snditer->second.empty()) - mActiveSounds.erase(snditer++); + snditer = mActiveSounds.erase(snditer); else ++snditer; } From 605c937572883913cf51fb52a6846dade8074d6c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 13 Sep 2017 03:27:48 -0700 Subject: [PATCH 058/505] Ensure 3D sources are spatialized Standard OpenAL does not spatialize non-mono sounds, although the game has some stereo sounds meant to play in 3D. The desired behavior can be achieved with the AL_SOFT_source_spatialize extension. --- apps/openmw/mwsound/openal_output.cpp | 5 +++++ apps/openmw/mwsound/openal_output.hpp | 3 +++ 2 files changed, 8 insertions(+) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 1b6b435f2..146776442 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -622,6 +622,7 @@ void OpenAL_Output::init(const std::string &devname) } ALC.EXT_EFX = !!alcIsExtensionPresent(mDevice, "ALC_EXT_EFX"); + AL.SOFT_source_spatialize = !!alIsExtensionPresent("AL_SOFT_source_spatialize"); alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); throwALerror(); @@ -972,6 +973,8 @@ void OpenAL_Output::initCommon2D(ALuint source, const osg::Vec3f &pos, ALfloat g alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); alSourcei(source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE); + if(AL.SOFT_source_spatialize) + alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT, AL_FALSE); if(useenv) { @@ -1009,6 +1012,8 @@ void OpenAL_Output::initCommon3D(ALuint source, const osg::Vec3f &pos, ALfloat m alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); alSourcei(source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE); + if(AL.SOFT_source_spatialize) + alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT, AL_TRUE); if((pos - mListenerPos).length2() > maxdist*maxdist) gain = 0.0f; diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index fb832abc6..777b9207f 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -26,6 +26,9 @@ namespace MWSound struct { int EXT_EFX : 1; } ALC; + struct { + int SOFT_source_spatialize : 1; + } AL; typedef std::deque IDDq; IDDq mFreeSources; From abe80f58683b604f98e49f7386bb451dc4e4400b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 13 Sep 2017 20:47:20 -0700 Subject: [PATCH 059/505] Move the soundlist when updating a Ptr instead of copying --- apps/openmw/mwsound/soundmanagerimp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 36617f3b2..25af9add8 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -1203,16 +1203,16 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(old); if(snditer != mActiveSounds.end()) { - SoundBufferRefPairList sndlist = snditer->second; + SoundBufferRefPairList sndlist = std::move(snditer->second); mActiveSounds.erase(snditer); - mActiveSounds[updated] = sndlist; + mActiveSounds.emplace(updated, std::move(sndlist)); } SaySoundMap::iterator sayiter = mActiveSaySounds.find(old); if(sayiter != mActiveSaySounds.end()) { Stream *stream = sayiter->second; mActiveSaySounds.erase(sayiter); - mActiveSaySounds[updated] = stream; + mActiveSaySounds.emplace(updated, stream); } } From c17edfd547b57efe458a8100c2709cf05c434081 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Sep 2017 03:41:11 -0700 Subject: [PATCH 060/505] Don't be so throw-happy in the sound manager --- apps/openmw/mwsound/openal_output.cpp | 389 ++++++++++++------------ apps/openmw/mwsound/openal_output.hpp | 10 +- apps/openmw/mwsound/sound_output.hpp | 10 +- apps/openmw/mwsound/soundmanagerimp.cpp | 323 +++++++++----------- 4 files changed, 364 insertions(+), 368 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 146776442..a6258babe 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -39,6 +39,26 @@ const float UnitsPerMeter = 69.99125109f; const int sLoudnessFPS = 20; // loudness values per second of audio +ALCenum checkALCError(ALCdevice *device, const char *func, int line) +{ + ALCenum err = alcGetError(device); + if(err != ALC_NO_ERROR) + std::cerr<< ">>>>>>>>> ALC error "<>>>>>>>> AL error "< void convertPointer(T& dest, R src) @@ -144,7 +164,7 @@ void LoadEffect(ALuint effect, const EFXEAXREVERBPROPERTIES &props) alEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, props.flRoomRolloffFactor); alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, props.iDecayHFLimit ? AL_TRUE : AL_FALSE); } - alGetError(); + getALError(); } } @@ -152,30 +172,6 @@ void LoadEffect(ALuint effect, const EFXEAXREVERBPROPERTIES &props) namespace MWSound { -static void fail(const std::string &msg) -{ throw std::runtime_error("OpenAL exception: " + msg); } - -static void throwALCerror(ALCdevice *device) -{ - ALCenum err = alcGetError(device); - if(err != ALC_NO_ERROR) - { - const ALCchar *errstring = alcGetString(device, err); - fail(errstring ? errstring : ""); - } -} - -static void throwALerror() -{ - ALenum err = alGetError(); - if(err != AL_NO_ERROR) - { - const ALchar *errstring = alGetString(err); - fail(errstring ? errstring : ""); - } -} - - static ALenum getALFormat(ChannelConfig chans, SampleType type) { static const struct { @@ -268,7 +264,8 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) } } - fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")"); + std::cerr<< "Unsupported sound format ("<getInfo(&srate, &chans, &type); - mFormat = getALFormat(chans, type); - mSampleRate = srate; +OpenAL_SoundStream::~OpenAL_SoundStream() +{ + if(mBuffers[0] && alIsBuffer(mBuffers[0])) + alDeleteBuffers(sNumBuffers, mBuffers); + alGetError(); - switch(type) - { - case SampleType_UInt8: mSilence = 0x80; break; - case SampleType_Int16: mSilence = 0x00; break; - case SampleType_Float32: mSilence = 0x00; break; - } + mDecoder->close(); +} + +bool OpenAL_SoundStream::init(bool getLoudnessData) +{ + alGenBuffers(sNumBuffers, mBuffers); + ALenum err = getALError(); + if(err != AL_NO_ERROR) + return false; - mFrameSize = framesToBytes(1, chans, type); - mBufferSize = static_cast(sBufferLength*srate); - mBufferSize *= mFrameSize; + ChannelConfig chans; + SampleType type; - if (getLoudnessData) - mLoudnessAnalyzer.reset(new Sound_Loudness(sLoudnessFPS, mSampleRate, chans, type)); - } - catch(std::exception&) + mDecoder->getInfo(&mSampleRate, &chans, &type); + mFormat = getALFormat(chans, type); + if(!mFormat) return false; + + switch(type) { - alDeleteBuffers(sNumBuffers, mBuffers); - alGetError(); - throw; + case SampleType_UInt8: mSilence = 0x80; break; + case SampleType_Int16: mSilence = 0x00; break; + case SampleType_Float32: mSilence = 0x00; break; } - mIsFinished = false; -} -OpenAL_SoundStream::~OpenAL_SoundStream() -{ - alDeleteBuffers(sNumBuffers, mBuffers); - alGetError(); - mDecoder->close(); + mFrameSize = framesToBytes(1, chans, type); + mBufferSize = static_cast(sBufferLength*mSampleRate); + mBufferSize *= mFrameSize; + + if (getLoudnessData) + mLoudnessAnalyzer.reset(new Sound_Loudness(sLoudnessFPS, mSampleRate, chans, type)); + + mIsFinished = false; + return true; } bool OpenAL_SoundStream::isPlaying() @@ -444,7 +446,7 @@ bool OpenAL_SoundStream::isPlaying() ALint state; alGetSourcei(mSource, AL_SOURCE_STATE, &state); - throwALerror(); + getALError(); if(state == AL_PLAYING || state == AL_PAUSED) return true; @@ -467,7 +469,7 @@ double OpenAL_SoundStream::getStreamDelay() const d = (double)inqueue / (double)mSampleRate; } - throwALerror(); + getALError(); return d; } @@ -493,7 +495,7 @@ double OpenAL_SoundStream::getStreamOffset() const t = (double)mDecoder->getSampleOffset() / (double)mSampleRate; } - throwALerror(); + getALError(); return t; } @@ -590,7 +592,7 @@ std::vector OpenAL_Output::enumerate() return devlist; } -void OpenAL_Output::init(const std::string &devname) +bool OpenAL_Output::init(const std::string &devname) { deinit(); @@ -598,9 +600,10 @@ void OpenAL_Output::init(const std::string &devname) if(!mDevice) { if(devname.empty()) - fail("Failed to open default device"); + std::cerr<< "Failed to open default audio device" <(maxmono+maxstereo, 256); + maxtotal = std::min(maxmono+maxstereo, 256); if (maxtotal == 0) // workaround for broken implementations maxtotal = 256; - for(size_t i = 0;i < maxtotal;i++) - { - ALuint src = 0; - alGenSources(1, &src); - throwALerror(); - mFreeSources.push_back(src); - } } - catch(std::exception &e) + for(size_t i = 0;i < maxtotal;i++) { - std::cout <<"Error: "< OpenAL_Output::enumerateHrtf() { - if(!mDevice) - fail("Device not initialized"); - std::vector ret; - if(!alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF")) + + if(!mDevice || !alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF")) return ret; LPALCGETSTRINGISOFT alcGetStringiSOFT = 0; @@ -816,7 +831,6 @@ void OpenAL_Output::enableHrtf(const std::string &hrtfname, bool auto_enable) return; } - LPALCGETSTRINGISOFT alcGetStringiSOFT = 0; getALCFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT"); @@ -891,7 +905,7 @@ void OpenAL_Output::disableHrtf() Sound_Handle OpenAL_Output::loadSound(const std::string &fname) { - throwALerror(); + getALError(); DecoderPtr decoder = mManager.getDecoder(); // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. @@ -914,20 +928,20 @@ Sound_Handle OpenAL_Output::loadSound(const std::string &fname) decoder->getInfo(&srate, &chans, &type); format = getALFormat(chans, type); + if(!format) return nullptr; decoder->readAll(data); decoder->close(); ALuint buf = 0; - try { - alGenBuffers(1, &buf); - alBufferData(buf, format, &data[0], data.size(), srate); - throwALerror(); - } - catch(...) { + alGenBuffers(1, &buf); + alBufferData(buf, format, &data[0], data.size(), srate); + if(getALError() != AL_NO_ERROR) + { if(buf && alIsBuffer(buf)) alDeleteBuffers(1, &buf); - throw; + getALError(); + return nullptr; } return MAKE_PTRID(buf); } @@ -952,6 +966,7 @@ void OpenAL_Output::unloadSound(Sound_Handle data) } } alDeleteBuffers(1, &buffer); + getALError(); } size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const @@ -960,7 +975,7 @@ size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const ALint size = 0; alGetBufferi(buffer, AL_SIZE, &size); - throwALerror(); + getALError(); return (ALuint)size; } @@ -1067,65 +1082,63 @@ void OpenAL_Output::updateCommon(ALuint source, const osg::Vec3f& pos, ALfloat m } -void OpenAL_Output::playSound(Sound *sound, Sound_Handle data, float offset) +bool OpenAL_Output::playSound(Sound *sound, Sound_Handle data, float offset) { ALuint source; if(mFreeSources.empty()) - fail("No free sources"); + { + std::cerr<< "No free sources!" <getPosition(), sound->getRealVolume(), sound->getPitch(), - sound->getIsLooping(), sound->getUseEnv()); - - alSourcef(source, AL_SEC_OFFSET, offset); - throwALerror(); - alSourcei(source, AL_BUFFER, GET_PTRID(data)); - alSourcePlay(source); - throwALerror(); + initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(), + sound->getIsLooping(), sound->getUseEnv()); + alSourcef(source, AL_SEC_OFFSET, offset); + if(getALError() != AL_NO_ERROR) + return false; - mActiveSounds.push_back(sound); - } - catch(std::exception&) { - mFreeSources.push_back(source); - throw; - } + alSourcei(source, AL_BUFFER, GET_PTRID(data)); + alSourcePlay(source); + if(getALError() != AL_NO_ERROR) + return false; + mFreeSources.pop_front(); sound->mHandle = MAKE_PTRID(source); + mActiveSounds.push_back(sound); + + return true; } -void OpenAL_Output::playSound3D(Sound *sound, Sound_Handle data, float offset) +bool OpenAL_Output::playSound3D(Sound *sound, Sound_Handle data, float offset) { ALuint source; if(mFreeSources.empty()) - fail("No free sources"); + { + std::cerr<< "No free sources!" <getPosition(), sound->getMinDistance(), sound->getMaxDistance(), - sound->getRealVolume(), sound->getPitch(), sound->getIsLooping(), - sound->getUseEnv()); - - alSourcef(source, AL_SEC_OFFSET, offset); - throwALerror(); + initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(), + sound->getRealVolume(), sound->getPitch(), sound->getIsLooping(), + sound->getUseEnv()); + alSourcef(source, AL_SEC_OFFSET, offset); + if(getALError() != AL_NO_ERROR) + return false; - alSourcei(source, AL_BUFFER, GET_PTRID(data)); - alSourcePlay(source); - throwALerror(); - - mActiveSounds.push_back(sound); - } - catch(std::exception&) { - mFreeSources.push_back(source); - throw; - } + alSourcei(source, AL_BUFFER, GET_PTRID(data)); + alSourcePlay(source); + if(getALError() != AL_NO_ERROR) + return false; + mFreeSources.pop_front(); sound->mHandle = MAKE_PTRID(source); + mActiveSounds.push_back(sound); + + return true; } void OpenAL_Output::finishSound(Sound *sound) @@ -1139,6 +1152,7 @@ void OpenAL_Output::finishSound(Sound *sound) // the initial queue already played when it hasn't. alSourceRewind(source); alSourcei(source, AL_BUFFER, 0); + getALError(); mFreeSources.push_back(source); mActiveSounds.erase(std::find(mActiveSounds.begin(), mActiveSounds.end(), sound)); @@ -1148,10 +1162,10 @@ bool OpenAL_Output::isSoundPlaying(Sound *sound) { if(!sound->mHandle) return false; ALuint source = GET_PTRID(sound->mHandle); - ALint state; + ALint state = AL_STOPPED; alGetSourcei(source, AL_SOURCE_STATE, &state); - throwALerror(); + getALError(); return state == AL_PLAYING || state == AL_PAUSED; } @@ -1163,69 +1177,68 @@ void OpenAL_Output::updateSound(Sound *sound) updateCommon(source, sound->getPosition(), sound->getMaxDistance(), sound->getRealVolume(), sound->getPitch(), sound->getUseEnv(), sound->getIs3D()); + getALError(); } -void OpenAL_Output::streamSound(DecoderPtr decoder, Stream *sound) +bool OpenAL_Output::streamSound(DecoderPtr decoder, Stream *sound) { - OpenAL_SoundStream *stream = 0; - ALuint source; - if(mFreeSources.empty()) - fail("No free sources"); - source = mFreeSources.front(); - mFreeSources.pop_front(); + { + std::cerr<< "No free sources!" <getIsLooping()) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; - try { - initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(), - false, sound->getUseEnv()); - throwALerror(); + initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(), + false, sound->getUseEnv()); + if(getALError() != AL_NO_ERROR) + return false; - stream = new OpenAL_SoundStream(source, decoder); - mStreamThread->add(stream); - mActiveStreams.push_back(sound); - } - catch(std::exception&) { - mStreamThread->remove(stream); + OpenAL_SoundStream *stream = new OpenAL_SoundStream(source, std::move(decoder)); + if(!stream->init()) + { delete stream; - mFreeSources.push_back(source); - throw; + return false; } + mStreamThread->add(stream); + mFreeSources.pop_front(); sound->mHandle = stream; + mActiveStreams.push_back(sound); + return true; } -void OpenAL_Output::streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData) +bool OpenAL_Output::streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData) { - OpenAL_SoundStream *stream = 0; - ALuint source; - if(mFreeSources.empty()) - fail("No free sources"); - source = mFreeSources.front(); - mFreeSources.pop_front(); + { + std::cerr<< "No free sources!" <getIsLooping()) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; - try { - initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(), - sound->getRealVolume(), sound->getPitch(), false, sound->getUseEnv()); - throwALerror(); + initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(), + sound->getRealVolume(), sound->getPitch(), false, sound->getUseEnv()); + if(getALError() != AL_NO_ERROR) + return false; - stream = new OpenAL_SoundStream(source, decoder, getLoudnessData); - mStreamThread->add(stream); - mActiveStreams.push_back(sound); - } - catch(std::exception&) { - mStreamThread->remove(stream); + OpenAL_SoundStream *stream = new OpenAL_SoundStream(source, std::move(decoder)); + if(!stream->init(getLoudnessData)) + { delete stream; - mFreeSources.push_back(source); - throw; + return false; } + mStreamThread->add(stream); + mFreeSources.pop_front(); sound->mHandle = stream; + mActiveStreams.push_back(sound); + return true; } void OpenAL_Output::finishStream(Stream *sound) @@ -1242,6 +1255,7 @@ void OpenAL_Output::finishStream(Stream *sound) // the initial queue already played when it hasn't. alSourceRewind(source); alSourcei(source, AL_BUFFER, 0); + getALError(); mFreeSources.push_back(source); mActiveStreams.erase(std::find(mActiveStreams.begin(), mActiveStreams.end(), sound)); @@ -1288,6 +1302,7 @@ void OpenAL_Output::updateStream(Stream *sound) updateCommon(source, sound->getPosition(), sound->getMaxDistance(), sound->getRealVolume(), sound->getPitch(), sound->getUseEnv(), sound->getIs3D()); + getALError(); } @@ -1346,7 +1361,7 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi (env == Env_Underwater) ? mWaterEffect : mDefaultEffect ); } - throwALerror(); + getALError(); } mListenerPos = pos; @@ -1374,8 +1389,8 @@ void OpenAL_Output::pauseSounds(int types) } if(!sources.empty()) { - alSourcePausev(sources.size(), &sources[0]); - throwALerror(); + alSourcePausev(sources.size(), sources.data()); + getALError(); } } @@ -1399,8 +1414,8 @@ void OpenAL_Output::resumeSounds(int types) } if(!sources.empty()) { - alSourcePlayv(sources.size(), &sources[0]); - throwALerror(); + alSourcePlayv(sources.size(), sources.data()); + getALError(); } } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 777b9207f..05f9c5090 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -59,7 +59,7 @@ namespace MWSound public: virtual std::vector enumerate(); - virtual void init(const std::string &devname=std::string()); + virtual bool init(const std::string &devname=std::string()); virtual void deinit(); virtual std::vector enumerateHrtf(); @@ -70,14 +70,14 @@ namespace MWSound virtual void unloadSound(Sound_Handle data); virtual size_t getSoundDataSize(Sound_Handle data) const; - virtual void playSound(Sound *sound, Sound_Handle data, float offset); - virtual void playSound3D(Sound *sound, Sound_Handle data, float offset); + virtual bool playSound(Sound *sound, Sound_Handle data, float offset); + virtual bool playSound3D(Sound *sound, Sound_Handle data, float offset); virtual void finishSound(Sound *sound); virtual bool isSoundPlaying(Sound *sound); virtual void updateSound(Sound *sound); - virtual void streamSound(DecoderPtr decoder, Stream *sound); - virtual void streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData); + virtual bool streamSound(DecoderPtr decoder, Stream *sound); + virtual bool streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData); virtual void finishStream(Stream *sound); virtual double getStreamDelay(Stream *sound); virtual double getStreamOffset(Stream *sound); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 907a601b5..01dc8b5b9 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -24,7 +24,7 @@ namespace MWSound SoundManager &mManager; virtual std::vector enumerate() = 0; - virtual void init(const std::string &devname=std::string()) = 0; + virtual bool init(const std::string &devname=std::string()) = 0; virtual void deinit() = 0; virtual std::vector enumerateHrtf() = 0; @@ -35,14 +35,14 @@ namespace MWSound virtual void unloadSound(Sound_Handle data) = 0; virtual size_t getSoundDataSize(Sound_Handle data) const = 0; - virtual void playSound(Sound *sound, Sound_Handle data, float offset) = 0; - virtual void playSound3D(Sound *sound, Sound_Handle data, float offset) = 0; + virtual bool playSound(Sound *sound, Sound_Handle data, float offset) = 0; + virtual bool playSound3D(Sound *sound, Sound_Handle data, float offset) = 0; virtual void finishSound(Sound *sound) = 0; virtual bool isSoundPlaying(Sound *sound) = 0; virtual void updateSound(Sound *sound) = 0; - virtual void streamSound(DecoderPtr decoder, Stream *sound) = 0; - virtual void streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData) = 0; + virtual bool streamSound(DecoderPtr decoder, Stream *sound) = 0; + virtual bool streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData) = 0; virtual void finishStream(Stream *sound) = 0; virtual double getStreamDelay(Stream *sound) = 0; virtual double getStreamOffset(Stream *sound) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 25af9add8..51ce67096 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -89,40 +89,42 @@ namespace MWSound std::cout << "Sound output: " << SOUND_OUT << std::endl; std::cout << "Sound decoder: " << SOUND_IN << std::endl; - try { - std::vector names = mOutput->enumerate(); - std::cout <<"Enumerated output devices:"<< std::endl; - for(size_t i = 0;i < names.size();i++) - std::cout <<" "<init(devname); - } - catch(std::exception &e) { - if(devname.empty()) - throw; - std::cerr <<"Failed to open device \""<init(); - Settings::Manager::setString("device", "Sound", ""); - } - - names = mOutput->enumerateHrtf(); - if(!names.empty()) - { - std::cout <<"Enumerated HRTF names:"<< std::endl; - for(size_t i = 0;i < names.size();i++) - std::cout <<" "< names = mOutput->enumerate(); + std::cout <<"Enumerated output devices:\n"; + std::for_each(names.cbegin(), names.cend(), + [](const std::string &name) -> void + { std::cout <<" "<disableHrtf(); - else if(!hrtfname.empty()) - mOutput->enableHrtf(hrtfname, hrtfstate<0); + std::string devname = Settings::Manager::getString("device", "Sound"); + bool inited = mOutput->init(devname); + if(!inited && !devname.empty()) + { + std::cerr<< "Failed to initialize device \""<init(); } - catch(std::exception &e) { - std::cout <<"Sound init failed: "<enumerateHrtf(); + if(!names.empty()) + { + std::cout<< "Enumerated HRTF names:\n"; + std::for_each(names.cbegin(), names.cend(), + [](const std::string &name) -> void + { std::cout<< " "<disableHrtf(); + else if(!hrtfname.empty()) + mOutput->enableHrtf(hrtfname, hrtfstate<0); } SoundManager::~SoundManager() @@ -186,8 +188,12 @@ namespace MWSound Sound_Buffer *SoundManager::lookupSound(const std::string &soundId) const { NameBufferMap::const_iterator snd = mBufferNameMap.find(soundId); - if(snd != mBufferNameMap.end()) return snd->second; - return 0; + if(snd != mBufferNameMap.end()) + { + Sound_Buffer *sfx = snd->second; + if(sfx->mHandle) return sfx; + } + return nullptr; } // Lookup a soundId for its sound data (resource name, local volume, @@ -201,15 +207,17 @@ namespace MWSound else { MWBase::World *world = MWBase::Environment::get().getWorld(); - const ESM::Sound *sound = world->getStore().get().find(soundId); + const ESM::Sound *sound = world->getStore().get().search(soundId); + if(!sound) return nullptr; sfx = insertSound(soundId, sound); } if(!sfx->mHandle) { sfx->mHandle = mOutput->loadSound(sfx->mResourceName); - mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle); + if(!sfx->mHandle) return nullptr; + mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle); if(mBufferCacheSize > mBufferCacheMax) { do { @@ -293,18 +301,24 @@ namespace MWSound static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f); static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); + bool played; float basevol = volumeFromType(Play_TypeVoice); Stream *sound = getStreamRef(); if(playlocal) { sound->init(1.0f, basevol, 1.0f, Play_NoEnv|Play_TypeVoice|Play_2D); - mOutput->streamSound(decoder, sound); + played = mOutput->streamSound(decoder, sound); } else { sound->init(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance, Play_Normal|Play_TypeVoice|Play_3D); - mOutput->streamSound3D(decoder, sound, true); + played = mOutput->streamSound3D(decoder, sound, true); + } + if(!played) + { + mUnusedStreams.push_back(sound); + return nullptr; } return sound; } @@ -351,23 +365,16 @@ namespace MWSound return; std::cout <<"Playing "<open(filename); + stopMusic(); - mMusic = getStreamRef(); - mMusic->init(1.0f, volumeFromType(Play_TypeMusic), 1.0f, - Play_NoEnv|Play_TypeMusic|Play_2D); - mOutput->streamSound(decoder, mMusic); - } - catch(std::exception &e) { - std::cout << "Music Error: " << e.what() << "\n"; - if(mMusic) - mUnusedStreams.push_back(mMusic); - mMusic = nullptr; - } + DecoderPtr decoder = getDecoder(); + decoder->open(filename); + + mMusic = getStreamRef(); + mMusic->init(1.0f, volumeFromType(Play_TypeMusic), 1.0f, + Play_NoEnv|Play_TypeMusic|Play_2D); + mOutput->streamSound(decoder, mMusic); } void SoundManager::advanceMusic(const std::string& filename) @@ -454,24 +461,20 @@ namespace MWSound { if(!mOutput->isInitialized()) return; - try - { - std::string voicefile = "Sound/"+filename; - mVFS->normalizeFilename(voicefile); - DecoderPtr decoder = loadVoice(voicefile); + std::string voicefile = "Sound/"+filename; - MWBase::World *world = MWBase::Environment::get().getWorld(); - const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); + mVFS->normalizeFilename(voicefile); + DecoderPtr decoder = loadVoice(voicefile); - stopSay(ptr); - Stream *sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); - mActiveSaySounds.insert(std::make_pair(ptr, sound)); - } - catch(std::exception &e) - { - std::cout <<"Sound Error: "<getActorHeadTransform(ptr).getTrans(); + + stopSay(ptr); + Stream *sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); + if(!sound) return; + + mActiveSaySounds.insert(std::make_pair(ptr, sound)); } float SoundManager::getSaySoundLoudness(const MWWorld::ConstPtr &ptr) const @@ -490,21 +493,17 @@ namespace MWSound { if(!mOutput->isInitialized()) return; - try - { - std::string voicefile = "Sound/"+filename; - mVFS->normalizeFilename(voicefile); - DecoderPtr decoder = loadVoice(voicefile); + std::string voicefile = "Sound/"+filename; - stopSay(MWWorld::ConstPtr()); - mActiveSaySounds.insert(std::make_pair(MWWorld::ConstPtr(), - playVoice(decoder, osg::Vec3f(), true))); - } - catch(std::exception &e) - { - std::cout <<"Sound Error: "<normalizeFilename(voicefile); + DecoderPtr decoder = loadVoice(voicefile); + + stopSay(MWWorld::ConstPtr()); + Stream *sound = playVoice(decoder, osg::Vec3f(), true); + if(!sound) return; + + mActiveSaySounds.insert(std::make_pair(MWWorld::ConstPtr(), sound)); } bool SoundManager::sayDone(const MWWorld::ConstPtr &ptr) const @@ -535,22 +534,18 @@ namespace MWSound { if(!mOutput->isInitialized()) return nullptr; - Stream *track = getStreamRef(); - try - { - track->init(1.0f, volumeFromType(type), 1.0f, Play_NoEnv|type|Play_2D); - mOutput->streamSound(decoder, track); - TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), track); - mActiveTracks.insert(iter, track); - } - catch(std::exception &e) + Stream *track = getStreamRef(); + track->init(1.0f, volumeFromType(type), 1.0f, Play_NoEnv|type|Play_2D); + if(!mOutput->streamSound(decoder, track)) { - std::cout <<"Sound Error: "<isInitialized()) return nullptr; - Sound *sound = nullptr; - try - { - Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); - float basevol = volumeFromType(type); - sound = getSoundRef(); - sound->init(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D); - mOutput->playSound(sound, sfx->mHandle, offset); - if(sfx->mUses++ == 0) - { - SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); - if(iter != mUnusedBuffers.end()) - mUnusedBuffers.erase(iter); - } - mActiveSounds[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx)); + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); + if(!sfx) return nullptr; + + Sound *sound = getSoundRef(); + sound->init(volume * sfx->mVolume, volumeFromType(type), pitch, mode|type|Play_2D); + if(!mOutput->playSound(sound, sfx->mHandle, offset)) + { + mUnusedSounds.push_back(sound); + return nullptr; } - catch(std::exception&) + + if(sfx->mUses++ == 0) { - //std::cout <<"Sound Error: "<isInitialized()) return nullptr; - Sound *sound = nullptr; - try - { - // Look up the sound in the ESM data - Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); - float basevol = volumeFromType(type); - const ESM::Position &pos = ptr.getRefData().getPosition(); - const osg::Vec3f objpos(pos.asVec3()); - if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) - return nullptr; + // Look up the sound in the ESM data + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); + if(!sfx) return nullptr; - // Only one copy of given sound can be played at time on ptr, so stop previous copy - stopSound3D(ptr, soundId); + const osg::Vec3f objpos(ptr.getRefData().getPosition().asVec3()); + if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) + return nullptr; - sound = getSoundRef(); - if(!(mode&Play_NoPlayerLocal) && ptr == MWMechanics::getPlayer()) - { - sound->init(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D); - mOutput->playSound(sound, sfx->mHandle, offset); - } - else - { - sound->init(objpos, volume * sfx->mVolume, basevol, pitch, - sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D); - mOutput->playSound3D(sound, sfx->mHandle, offset); - } - if(sfx->mUses++ == 0) - { - SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); - if(iter != mUnusedBuffers.end()) - mUnusedBuffers.erase(iter); - } - mActiveSounds[ptr].push_back(std::make_pair(sound, sfx)); + // Only one copy of given sound can be played at time on ptr, so stop previous copy + stopSound3D(ptr, soundId); + + bool played; + Sound *sound = getSoundRef(); + if(!(mode&Play_NoPlayerLocal) && ptr == MWMechanics::getPlayer()) + { + sound->init(volume * sfx->mVolume, volumeFromType(type), pitch, mode|type|Play_2D); + played = mOutput->playSound(sound, sfx->mHandle, offset); } - catch(std::exception&) + else { - //std::cout <<"Sound Error: "<init(objpos, volume * sfx->mVolume, volumeFromType(type), pitch, + sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D); + played = mOutput->playSound3D(sound, sfx->mHandle, offset); } + if(!played) + { + mUnusedSounds.push_back(sound); + return nullptr; + } + + if(sfx->mUses++ == 0) + { + SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); + if(iter != mUnusedBuffers.end()) + mUnusedBuffers.erase(iter); + } + mActiveSounds[ptr].push_back(std::make_pair(sound, sfx)); return sound; } @@ -657,32 +643,27 @@ namespace MWSound { if(!mOutput->isInitialized()) return nullptr; - Sound *sound = nullptr; - try - { - // Look up the sound in the ESM data - Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); - float basevol = volumeFromType(type); - sound = getSoundRef(); - sound->init(initialPos, volume * sfx->mVolume, basevol, pitch, - sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D); - mOutput->playSound3D(sound, sfx->mHandle, offset); - if(sfx->mUses++ == 0) - { - SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); - if(iter != mUnusedBuffers.end()) - mUnusedBuffers.erase(iter); - } - mActiveSounds[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx)); + // Look up the sound in the ESM data + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); + if(!sfx) return nullptr; + + Sound *sound = getSoundRef(); + sound->init(initialPos, volume * sfx->mVolume, volumeFromType(type), pitch, + sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D); + if(!mOutput->playSound3D(sound, sfx->mHandle, offset)) + { + mUnusedSounds.push_back(sound); + return nullptr; } - catch(std::exception &) + + if(sfx->mUses++ == 0) { - //std::cout <<"Sound Error: "< Date: Thu, 14 Sep 2017 04:48:12 -0700 Subject: [PATCH 061/505] Set HRTF when initializing the device --- apps/openmw/mwsound/openal_output.cpp | 103 ++++++++++++++++-------- apps/openmw/mwsound/openal_output.hpp | 10 +-- apps/openmw/mwsound/sound_output.hpp | 11 ++- apps/openmw/mwsound/soundmanagerimp.cpp | 11 +-- 4 files changed, 85 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index a6258babe..b3ba4a07f 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -592,7 +592,7 @@ std::vector OpenAL_Output::enumerate() return devlist; } -bool OpenAL_Output::init(const std::string &devname) +bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname, HrtfMode hrtfmode) { deinit(); @@ -615,7 +615,47 @@ bool OpenAL_Output::init(const std::string &devname) std::cout << "Opened \""< attrs; + attrs.reserve(15); + if(ALC.SOFT_HRTF) + { + LPALCGETSTRINGISOFT alcGetStringiSOFT = 0; + getALCFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT"); + + attrs.push_back(ALC_HRTF_SOFT); + attrs.push_back(hrtfmode == HrtfMode::Disable ? ALC_FALSE : + hrtfmode == HrtfMode::Enable ? ALC_TRUE : + /*hrtfmode == HrtfMode::Auto ?*/ ALC_DONT_CARE_SOFT); + if(!hrtfname.empty()) + { + ALCint index = -1; + ALCint num_hrtf; + alcGetIntegerv(mDevice, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf); + for(ALCint i = 0;i < num_hrtf;++i) + { + const ALCchar *entry = alcGetStringiSOFT(mDevice, ALC_HRTF_SPECIFIER_SOFT, i); + if(hrtfname == entry) + { + index = i; + break; + } + } + + if(index < 0) + std::cerr<< "Failed to find HRTF name \""< OpenAL_Output::enumerateHrtf() { std::vector ret; - if(!mDevice || !alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF")) + if(!mDevice || !ALC.SOFT_HRTF) return ret; LPALCGETSTRINGISOFT alcGetStringiSOFT = 0; @@ -823,9 +877,9 @@ std::vector OpenAL_Output::enumerateHrtf() return ret; } -void OpenAL_Output::enableHrtf(const std::string &hrtfname, bool auto_enable) +void OpenAL_Output::setHrtf(const std::string &hrtfname, HrtfMode hrtfmode) { - if(!alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF")) + if(!mDevice || !ALC.SOFT_HRTF) { std::cerr<< "HRTF extension not present" < attrs; + attrs.reserve(15); + attrs.push_back(ALC_HRTF_SOFT); - attrs.push_back(auto_enable ? ALC_DONT_CARE_SOFT : ALC_TRUE); + attrs.push_back(hrtfmode == HrtfMode::Disable ? ALC_FALSE : + hrtfmode == HrtfMode::Enable ? ALC_TRUE : + /*hrtfmode == HrtfMode::Auto ?*/ ALC_DONT_CARE_SOFT); if(!hrtfname.empty()) { ALCint index = -1; @@ -864,12 +922,12 @@ void OpenAL_Output::enableHrtf(const std::string &hrtfname, bool auto_enable) } } attrs.push_back(0); - alcResetDeviceSOFT(mDevice, &attrs[0]); + alcResetDeviceSOFT(mDevice, attrs.data()); ALCint hrtf_state; alcGetIntegerv(mDevice, ALC_HRTF_SOFT, 1, &hrtf_state); if(!hrtf_state) - std::cerr<< "Failed to enable HRTF" < attrs; - attrs.push_back(ALC_HRTF_SOFT); - attrs.push_back(ALC_FALSE); - attrs.push_back(0); - alcResetDeviceSOFT(mDevice, &attrs[0]); - - ALCint hrtf_state; - alcGetIntegerv(mDevice, ALC_HRTF_SOFT, 1, &hrtf_state); - if(hrtf_state) - std::cerr<< "Failed to disable HRTF" < IDDq; @@ -59,12 +60,11 @@ namespace MWSound public: virtual std::vector enumerate(); - virtual bool init(const std::string &devname=std::string()); + virtual bool init(const std::string &devname, const std::string &hrtfname, HrtfMode hrtfmode); virtual void deinit(); virtual std::vector enumerateHrtf(); - virtual void enableHrtf(const std::string &hrtfname, bool auto_enable); - virtual void disableHrtf(); + virtual void setHrtf(const std::string &hrtfname, HrtfMode hrtfmode); virtual Sound_Handle loadSound(const std::string &fname); virtual void unloadSound(Sound_Handle data); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 01dc8b5b9..ad18e0d40 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -19,17 +19,22 @@ namespace MWSound // An opaque handle for the implementation's sound instances. typedef void *Sound_Instance; + enum class HrtfMode { + Disable, + Enable, + Auto + }; + class Sound_Output { SoundManager &mManager; virtual std::vector enumerate() = 0; - virtual bool init(const std::string &devname=std::string()) = 0; + virtual bool init(const std::string &devname, const std::string &hrtfname, HrtfMode hrtfmode) = 0; virtual void deinit() = 0; virtual std::vector enumerateHrtf() = 0; - virtual void enableHrtf(const std::string &hrtfname, bool auto_enable) = 0; - virtual void disableHrtf() = 0; + virtual void setHrtf(const std::string &hrtfname, HrtfMode hrtfmode) = 0; virtual Sound_Handle loadSound(const std::string &fname) = 0; virtual void unloadSound(Sound_Handle data) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 51ce67096..7310e457f 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -85,6 +85,8 @@ namespace MWSound std::string hrtfname = Settings::Manager::getString("hrtf", "Sound"); int hrtfstate = Settings::Manager::getInt("hrtf enable", "Sound"); + HrtfMode hrtfmode = hrtfstate < 0 ? HrtfMode::Auto : + hrtfstate > 0 ? HrtfMode::Enable : HrtfMode::Disable; std::cout << "Sound output: " << SOUND_OUT << std::endl; std::cout << "Sound decoder: " << SOUND_IN << std::endl; @@ -98,11 +100,11 @@ namespace MWSound std::cout.flush(); std::string devname = Settings::Manager::getString("device", "Sound"); - bool inited = mOutput->init(devname); + bool inited = mOutput->init(devname, hrtfname, hrtfmode); if(!inited && !devname.empty()) { std::cerr<< "Failed to initialize device \""<init(); + inited = mOutput->init(std::string(), hrtfname, hrtfmode); } if(!inited) { @@ -120,11 +122,6 @@ namespace MWSound ); std::cout.flush(); } - - if(hrtfstate == 0) - mOutput->disableHrtf(); - else if(!hrtfname.empty()) - mOutput->enableHrtf(hrtfname, hrtfstate<0); } SoundManager::~SoundManager() From 1e123a22e1a51d59d3a1ea4336142d87f93b086d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Sep 2017 16:56:46 -0700 Subject: [PATCH 062/505] Avoid some explicit loops --- apps/openmw/mwsound/soundmanagerimp.cpp | 33 ++++++++++++------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 7310e457f..2e8ff85c8 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -819,15 +819,12 @@ namespace MWSound if(regn == NULL) return; - std::vector::const_iterator soundIter; if(total == 0) { - soundIter = regn->mSoundList.begin(); - while(soundIter != regn->mSoundList.end()) - { - total += (int)soundIter->mChance; - ++soundIter; - } + std::for_each(regn->mSoundList.cbegin(), regn->mSoundList.cend(), + [](const ESM::Region::SoundRef &sndref) -> void + { total += (int)sndref.mChance; } + ); if(total == 0) return; } @@ -835,18 +832,20 @@ namespace MWSound int r = Misc::Rng::rollDice(total); int pos = 0; - soundIter = regn->mSoundList.begin(); - while(soundIter != regn->mSoundList.end()) - { - if(r - pos < soundIter->mChance) + std::find_if_not(regn->mSoundList.cbegin(), regn->mSoundList.cend(), + [&pos, r, this](const ESM::Region::SoundRef &sndref) -> bool { - playSound(soundIter->mSound.toString(), 1.0f, 1.0f); - break; + if(r - pos < sndref.mChance) + { + playSound(sndref.mSound.toString(), 1.0f, 1.0f); + // Played this sound, stop iterating + return false; + } + pos += sndref.mChance; + // Not this sound, keep iterating + return true; } - pos += soundIter->mChance; - - ++soundIter; - } + ); } void SoundManager::updateWaterSound(float /*duration*/) From 0c1ad7c74e32a7aecf6e608558e7d6082615621c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Sep 2017 21:39:13 -0700 Subject: [PATCH 063/505] Replace a few more explicit loops --- apps/openmw/mwsound/openal_output.cpp | 102 +++++++++++++------------- 1 file changed, 50 insertions(+), 52 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index b3ba4a07f..00562de1a 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -1,9 +1,10 @@ #include #include #include +#include #include #include -#include +#include #include @@ -174,93 +175,90 @@ namespace MWSound static ALenum getALFormat(ChannelConfig chans, SampleType type) { - static const struct { + struct FormatEntry { ALenum format; ChannelConfig chans; SampleType type; - } fmtlist[] = { + }; + struct FormatEntryExt { + const char name[32]; + ChannelConfig chans; + SampleType type; + }; + static const std::array fmtlist{{ { AL_FORMAT_MONO16, ChannelConfig_Mono, SampleType_Int16 }, { AL_FORMAT_MONO8, ChannelConfig_Mono, SampleType_UInt8 }, { AL_FORMAT_STEREO16, ChannelConfig_Stereo, SampleType_Int16 }, { AL_FORMAT_STEREO8, ChannelConfig_Stereo, SampleType_UInt8 }, - }; - static const size_t fmtlistsize = sizeof(fmtlist)/sizeof(fmtlist[0]); + }}; - for(size_t i = 0;i < fmtlistsize;i++) - { - if(fmtlist[i].chans == chans && fmtlist[i].type == type) - return fmtlist[i].format; - } + auto fmt = std::find_if(fmtlist.cbegin(), fmtlist.cend(), + [chans,type](const FormatEntry &fmt) -> bool + { return fmt.chans == chans && fmt.type == type; } + ); + if(fmt != fmtlist.cend()) + return fmt->format; if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { - static const struct { - char name[32]; - ChannelConfig chans; - SampleType type; - } mcfmtlist[] = { + static const std::array mcfmtlist{{ { "AL_FORMAT_QUAD16", ChannelConfig_Quad, SampleType_Int16 }, { "AL_FORMAT_QUAD8", ChannelConfig_Quad, SampleType_UInt8 }, { "AL_FORMAT_51CHN16", ChannelConfig_5point1, SampleType_Int16 }, { "AL_FORMAT_51CHN8", ChannelConfig_5point1, SampleType_UInt8 }, { "AL_FORMAT_71CHN16", ChannelConfig_7point1, SampleType_Int16 }, { "AL_FORMAT_71CHN8", ChannelConfig_7point1, SampleType_UInt8 }, - }; - static const size_t mcfmtlistsize = sizeof(mcfmtlist)/sizeof(mcfmtlist[0]); + }}; + ALenum format = AL_NONE; - for(size_t i = 0;i < mcfmtlistsize;i++) - { - if(mcfmtlist[i].chans == chans && mcfmtlist[i].type == type) + std::find_if(mcfmtlist.cbegin(), mcfmtlist.cend(), + [&format,chans,type](const FormatEntryExt &fmt) -> bool { - ALenum format = alGetEnumValue(mcfmtlist[i].name); - if(format != 0 && format != -1) - return format; + if(fmt.chans == chans && fmt.type == type) + format = alGetEnumValue(fmt.name); + return format != 0 && format != -1; } - } + ); + if(format != 0 && format != -1) + return format; } if(alIsExtensionPresent("AL_EXT_FLOAT32")) { - static const struct { - char name[32]; - ChannelConfig chans; - SampleType type; - } fltfmtlist[] = { + static const std::array fltfmtlist{{ { "AL_FORMAT_MONO_FLOAT32", ChannelConfig_Mono, SampleType_Float32 }, { "AL_FORMAT_STEREO_FLOAT32", ChannelConfig_Stereo, SampleType_Float32 }, - }; - static const size_t fltfmtlistsize = sizeof(fltfmtlist)/sizeof(fltfmtlist[0]); + }}; + ALenum format = AL_NONE; - for(size_t i = 0;i < fltfmtlistsize;i++) - { - if(fltfmtlist[i].chans == chans && fltfmtlist[i].type == type) + std::find_if(fltfmtlist.cbegin(), fltfmtlist.cend(), + [&format,chans,type](const FormatEntryExt &fmt) -> bool { - ALenum format = alGetEnumValue(fltfmtlist[i].name); - if(format != 0 && format != -1) - return format; + if(fmt.chans == chans && fmt.type == type) + format = alGetEnumValue(fmt.name); + return format != 0 && format != -1; } - } + ); + if(format != 0 && format != -1) + return format; + if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { - static const struct { - char name[32]; - ChannelConfig chans; - SampleType type; - } fltmcfmtlist[] = { + static const std::array fltmcfmtlist{{ { "AL_FORMAT_QUAD32", ChannelConfig_Quad, SampleType_Float32 }, { "AL_FORMAT_51CHN32", ChannelConfig_5point1, SampleType_Float32 }, { "AL_FORMAT_71CHN32", ChannelConfig_7point1, SampleType_Float32 }, - }; - static const size_t fltmcfmtlistsize = sizeof(fltmcfmtlist)/sizeof(fltmcfmtlist[0]); + }}; - for(size_t i = 0;i < fltmcfmtlistsize;i++) - { - if(fltmcfmtlist[i].chans == chans && fltmcfmtlist[i].type == type) + std::find_if(fltmcfmtlist.cbegin(), fltmcfmtlist.cend(), + [&format,chans,type](const FormatEntryExt &fmt) -> bool { - ALenum format = alGetEnumValue(fltmcfmtlist[i].name); - if(format != 0 && format != -1) - return format; + if(fmt.chans == chans && fmt.type == type) + format = alGetEnumValue(fmt.name); + return format != 0 && format != -1; } - } + ); + if(format != 0 && format != -1) + return format; } } From 780e82480d7a8b700ab6459f09da6bc3076f2aea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Sep 2017 01:03:41 -0700 Subject: [PATCH 064/505] Make the PlayMode and PlayType enums scoped Also shorten them by putting them in the MWSound namespace --- apps/openmw/mwbase/soundmanager.hpp | 81 ++++++++++++----------- apps/openmw/mwclass/container.cpp | 4 +- apps/openmw/mwclass/door.cpp | 4 +- apps/openmw/mwclass/light.cpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/character.cpp | 13 ++-- apps/openmw/mwrender/npcanimation.cpp | 5 +- apps/openmw/mwscript/soundextensions.cpp | 16 ++--- apps/openmw/mwsound/movieaudiofactory.cpp | 2 +- apps/openmw/mwsound/openal_output.cpp | 56 ++++++++-------- apps/openmw/mwsound/sound.hpp | 14 ++-- apps/openmw/mwsound/soundmanagerimp.cpp | 52 ++++++++------- apps/openmw/mwsound/soundmanagerimp.hpp | 16 ++--- apps/openmw/mwworld/action.cpp | 12 ++-- apps/openmw/mwworld/projectilemanager.cpp | 11 ++- apps/openmw/mwworld/weather.cpp | 6 +- 17 files changed, 157 insertions(+), 146 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 4439fe8f3..f1c35df19 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -18,6 +18,37 @@ namespace MWSound class Stream; struct Sound_Decoder; typedef std::shared_ptr DecoderPtr; + + /* These must all fit together */ + enum class PlayMode { + Normal = 0, /* non-looping, affected by environment */ + Loop = 1<<0, /* Sound will continually loop until explicitly stopped */ + NoEnv = 1<<1, /* Do not apply environment effects (eg, underwater filters) */ + RemoveAtDistance = 1<<2, /* (3D only) If the listener gets further than 2000 units away + * from the sound source, the sound is removed. + * This is weird stuff but apparently how vanilla works for sounds + * played by the PlayLoopSound family of script functions. Perhaps + * we can make this cut off a more subtle fade later, but have to + * be careful to not change the overall volume of areas by too + * much. */ + NoPlayerLocal = 1<<3, /* (3D only) Don't play the sound local to the listener even if the + * player is making it. */ + LoopNoEnv = Loop | NoEnv, + LoopRemoveAtDistance = Loop | RemoveAtDistance + }; + enum class Type { + Sfx = 1<<4, /* Normal SFX sound */ + Voice = 1<<5, /* Voice sound */ + Foot = 1<<6, /* Footstep sound */ + Music = 1<<7, /* Music track */ + Movie = 1<<8, /* Movie audio track */ + Mask = Sfx | Voice | Foot | Music | Movie + }; + // Used for creating a type mask for SoundManager::pauseSounds and resumeSounds + inline int operator~(Type a) { return ~static_cast(a); } + inline int operator&(Type a, Type b) { return static_cast(a) & static_cast(b); } + inline int operator&(int a, Type b) { return a & static_cast(b); } + inline int operator|(Type a, Type b) { return static_cast(a) | static_cast(b); } } namespace MWBase @@ -28,44 +59,18 @@ namespace MWBase /// \brief Interface for sound manager (implemented in MWSound) class SoundManager { - public: - /* These must all fit together */ - enum PlayMode { - Play_Normal = 0, /* non-looping, affected by environment */ - Play_Loop = 1<<0, /* Sound will continually loop until explicitly stopped */ - Play_NoEnv = 1<<1, /* Do not apply environment effects (eg, underwater filters) */ - Play_RemoveAtDistance = 1<<2, /* (3D only) If the listener gets further than 2000 units away - from the sound source, the sound is removed. - This is weird stuff but apparently how vanilla works for sounds - played by the PlayLoopSound family of script functions. Perhaps we - can make this cut off a more subtle fade later, but have to - be careful to not change the overall volume of areas by too much. */ - Play_NoPlayerLocal = 1<<3, /* (3D only) Don't play the sound local to the listener even if the - player is making it. */ - Play_LoopNoEnv = Play_Loop | Play_NoEnv, - Play_LoopRemoveAtDistance = Play_Loop | Play_RemoveAtDistance - }; - enum PlayType { - Play_TypeSfx = 1<<4, /* Normal SFX sound */ - Play_TypeVoice = 1<<5, /* Voice sound */ - Play_TypeFoot = 1<<6, /* Footstep sound */ - Play_TypeMusic = 1<<7, /* Music track */ - Play_TypeMovie = 1<<8, /* Movie audio track */ - Play_TypeMask = Play_TypeSfx|Play_TypeVoice|Play_TypeFoot|Play_TypeMusic|Play_TypeMovie - }; - - private: - SoundManager (const SoundManager&); ///< not implemented SoundManager& operator= (const SoundManager&); ///< not implemented - public: + protected: + using PlayMode = MWSound::PlayMode; + using Type = MWSound::Type; + public: SoundManager() {} - virtual ~SoundManager() {} virtual void processChangedSettings(const std::set< std::pair >& settings) = 0; @@ -106,7 +111,7 @@ namespace MWBase /// and get an average loudness value (scale [0,1]) at the current time position. /// If the actor is not saying anything, returns 0. - virtual SoundStream *playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; + virtual SoundStream *playTrack(const MWSound::DecoderPtr& decoder, Type type) = 0; ///< Play a 2D audio track, using a custom decoder. The caller is expected to call /// stopTrack with the returned handle when done. @@ -119,20 +124,20 @@ namespace MWBase /// decoder's read method. virtual Sound *playSound(const std::string& soundId, float volume, float pitch, - PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, + Type type=Type::Sfx, PlayMode mode=PlayMode::Normal, float offset=0) = 0; ///< Play a sound, independently of 3D-position ///< @param offset Number of seconds into the sound to start playback. virtual Sound *playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, - float volume, float pitch, PlayType type=Play_TypeSfx, - PlayMode mode=Play_Normal, float offset=0) = 0; + float volume, float pitch, Type type=Type::Sfx, + PlayMode mode=PlayMode::Normal, float offset=0) = 0; ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. ///< @param offset Number of seconds into the sound to start playback. virtual Sound *playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, - float volume, float pitch, PlayType type=Play_TypeSfx, - PlayMode mode=Play_Normal, float offset=0) = 0; + float volume, float pitch, Type type=Type::Sfx, + PlayMode mode=PlayMode::Normal, float offset=0) = 0; ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. virtual void stopSound(Sound *sound) = 0; @@ -160,10 +165,10 @@ namespace MWBase ///< Is the given sound currently playing on the given object? /// If you want to check if sound played with playSound is playing, use empty Ptr - virtual void pauseSounds(int types=Play_TypeMask) = 0; + virtual void pauseSounds(int types=static_cast(Type::Mask)) = 0; ///< Pauses all currently playing sounds, including music. - virtual void resumeSounds(int types=Play_TypeMask) = 0; + virtual void resumeSounds(int types=static_cast(Type::Mask)) = 0; ///< Resumes all previously paused sounds. virtual void update(float duration) = 0; diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index dc4eb844a..b6a46cff8 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -169,9 +169,7 @@ namespace MWClass if(isTrapped) { ptr.getCellRef().setTrap(""); - MWBase::Environment::get().getSoundManager()->playSound3D(ptr, - "Disarm Trap", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, - MWBase::SoundManager::Play_Normal); + MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Disarm Trap", 1.0f, 1.0f); isTrapped = false; } } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 07e6cc9db..903ec4958 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -163,9 +163,7 @@ namespace MWClass if(isTrapped) { ptr.getCellRef().setTrap(""); - MWBase::Environment::get().getSoundManager()->playSound3D(ptr, - "Disarm Trap", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, - MWBase::SoundManager::Play_Normal); + MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Disarm Trap", 1.0f, 1.0f); isTrapped = false; } } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 172c16c83..f9056b75d 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -49,8 +49,8 @@ namespace MWClass if (!ref->mBase->mSound.empty() && !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)) MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0, - MWBase::SoundManager::Play_TypeSfx, - MWBase::SoundManager::Play_Loop); + MWSound::Type::Sfx, + MWSound::PlayMode::Loop); } bool Light::useAnim() const diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 4b7b3c387..1526949a3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1848,7 +1848,8 @@ namespace MWGui if (mVideoWidget->hasAudioStream()) MWBase::Environment::get().getSoundManager()->pauseSounds( - MWBase::SoundManager::Play_TypeMask&(~MWBase::SoundManager::Play_TypeMovie)); + ~MWSound::Type::Movie & MWSound::Type::Mask + ); osg::Timer frameTimer; while (mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { @@ -2035,7 +2036,7 @@ namespace MWGui void WindowManager::playSound(const std::string& soundId, float volume, float pitch) { - MWBase::Environment::get().getSoundManager()->playSound(soundId, volume, pitch, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoEnv); + MWBase::Environment::get().getSoundManager()->playSound(soundId, volume, pitch, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); } void WindowManager::setConsoleSelectedObject(const MWWorld::Ptr &object) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d15e1a1a5..baa2470da 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -991,7 +991,7 @@ namespace MWMechanics // ...But, only the player makes a sound. if(isPlayer) MWBase::Environment::get().getSoundManager()->playSound("torch out", - 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoEnv); + 1.0, 1.0, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); } } } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 51dc37e18..2f645279a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -843,8 +843,8 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: { // Don't make foot sounds local for the player, it makes sense to keep them // positioned on the ground. - sndMgr->playSound3D(mPtr, sound, volume, pitch, MWBase::SoundManager::Play_TypeFoot, - MWBase::SoundManager::Play_NoPlayerLocal); + sndMgr->playSound3D(mPtr, sound, volume, pitch, MWSound::Type::Foot, + MWSound::PlayMode::NoPlayerLocal); } else { @@ -1177,8 +1177,8 @@ bool CharacterController::updateWeaponState() && mWeaponType == WeapType_None) { if(!sndMgr->getSoundPlaying(mPtr, "WolfRun")) - sndMgr->playSound3D(mPtr, "WolfRun", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, - MWBase::SoundManager::Play_Loop); + sndMgr->playSound3D(mPtr, "WolfRun", 1.0f, 1.0f, MWSound::Type::Sfx, + MWSound::PlayMode::Loop); } else sndMgr->stopSound3D(mPtr, "WolfRun"); @@ -1309,9 +1309,8 @@ bool CharacterController::updateWeaponState() if(!resultMessage.empty()) MWBase::Environment::get().getWindowManager()->messageBox(resultMessage); if(!resultSound.empty()) - MWBase::Environment::get().getSoundManager()->playSound3D(target, - resultSound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, - MWBase::SoundManager::Play_Normal); + MWBase::Environment::get().getSoundManager()->playSound3D(target, resultSound, + 1.0f, 1.0f); } else if (ammunition) { diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e4d0abf7b..8211c2f5f 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -770,8 +770,9 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g mSoundIds[type] = csi->getClass().getSound(*csi); if (!mSoundIds[type].empty()) { - MWBase::Environment::get().getSoundManager()->playSound3D(mPtr, mSoundIds[type], 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, - MWBase::SoundManager::Play_Loop); + MWBase::Environment::get().getSoundManager()->playSound3D(mPtr, mSoundIds[type], + 1.0f, 1.0f, MWSound::Type::Sfx, MWSound::PlayMode::Loop + ); } } } diff --git a/apps/openmw/mwscript/soundextensions.cpp b/apps/openmw/mwscript/soundextensions.cpp index bedc02138..4d199c299 100644 --- a/apps/openmw/mwscript/soundextensions.cpp +++ b/apps/openmw/mwscript/soundextensions.cpp @@ -82,7 +82,7 @@ namespace MWScript std::string sound = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - MWBase::Environment::get().getSoundManager()->playSound(sound, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoEnv); + MWBase::Environment::get().getSoundManager()->playSound(sound, 1.0, 1.0, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); } }; @@ -101,7 +101,7 @@ namespace MWScript Interpreter::Type_Float pitch = runtime[0].mFloat; runtime.pop(); - MWBase::Environment::get().getSoundManager()->playSound(sound, volume, pitch, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoEnv); + MWBase::Environment::get().getSoundManager()->playSound(sound, volume, pitch, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); } }; @@ -122,9 +122,9 @@ namespace MWScript runtime.pop(); MWBase::Environment::get().getSoundManager()->playSound3D(ptr, sound, 1.0, 1.0, - MWBase::SoundManager::Play_TypeSfx, - mLoop ? MWBase::SoundManager::Play_LoopRemoveAtDistance - : MWBase::SoundManager::Play_Normal); + MWSound::Type::Sfx, + mLoop ? MWSound::PlayMode::LoopRemoveAtDistance + : MWSound::PlayMode::Normal); } }; @@ -151,9 +151,9 @@ namespace MWScript runtime.pop(); MWBase::Environment::get().getSoundManager()->playSound3D(ptr, sound, volume, pitch, - MWBase::SoundManager::Play_TypeSfx, - mLoop ? MWBase::SoundManager::Play_LoopRemoveAtDistance - : MWBase::SoundManager::Play_Normal); + MWSound::Type::Sfx, + mLoop ? MWSound::PlayMode::LoopRemoveAtDistance + : MWSound::PlayMode::Normal); } }; diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 9c9b442c7..f54ab5c06 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -162,7 +162,7 @@ namespace MWSound decoder->setupFormat(); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - MWBase::SoundStream *sound = sndMgr->playTrack(decoder->mDecoderBridge, MWBase::SoundManager::Play_TypeMovie); + MWBase::SoundStream *sound = sndMgr->playTrack(decoder->mDecoderBridge, MWSound::Type::Movie); if (!sound) { decoder.reset(); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 00562de1a..1a9baed77 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -1403,21 +1403,23 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi void OpenAL_Output::pauseSounds(int types) { std::vector sources; - SoundVec::const_iterator sound = mActiveSounds.begin(); - for(;sound != mActiveSounds.end();++sound) - { - if(*sound && (*sound)->mHandle && ((*sound)->getPlayType()&types)) - sources.push_back(GET_PTRID((*sound)->mHandle)); - } - StreamVec::const_iterator stream = mActiveStreams.begin(); - for(;stream != mActiveStreams.end();++stream) - { - if(*stream && (*stream)->mHandle && ((*stream)->getPlayType()&types)) + std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(), + [types,&sources](const SoundVec::value_type &sound) -> void { - OpenAL_SoundStream *strm = reinterpret_cast((*stream)->mHandle); - sources.push_back(strm->mSource); + if(sound && sound->mHandle && (types&sound->getPlayType())) + sources.push_back(GET_PTRID(sound->mHandle)); } - } + ); + std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(), + [types,&sources](const StreamVec::value_type &stream) -> void + { + if(stream && stream->mHandle && (types&stream->getPlayType())) + { + OpenAL_SoundStream *strm = reinterpret_cast(stream->mHandle); + sources.push_back(strm->mSource); + } + } + ); if(!sources.empty()) { alSourcePausev(sources.size(), sources.data()); @@ -1428,21 +1430,23 @@ void OpenAL_Output::pauseSounds(int types) void OpenAL_Output::resumeSounds(int types) { std::vector sources; - SoundVec::const_iterator sound = mActiveSounds.begin(); - for(;sound != mActiveSounds.end();++sound) - { - if(*sound && (*sound)->mHandle && ((*sound)->getPlayType()&types)) - sources.push_back(GET_PTRID((*sound)->mHandle)); - } - StreamVec::const_iterator stream = mActiveStreams.begin(); - for(;stream != mActiveStreams.end();++stream) - { - if(*stream && (*stream)->mHandle && ((*stream)->getPlayType()&types)) + std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(), + [types,&sources](const SoundVec::value_type &sound) -> void { - OpenAL_SoundStream *strm = reinterpret_cast((*stream)->mHandle); - sources.push_back(strm->mSource); + if(sound && sound->mHandle && (types&sound->getPlayType())) + sources.push_back(GET_PTRID(sound->mHandle)); } - } + ); + std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(), + [types,&sources](const StreamVec::value_type &stream) -> void + { + if(stream && stream->mHandle && (types&stream->getPlayType())) + { + OpenAL_SoundStream *strm = reinterpret_cast(stream->mHandle); + sources.push_back(strm->mSource); + } + } + ); if(!sources.empty()) { alSourcePlayv(sources.size(), sources.data()); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 1389835db..7324b6747 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -7,6 +7,10 @@ namespace MWSound { + // For testing individual PlayMode flags + inline int operator&(int a, PlayMode b) { return a & static_cast(b); } + inline int operator&(PlayMode a, PlayMode b) { return static_cast(a) & static_cast(b); } + class SoundBase { SoundBase& operator=(const SoundBase&) = delete; SoundBase(const SoundBase&) = delete; @@ -48,11 +52,11 @@ namespace MWSound float getMinDistance() const { return mMinDistance; } float getMaxDistance() const { return mMaxDistance; } - MWBase::SoundManager::PlayType getPlayType() const - { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); } - bool getUseEnv() const { return !(mFlags&MWBase::SoundManager::Play_NoEnv); } - bool getIsLooping() const { return mFlags&MWBase::SoundManager::Play_Loop; } - bool getDistanceCull() const { return mFlags&MWBase::SoundManager::Play_RemoveAtDistance; } + MWSound::Type getPlayType() const + { return static_cast(mFlags&MWSound::Type::Mask); } + bool getUseEnv() const { return !(mFlags&MWSound::PlayMode::NoEnv); } + bool getIsLooping() const { return mFlags&MWSound::PlayMode::Loop; } + bool getDistanceCull() const { return mFlags&MWSound::PlayMode::RemoveAtDistance; } bool getIs3D() const { return mFlags&Play_3D; } void init(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 2e8ff85c8..0b6d8ff34 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -35,6 +35,9 @@ namespace MWSound { + // For combining PlayMode and Type flags + inline int operator|(PlayMode a, Type b) { return static_cast(a) | static_cast(b); } + SoundManager::SoundManager(const VFS::Manager* vfs, const std::map& fallbackMap, bool useSound) : mVFS(vfs) , mFallback(fallbackMap) @@ -299,17 +302,17 @@ namespace MWSound static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); bool played; - float basevol = volumeFromType(Play_TypeVoice); + float basevol = volumeFromType(Type::Voice); Stream *sound = getStreamRef(); if(playlocal) { - sound->init(1.0f, basevol, 1.0f, Play_NoEnv|Play_TypeVoice|Play_2D); + sound->init(1.0f, basevol, 1.0f, PlayMode::NoEnv|Type::Voice|Play_2D); played = mOutput->streamSound(decoder, sound); } else { sound->init(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance, - Play_Normal|Play_TypeVoice|Play_3D); + PlayMode::Normal|Type::Voice|Play_3D); played = mOutput->streamSound3D(decoder, sound, true); } if(!played) @@ -321,26 +324,25 @@ namespace MWSound } // Gets the combined volume settings for the given sound type - float SoundManager::volumeFromType(PlayType type) const + float SoundManager::volumeFromType(Type type) const { float volume = mMasterVolume; switch(type) { - case Play_TypeSfx: + case Type::Sfx: volume *= mSFXVolume; break; - case Play_TypeVoice: + case Type::Voice: volume *= mVoiceVolume; break; - case Play_TypeFoot: + case Type::Foot: volume *= mFootstepsVolume; break; - case Play_TypeMusic: + case Type::Music: volume *= mMusicVolume; break; - case Play_TypeMask: - break; - default: + case Type::Movie: + case Type::Mask: break; } return volume; @@ -369,8 +371,8 @@ namespace MWSound decoder->open(filename); mMusic = getStreamRef(); - mMusic->init(1.0f, volumeFromType(Play_TypeMusic), 1.0f, - Play_NoEnv|Play_TypeMusic|Play_2D); + mMusic->init(1.0f, volumeFromType(Type::Music), 1.0f, + PlayMode::NoEnv|Type::Music|Play_2D); mOutput->streamSound(decoder, mMusic); } @@ -527,13 +529,13 @@ namespace MWSound } - Stream *SoundManager::playTrack(const DecoderPtr& decoder, PlayType type) + Stream *SoundManager::playTrack(const DecoderPtr& decoder, Type type) { if(!mOutput->isInitialized()) return nullptr; Stream *track = getStreamRef(); - track->init(1.0f, volumeFromType(type), 1.0f, Play_NoEnv|type|Play_2D); + track->init(1.0f, volumeFromType(type), 1.0f, PlayMode::NoEnv|type|Play_2D); if(!mOutput->streamSound(decoder, track)) { mUnusedStreams.push_back(track); @@ -561,7 +563,7 @@ namespace MWSound } - Sound *SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) + Sound *SoundManager::playSound(const std::string& soundId, float volume, float pitch, Type type, PlayMode mode, float offset) { if(!mOutput->isInitialized()) return nullptr; @@ -588,7 +590,7 @@ namespace MWSound } Sound *SoundManager::playSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId, - float volume, float pitch, PlayType type, PlayMode mode, + float volume, float pitch, Type type, PlayMode mode, float offset) { if(!mOutput->isInitialized()) @@ -599,7 +601,7 @@ namespace MWSound if(!sfx) return nullptr; const osg::Vec3f objpos(ptr.getRefData().getPosition().asVec3()); - if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) + if((mode&PlayMode::RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) return nullptr; // Only one copy of given sound can be played at time on ptr, so stop previous copy @@ -607,7 +609,7 @@ namespace MWSound bool played; Sound *sound = getSoundRef(); - if(!(mode&Play_NoPlayerLocal) && ptr == MWMechanics::getPlayer()) + if(!(mode&PlayMode::NoPlayerLocal) && ptr == MWMechanics::getPlayer()) { sound->init(volume * sfx->mVolume, volumeFromType(type), pitch, mode|type|Play_2D); played = mOutput->playSound(sound, sfx->mHandle, offset); @@ -635,7 +637,7 @@ namespace MWSound } Sound *SoundManager::playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, - float volume, float pitch, PlayType type, PlayMode mode, + float volume, float pitch, Type type, PlayMode mode, float offset) { if(!mOutput->isInitialized()) @@ -772,7 +774,7 @@ namespace MWSound { if(mOutput->isInitialized()) { - types &= Play_TypeMask; + types = types & Type::Mask; mOutput->pauseSounds(types); mPausedSoundTypes |= types; } @@ -782,7 +784,7 @@ namespace MWSound { if(mOutput->isInitialized()) { - types &= types&Play_TypeMask&mPausedSoundTypes; + types = types & Type::Mask & mPausedSoundTypes; mOutput->resumeSounds(types); mPausedSoundTypes &= ~types; } @@ -932,7 +934,7 @@ namespace MWSound if(soundIdChanged) { mOutput->finishSound(mNearWaterSound); - mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop); + mNearWaterSound = playSound(soundId, volume, 1.0f, Type::Sfx, PlayMode::Loop); } else if (sfx) mNearWaterSound->setVolume(volume * sfx->mVolume); @@ -941,7 +943,7 @@ namespace MWSound else if (volume > 0.0f) { LastCell = curcell; - mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop); + mNearWaterSound = playSound(soundId, volume, 1.0f, Type::Sfx, PlayMode::Loop); } } @@ -1084,7 +1086,7 @@ namespace MWSound { // Play underwater sound (after updating sounds) if(!mUnderwaterSound) - mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv); + mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Type::Sfx, PlayMode::LoopNoEnv); } mOutput->finishUpdate(); } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index e5889e36d..d2dce3928 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -135,7 +135,7 @@ namespace MWSound std::string mNextMusic; - float volumeFromType(PlayType type) const; + float volumeFromType(Type type) const; SoundManager(const SoundManager &rhs); SoundManager& operator=(const SoundManager &rhs); @@ -186,7 +186,7 @@ namespace MWSound /// and get an average loudness value (scale [0,1]) at the current time position. /// If the actor is not saying anything, returns 0. - virtual Stream *playTrack(const DecoderPtr& decoder, PlayType type); + virtual Stream *playTrack(const DecoderPtr& decoder, Type type); ///< Play a 2D audio track, using a custom decoder virtual void stopTrack(Stream *stream); @@ -197,18 +197,18 @@ namespace MWSound /// returned by \ref playTrack). Only intended to be called by the track /// decoder's read method. - virtual Sound *playSound(const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0); + virtual Sound *playSound(const std::string& soundId, float volume, float pitch, Type type=Type::Sfx, PlayMode mode=PlayMode::Normal, float offset=0); ///< Play a sound, independently of 3D-position ///< @param offset Number of seconds into the sound to start playback. virtual Sound *playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, - float volume, float pitch, PlayType type=Play_TypeSfx, - PlayMode mode=Play_Normal, float offset=0); + float volume, float pitch, Type type=Type::Sfx, + PlayMode mode=PlayMode::Normal, float offset=0); ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. ///< @param offset Number of seconds into the sound to start playback. virtual Sound *playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, - float volume, float pitch, PlayType type, PlayMode mode, float offset=0); + float volume, float pitch, Type type, PlayMode mode, float offset=0); ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. ///< @param offset Number of seconds into the sound to start playback. @@ -237,10 +237,10 @@ namespace MWSound virtual bool getSoundPlaying(const MWWorld::ConstPtr &reference, const std::string& soundId) const; ///< Is the given sound currently playing on the given object? - virtual void pauseSounds(int types=Play_TypeMask); + virtual void pauseSounds(int types); ///< Pauses all currently playing sounds, including music. - virtual void resumeSounds(int types=Play_TypeMask); + virtual void resumeSounds(int types); ///< Resumes all previously paused sounds. virtual void update(float duration); diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index 468207e81..32a3c8f96 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -27,18 +27,18 @@ void MWWorld::Action::execute (const Ptr& actor, bool noSound) { if(!mSoundId.empty() && !noSound) { - MWBase::SoundManager::PlayMode envType = MWBase::SoundManager::Play_Normal; + MWSound::PlayMode envType = MWSound::PlayMode::Normal; // Action sounds should not have a distortion in GUI mode // example: take an item or drink a potion underwater if (actor == MWMechanics::getPlayer() && MWBase::Environment::get().getWindowManager()->isGuiMode()) { - envType = MWBase::SoundManager::Play_NoEnv; + envType = MWSound::PlayMode::NoEnv; } if(mKeepSound && actor == MWMechanics::getPlayer()) MWBase::Environment::get().getSoundManager()->playSound(mSoundId, 1.0, 1.0, - MWBase::SoundManager::Play_TypeSfx, envType, mSoundOffset + MWSound::Type::Sfx, envType, mSoundOffset ); else { @@ -46,13 +46,11 @@ void MWWorld::Action::execute (const Ptr& actor, bool noSound) if(mKeepSound) MWBase::Environment::get().getSoundManager()->playSound3D( (local ? actor : mTarget).getRefData().getPosition().asVec3(), - mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, - envType, mSoundOffset + mSoundId, 1.0, 1.0, MWSound::Type::Sfx, envType, mSoundOffset ); else MWBase::Environment::get().getSoundManager()->playSound3D(local ? actor : mTarget, - mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, - envType, mSoundOffset + mSoundId, 1.0, 1.0, MWSound::Type::Sfx, envType, mSoundOffset ); } } diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 64d601563..5b15583bf 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -283,7 +283,8 @@ namespace MWWorld MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); for (size_t it = 0; it != state.mSoundIds.size(); it++) { - MWBase::Sound *sound = sndMgr->playSound3D(pos, state.mSoundIds.at(it), 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); + MWBase::Sound *sound = sndMgr->playSound3D(pos, state.mSoundIds.at(it), 1.0f, 1.0f, + MWSound::Type::Sfx, MWSound::PlayMode::Loop); if (sound) state.mSounds.push_back(sound); } @@ -377,10 +378,9 @@ namespace MWWorld MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, result.mHitObject, ESM::RT_Target, it->mSpellId, it->mSourceName); + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); for (size_t soundIter = 0; soundIter != it->mSounds.size(); soundIter++) - { - MWBase::Environment::get().getSoundManager()->stopSound(it->mSounds.at(soundIter)); - } + sndMgr->stopSound(it->mSounds.at(soundIter)); mParent->removeChild(it->mNode); @@ -581,11 +581,10 @@ namespace MWWorld createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, lightDiffuseColor, texture); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - for (size_t soundIter = 0; soundIter != state.mSoundIds.size(); soundIter++) { MWBase::Sound *sound = sndMgr->playSound3D(esm.mPosition, state.mSoundIds.at(soundIter), 1.0f, 1.0f, - MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); + MWSound::Type::Sfx, MWSound::PlayMode::Loop); if (sound) state.mSounds.push_back(sound); } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index c4b46961c..2f0a2f8cf 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -731,8 +731,10 @@ void WeatherManager::update(float duration, bool paused) { stopSounds(); if (!mResult.mAmbientLoopSoundID.empty()) - mAmbientSound = MWBase::Environment::get().getSoundManager()->playSound(mResult.mAmbientLoopSoundID, mResult.mAmbientSoundVolume, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); - + mAmbientSound = MWBase::Environment::get().getSoundManager()->playSound( + mResult.mAmbientLoopSoundID, mResult.mAmbientSoundVolume, 1.0, + MWSound::Type::Sfx, MWSound::PlayMode::Loop + ); mPlayingSoundID = mResult.mAmbientLoopSoundID; } else if (mAmbientSound) From d68e1581ee3652bcb7f93457d7e67008c3f79538 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Sep 2017 05:40:20 -0700 Subject: [PATCH 065/505] Use an std::array for the OpenAL stream buffers --- apps/openmw/mwsound/openal_output.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 1a9baed77..64aa1aff7 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -273,13 +273,12 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) // class OpenAL_SoundStream { - static const ALuint sNumBuffers = 6; static const ALfloat sBufferLength; private: ALuint mSource; - ALuint mBuffers[sNumBuffers]; + std::array mBuffers; ALint mCurrentBufIdx; ALenum mFormat; @@ -392,16 +391,17 @@ private: OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder) - : mSource(src), mBuffers{0}, mCurrentBufIdx(0), mFormat(AL_NONE), mSampleRate(0) + : mSource(src), mCurrentBufIdx(0), mFormat(AL_NONE), mSampleRate(0) , mBufferSize(0), mFrameSize(0), mSilence(0), mDecoder(std::move(decoder)) , mLoudnessAnalyzer(nullptr) { + mBuffers.fill(0); } OpenAL_SoundStream::~OpenAL_SoundStream() { if(mBuffers[0] && alIsBuffer(mBuffers[0])) - alDeleteBuffers(sNumBuffers, mBuffers); + alDeleteBuffers(mBuffers.size(), mBuffers.data()); alGetError(); mDecoder->close(); @@ -409,7 +409,7 @@ OpenAL_SoundStream::~OpenAL_SoundStream() bool OpenAL_SoundStream::init(bool getLoudnessData) { - alGenBuffers(sNumBuffers, mBuffers); + alGenBuffers(mBuffers.size(), mBuffers.data()); ALenum err = getALError(); if(err != AL_NO_ERROR) return false; @@ -542,10 +542,10 @@ ALint OpenAL_SoundStream::refillQueue() ALint queued; alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); - if(!mIsFinished && (ALuint)queued < sNumBuffers) + if(!mIsFinished && (ALuint)queued < mBuffers.size()) { std::vector data(mBufferSize); - for(;!mIsFinished && (ALuint)queued < sNumBuffers;++queued) + for(;!mIsFinished && (ALuint)queued < mBuffers.size();++queued) { size_t got = mDecoder->read(&data[0], data.size()); if(got < data.size()) @@ -561,7 +561,7 @@ ALint OpenAL_SoundStream::refillQueue() ALuint bufid = mBuffers[mCurrentBufIdx]; alBufferData(bufid, mFormat, &data[0], data.size(), mSampleRate); alSourceQueueBuffers(mSource, 1, &bufid); - mCurrentBufIdx = (mCurrentBufIdx+1) % sNumBuffers; + mCurrentBufIdx = (mCurrentBufIdx+1) % mBuffers.size(); } } } From 2abf7f1752bfd06530425c5d33d6ae73653d90be Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 15 Sep 2017 12:19:12 -0400 Subject: [PATCH 066/505] Remove unnecessary cache dump --- components/terrain/world.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 22c65b62c..335bb496b 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -77,7 +77,6 @@ void World::updateTextureFiltering() void World::clearAssociatedCaches() { - mTextureManager->clearCache(); mChunkManager->clearCache(); } From 44738e1141464605104db17d596a38f6905e2e24 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 11 Sep 2017 20:49:22 +0400 Subject: [PATCH 067/505] Clear player fields upon reload (bug #2639) --- apps/openmw/mwworld/player.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index d233fba6f..19bf7f55e 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -276,6 +276,29 @@ namespace MWWorld mAutoMove = false; mForwardBackward = 0; mTeleported = false; + mAttackingOrSpell = false; + mCurrentCrimeId = -1; + mPaidCrimeId = -1; + mLastKnownExteriorPosition = osg::Vec3f(0,0,0); + + for (int i=0; i Date: Sat, 16 Sep 2017 15:04:15 +0100 Subject: [PATCH 068/505] Update differences.rst --- docs/source/reference/modding/differences.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/reference/modding/differences.rst b/docs/source/reference/modding/differences.rst index e7cac15d0..d492dc542 100644 --- a/docs/source/reference/modding/differences.rst +++ b/docs/source/reference/modding/differences.rst @@ -12,14 +12,14 @@ OpenMW is designed to be able to use all the normal Morrowind mod files such as Multiple Data Folders --------------------- -The largest difference between OpenMW and Morrowind in terms of data structure is OpenMW's support of multiple data folders. This has many advantages, especially when it comes to unistalling mods and preventing unintentional overwrites of files. +The largest difference between OpenMW and Morrowind in terms of data structure is OpenMW's support of multiple data folders. This has many advantages, especially when it comes to uninstalling mods and preventing unintentional overwrites of files. .. warning:: Most mods can still be installed into the root OpenMW data folder, but this is not recommended. To install mods via this new feature: -#. Open ``openmw.cfg`` with your preffered text editor. It is located as described in :doc:`paths` and *not* in your OpenMW root directory. +#. Open ``openmw.cfg`` with your preferred text editor. It is located as described in :doc:`paths` and *not* in your OpenMW root directory. #. Find or search for ``data=``. This is located very near the bottom of the file. #. Add a new line below this line and make a new entry of the format ``data="path/to/your/mod"`` #. Make as many of these entries as you need for each mod folder you want to include. From f594eda5744a7cede847a262a0cd61b4849778ae Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 16 Sep 2017 23:04:54 +0000 Subject: [PATCH 069/505] Reset attackStrength when starting a new attack (Fixes #3935) --- apps/openmw/mwmechanics/character.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2f645279a..bfe8812e6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1216,6 +1216,7 @@ bool CharacterController::updateWeaponState() if(mUpperBodyState == UpperCharState_WeapEquiped && (mHitState == CharState_None || mHitState == CharState_Block)) { MWBase::Environment::get().getWorld()->breakInvisibility(mPtr); + mAttackStrength = 0; if(mWeaponType == WeapType_Spell) { // Unset casting flag, otherwise pressing the mouse button down would From acd6d9cd72cc4c24d552403a324a5e34a43c887b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Sep 2017 19:36:49 -0700 Subject: [PATCH 070/505] Try opening the default device fallback in OpenAL_Output --- apps/openmw/mwsound/openal_output.cpp | 36 +++++++++++++------------ apps/openmw/mwsound/soundmanagerimp.cpp | 19 +++---------- 2 files changed, 23 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 64aa1aff7..85a7d13ba 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -595,24 +595,24 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname deinit(); mDevice = alcOpenDevice(devname.c_str()); - if(!mDevice) + if(!mDevice && !devname.empty()) { - if(devname.empty()) - std::cerr<< "Failed to open default audio device" <removeAll(); - for(size_t i = 0;i < mFreeSources.size();i++) - alDeleteSources(1, &mFreeSources[i]); + std::for_each(mFreeSources.cbegin(), mFreeSources.cend(), + [](ALuint source) -> void + { alDeleteSources(1, &source); } + ); mFreeSources.clear(); if(mEffectSlot) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 0b6d8ff34..03bff89b4 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -26,11 +26,7 @@ #include "sound.hpp" #include "openal_output.hpp" -#define SOUND_OUT "OpenAL" #include "ffmpeg_decoder.hpp" -#ifndef SOUND_IN -#define SOUND_IN "FFmpeg" -#endif namespace MWSound @@ -60,6 +56,8 @@ namespace MWSound , mUnderwaterSound(nullptr) , mNearWaterSound(nullptr) { + std::cout<< "Initializing sound..." < 0 ? HrtfMode::Enable : HrtfMode::Disable; - std::cout << "Sound output: " << SOUND_OUT << std::endl; - std::cout << "Sound decoder: " << SOUND_IN << std::endl; - std::vector names = mOutput->enumerate(); std::cout <<"Enumerated output devices:\n"; std::for_each(names.cbegin(), names.cend(), @@ -103,15 +98,9 @@ namespace MWSound std::cout.flush(); std::string devname = Settings::Manager::getString("device", "Sound"); - bool inited = mOutput->init(devname, hrtfname, hrtfmode); - if(!inited && !devname.empty()) - { - std::cerr<< "Failed to initialize device \""<init(std::string(), hrtfname, hrtfmode); - } - if(!inited) + if(!mOutput->init(devname, hrtfname, hrtfmode)) { - std::cerr<< "Failed to initialize default audio device, sound disabled" < Date: Fri, 15 Sep 2017 21:21:49 -0700 Subject: [PATCH 071/505] Print a bit more information for sound initialization --- apps/openmw/mwsound/openal_output.cpp | 13 +++++++++++++ apps/openmw/mwsound/soundmanagerimp.cpp | 19 ++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 85a7d13ba..a6d3e4b12 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -594,6 +594,8 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname { deinit(); + std::cout<< "Initializing OpenAL..." < 0 ? HrtfMode::Enable : HrtfMode::Disable; + std::string devname = Settings::Manager::getString("device", "Sound"); + if(!mOutput->init(devname, hrtfname, hrtfmode)) + { + std::cerr<< "Failed to initialize audio output, sound disabled" < names = mOutput->enumerate(); std::cout <<"Enumerated output devices:\n"; std::for_each(names.cbegin(), names.cend(), @@ -97,13 +105,6 @@ namespace MWSound ); std::cout.flush(); - std::string devname = Settings::Manager::getString("device", "Sound"); - if(!mOutput->init(devname, hrtfname, hrtfmode)) - { - std::cerr<< "Failed to initialize audio output, sound disabled" <enumerateHrtf(); if(!names.empty()) { From 1e729e8da96b9ec08046c899aa25eccaf94beecf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 16 Sep 2017 01:56:58 -0700 Subject: [PATCH 072/505] Avoid more explicit loops --- apps/openmw/mwsound/soundmanagerimp.cpp | 158 ++++++++++-------------- 1 file changed, 65 insertions(+), 93 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 2a65be737..f50b3f2fb 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -99,20 +99,16 @@ namespace MWSound std::vector names = mOutput->enumerate(); std::cout <<"Enumerated output devices:\n"; - std::for_each(names.cbegin(), names.cend(), - [](const std::string &name) -> void - { std::cout <<" "<enumerateHrtf(); if(!names.empty()) { std::cout<< "Enumerated HRTF names:\n"; - std::for_each(names.cbegin(), names.cend(), - [](const std::string &name) -> void - { std::cout<< " "<begin(); - for(;sfxiter != mSoundBuffers->end();++sfxiter) + for(Sound_Buffer &sfx : *mSoundBuffers) { - if(sfxiter->mHandle) - mOutput->unloadSound(sfxiter->mHandle); - sfxiter->mHandle = 0; + if(sfx.mHandle) + mOutput->unloadSound(sfx.mHandle); + sfx.mHandle = 0; } mUnusedBuffers.clear(); mOutput.reset(); @@ -668,11 +663,10 @@ namespace MWSound if(snditer != mActiveSounds.end()) { Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); - SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); - for(;sndidx != snditer->second.end();++sndidx) + for(SoundBufferRefPair &snd : snditer->second) { - if(sndidx->second == sfx) - mOutput->finishSound(sndidx->first); + if(snd.second == sfx) + mOutput->finishSound(snd.first); } } } @@ -682,33 +676,28 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); - for(;sndidx != snditer->second.end();++sndidx) - mOutput->finishSound(sndidx->first); + for(SoundBufferRefPair &snd : snditer->second) + mOutput->finishSound(snd.first); } + SaySoundMap::iterator sayiter = mActiveSaySounds.find(ptr); + if(sayiter != mActiveSaySounds.end()) + mOutput->finishStream(sayiter->second); } void SoundManager::stopSound(const MWWorld::CellStore *cell) { - SoundMap::iterator snditer = mActiveSounds.begin(); - for(;snditer != mActiveSounds.end();++snditer) + for(SoundMap::value_type &snd : mActiveSounds) { - if(snditer->first != MWWorld::ConstPtr() && - snditer->first != MWMechanics::getPlayer() && - snditer->first.getCell() == cell) + if(!snd.first.isEmpty() && snd.first != MWMechanics::getPlayer() && snd.first.getCell() == cell) { - SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); - for(;sndidx != snditer->second.end();++sndidx) - mOutput->finishSound(sndidx->first); + for(SoundBufferRefPair &sndbuf : snd.second) + mOutput->finishSound(sndbuf.first); } } - SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); - for(;sayiter != mActiveSaySounds.end();++sayiter) + for(SaySoundMap::value_type &snd : mActiveSaySounds) { - if(sayiter->first != MWWorld::ConstPtr() && - sayiter->first != MWMechanics::getPlayer() && - sayiter->first.getCell() == cell) - mOutput->finishStream(sayiter->second); + if(!snd.first.isEmpty() && snd.first != MWMechanics::getPlayer() && snd.first.getCell() == cell) + mOutput->finishStream(snd.second); } } @@ -718,11 +707,10 @@ namespace MWSound if(snditer != mActiveSounds.end()) { Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); - SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); - for(;sndidx != snditer->second.end();++sndidx) + for(SoundBufferRefPair &sndbuf : snditer->second) { - if(sndidx->second == sfx) - mOutput->finishSound(sndidx->first); + if(sndbuf.second == sfx) + mOutput->finishSound(sndbuf.first); } } } @@ -734,11 +722,10 @@ namespace MWSound if(snditer != mActiveSounds.end()) { Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); - SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); - for(;sndidx != snditer->second.end();++sndidx) + for(SoundBufferRefPair &sndbuf : snditer->second) { - if(sndidx->second == sfx) - sndidx->first->setFadeout(duration); + if(sndbuf.second == sfx) + sndbuf.first->setFadeout(duration); } } } @@ -749,12 +736,10 @@ namespace MWSound if(snditer != mActiveSounds.end()) { Sound_Buffer *sfx = lookupSound(Misc::StringUtils::lowerCase(soundId)); - SoundBufferRefPairList::const_iterator sndidx = snditer->second.begin(); - for(;sndidx != snditer->second.end();++sndidx) - { - if(sndidx->second == sfx && mOutput->isSoundPlaying(sndidx->first)) - return true; - } + return std::find_if(snditer->second.cbegin(), snditer->second.cend(), + [this,sfx](const SoundBufferRefPair &snd) -> bool + { return snd.second == sfx && mOutput->isSoundPlaying(snd.first); } + ) != snditer->second.cend(); } return false; } @@ -813,10 +798,8 @@ namespace MWSound if(total == 0) { - std::for_each(regn->mSoundList.cbegin(), regn->mSoundList.cend(), - [](const ESM::Region::SoundRef &sndref) -> void - { total += (int)sndref.mChance; } - ); + for(const ESM::Region::SoundRef &sndref : regn->mSoundList) + total += (int)sndref.mChance; if(total == 0) return; } @@ -824,20 +807,15 @@ namespace MWSound int r = Misc::Rng::rollDice(total); int pos = 0; - std::find_if_not(regn->mSoundList.cbegin(), regn->mSoundList.cend(), - [&pos, r, this](const ESM::Region::SoundRef &sndref) -> bool + for(const ESM::Region::SoundRef &sndref : regn->mSoundList) + { + if(r - pos < sndref.mChance) { - if(r - pos < sndref.mChance) - { - playSound(sndref.mSound.toString(), 1.0f, 1.0f); - // Played this sound, stop iterating - return false; - } - pos += sndref.mChance; - // Not this sound, keep iterating - return true; + playSound(sndref.mSound.toString(), 1.0f, 1.0f); + break; } - ); + pos += sndref.mChance; + } } void SoundManager::updateWaterSound(float /*duration*/) @@ -1125,28 +1103,23 @@ namespace MWSound if(!mOutput->isInitialized()) return; mOutput->startUpdate(); - SoundMap::iterator snditer = mActiveSounds.begin(); - for(;snditer != mActiveSounds.end();++snditer) + for(SoundMap::value_type &snd : mActiveSounds) { - SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); - for(;sndidx != snditer->second.end();++sndidx) + for(SoundBufferRefPair &sndbuf : snd.second) { - Sound *sound = sndidx->first; + Sound *sound = sndbuf.first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); mOutput->updateSound(sound); } } - SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); - for(;sayiter != mActiveSaySounds.end();++sayiter) + for(SaySoundMap::value_type &snd : mActiveSaySounds) { - Stream *sound = sayiter->second; + Stream *sound = snd.second; sound->setBaseVolume(volumeFromType(sound->getPlayType())); mOutput->updateStream(sound); } - TrackList::iterator trkiter = mActiveTracks.begin(); - for(;trkiter != mActiveTracks.end();++trkiter) + for(Stream *sound : mActiveTracks) { - Stream *sound = *trkiter; sound->setBaseVolume(volumeFromType(sound->getPlayType())); mOutput->updateStream(sound); } @@ -1252,36 +1225,35 @@ namespace MWSound void SoundManager::clear() { - SoundMap::iterator snditer = mActiveSounds.begin(); - for(;snditer != mActiveSounds.end();++snditer) + stopMusic(); + + for(SoundMap::value_type &snd : mActiveSounds) { - SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); - for(;sndidx != snditer->second.end();++sndidx) + for(SoundBufferRefPair &sndbuf : snd.second) { - mOutput->finishSound(sndidx->first); - mUnusedSounds.push_back(sndidx->first); - Sound_Buffer *sfx = sndidx->second; + mOutput->finishSound(sndbuf.first); + mUnusedSounds.push_back(sndbuf.first); + Sound_Buffer *sfx = sndbuf.second; if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sfx); } } mActiveSounds.clear(); - SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); - for(;sayiter != mActiveSaySounds.end();++sayiter) + mUnderwaterSound = nullptr; + mNearWaterSound = nullptr; + + for(SaySoundMap::value_type &snd : mActiveSaySounds) { - mOutput->finishStream(sayiter->second); - mUnusedStreams.push_back(sayiter->second); + mOutput->finishStream(snd.second); + mUnusedStreams.push_back(snd.second); } mActiveSaySounds.clear(); - TrackList::iterator trkiter = mActiveTracks.begin(); - for(;trkiter != mActiveTracks.end();++trkiter) + + for(Stream *sound : mActiveTracks) { - mOutput->finishStream(*trkiter); - mUnusedStreams.push_back(*trkiter); + mOutput->finishStream(sound); + mUnusedStreams.push_back(sound); } mActiveTracks.clear(); - mUnderwaterSound = nullptr; - mNearWaterSound = nullptr; - stopMusic(); } } From 4b448c74d24023c9f43c952335829c3c287061f7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 16 Sep 2017 03:19:06 -0700 Subject: [PATCH 073/505] Use range-for loops instead of for_each --- apps/openmw/mwsound/openal_output.cpp | 152 +++++++++++--------------- 1 file changed, 66 insertions(+), 86 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index a6d3e4b12..77a14a398 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -192,12 +192,11 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) { AL_FORMAT_STEREO8, ChannelConfig_Stereo, SampleType_UInt8 }, }}; - auto fmt = std::find_if(fmtlist.cbegin(), fmtlist.cend(), - [chans,type](const FormatEntry &fmt) -> bool - { return fmt.chans == chans && fmt.type == type; } - ); - if(fmt != fmtlist.cend()) - return fmt->format; + for(auto &fmt : fmtlist) + { + if(fmt.chans == chans && fmt.type == type) + return fmt.format; + } if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { @@ -209,18 +208,16 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) { "AL_FORMAT_71CHN16", ChannelConfig_7point1, SampleType_Int16 }, { "AL_FORMAT_71CHN8", ChannelConfig_7point1, SampleType_UInt8 }, }}; - ALenum format = AL_NONE; - std::find_if(mcfmtlist.cbegin(), mcfmtlist.cend(), - [&format,chans,type](const FormatEntryExt &fmt) -> bool + for(auto &fmt : mcfmtlist) + { + if(fmt.chans == chans && fmt.type == type) { - if(fmt.chans == chans && fmt.type == type) - format = alGetEnumValue(fmt.name); - return format != 0 && format != -1; + ALenum format = alGetEnumValue(fmt.name); + if(format != 0 && format != -1) + return format; } - ); - if(format != 0 && format != -1) - return format; + } } if(alIsExtensionPresent("AL_EXT_FLOAT32")) { @@ -228,18 +225,16 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) { "AL_FORMAT_MONO_FLOAT32", ChannelConfig_Mono, SampleType_Float32 }, { "AL_FORMAT_STEREO_FLOAT32", ChannelConfig_Stereo, SampleType_Float32 }, }}; - ALenum format = AL_NONE; - std::find_if(fltfmtlist.cbegin(), fltfmtlist.cend(), - [&format,chans,type](const FormatEntryExt &fmt) -> bool + for(auto &fmt : fltfmtlist) + { + if(fmt.chans == chans && fmt.type == type) { - if(fmt.chans == chans && fmt.type == type) - format = alGetEnumValue(fmt.name); - return format != 0 && format != -1; + ALenum format = alGetEnumValue(fmt.name); + if(format != 0 && format != -1) + return format; } - ); - if(format != 0 && format != -1) - return format; + } if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { @@ -249,16 +244,15 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) { "AL_FORMAT_71CHN32", ChannelConfig_7point1, SampleType_Float32 }, }}; - std::find_if(fltmcfmtlist.cbegin(), fltmcfmtlist.cend(), - [&format,chans,type](const FormatEntryExt &fmt) -> bool + for(auto &fmt : fltmcfmtlist) + { + if(fmt.chans == chans && fmt.type == type) { - if(fmt.chans == chans && fmt.type == type) - format = alGetEnumValue(fmt.name); - return format != 0 && format != -1; + ALenum format = alGetEnumValue(fmt.name); + if(format != 0 && format != -1) + return format; } - ); - if(format != 0 && format != -1) - return format; + } } } @@ -547,11 +541,11 @@ ALint OpenAL_SoundStream::refillQueue() std::vector data(mBufferSize); for(;!mIsFinished && (ALuint)queued < mBuffers.size();++queued) { - size_t got = mDecoder->read(&data[0], data.size()); + size_t got = mDecoder->read(data.data(), data.size()); if(got < data.size()) { mIsFinished = true; - std::memset(&data[got], mSilence, data.size()-got); + std::fill(data.begin()+got, data.end(), mSilence); } if(got > 0) { @@ -559,7 +553,7 @@ ALint OpenAL_SoundStream::refillQueue() mLoudnessAnalyzer->analyzeLoudness(data); ALuint bufid = mBuffers[mCurrentBufIdx]; - alBufferData(bufid, mFormat, &data[0], data.size(), mSampleRate); + alBufferData(bufid, mFormat, data.data(), data.size(), mSampleRate); alSourceQueueBuffers(mSource, 1, &bufid); mCurrentBufIdx = (mCurrentBufIdx+1) % mBuffers.size(); } @@ -837,10 +831,8 @@ void OpenAL_Output::deinit() { mStreamThread->removeAll(); - std::for_each(mFreeSources.cbegin(), mFreeSources.cend(), - [](ALuint source) -> void - { alDeleteSources(1, &source); } - ); + for(ALuint source : mFreeSources) + alDeleteSources(1, &source); mFreeSources.clear(); if(mEffectSlot) @@ -1383,23 +1375,19 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi if(mWaterFilter) { ALuint filter = (env == Env_Underwater) ? mWaterFilter : AL_FILTER_NULL; - std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(), - [filter](const SoundVec::value_type &item) -> void - { - if(item->getUseEnv()) - alSourcei(GET_PTRID(item->mHandle), AL_DIRECT_FILTER, filter); - } - ); - std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(), - [filter](const StreamVec::value_type &item) -> void - { - if(item->getUseEnv()) - alSourcei( - reinterpret_cast(item->mHandle)->mSource, - AL_DIRECT_FILTER, filter - ); - } - ); + for(Sound *sound : mActiveSounds) + { + if(sound->getUseEnv()) + alSourcei(GET_PTRID(sound->mHandle), AL_DIRECT_FILTER, filter); + } + for(Stream *sound : mActiveStreams) + { + if(sound->getUseEnv()) + alSourcei( + reinterpret_cast(sound->mHandle)->mSource, + AL_DIRECT_FILTER, filter + ); + } } // Update the environment effect if(mEffectSlot) @@ -1418,23 +1406,19 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi void OpenAL_Output::pauseSounds(int types) { std::vector sources; - std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(), - [types,&sources](const SoundVec::value_type &sound) -> void - { - if(sound && sound->mHandle && (types&sound->getPlayType())) - sources.push_back(GET_PTRID(sound->mHandle)); - } - ); - std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(), - [types,&sources](const StreamVec::value_type &stream) -> void + for(Sound *sound : mActiveSounds) + { + if((types&sound->getPlayType())) + sources.push_back(GET_PTRID(sound->mHandle)); + } + for(Stream *sound : mActiveStreams) + { + if((types&sound->getPlayType())) { - if(stream && stream->mHandle && (types&stream->getPlayType())) - { - OpenAL_SoundStream *strm = reinterpret_cast(stream->mHandle); - sources.push_back(strm->mSource); - } + OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); + sources.push_back(stream->mSource); } - ); + } if(!sources.empty()) { alSourcePausev(sources.size(), sources.data()); @@ -1445,23 +1429,19 @@ void OpenAL_Output::pauseSounds(int types) void OpenAL_Output::resumeSounds(int types) { std::vector sources; - std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(), - [types,&sources](const SoundVec::value_type &sound) -> void - { - if(sound && sound->mHandle && (types&sound->getPlayType())) - sources.push_back(GET_PTRID(sound->mHandle)); - } - ); - std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(), - [types,&sources](const StreamVec::value_type &stream) -> void + for(Sound *sound : mActiveSounds) + { + if((types&sound->getPlayType())) + sources.push_back(GET_PTRID(sound->mHandle)); + } + for(Stream *sound : mActiveStreams) + { + if((types&sound->getPlayType())) { - if(stream && stream->mHandle && (types&stream->getPlayType())) - { - OpenAL_SoundStream *strm = reinterpret_cast(stream->mHandle); - sources.push_back(strm->mSource); - } + OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); + sources.push_back(stream->mSource); } - ); + } if(!sources.empty()) { alSourcePlayv(sources.size(), sources.data()); From 5c53ee42a10d8037420f442b65b2ac9e7045ad82 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 16 Sep 2017 03:48:41 -0700 Subject: [PATCH 074/505] Prepare all Sound_Buffers when retrieving the first one --- apps/openmw/mwsound/soundmanagerimp.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index f50b3f2fb..949b724f1 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -185,9 +185,23 @@ namespace MWSound // minRange, and maxRange), and ensure it's ready for use. Sound_Buffer *SoundManager::loadSound(const std::string &soundId) { +#ifdef __GNUC__ +#define LIKELY(x) __builtin_expect((bool)(x), true) +#define UNLIKELY(x) __builtin_expect((bool)(x), false) +#else +#define LIKELY(x) (bool)(x) +#define UNLIKELY(x) (bool)(x) +#endif + if(UNLIKELY(mBufferNameMap.empty())) + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + for(const ESM::Sound &sound : world->getStore().get()) + insertSound(Misc::StringUtils::lowerCase(sound.mId), &sound); + } + Sound_Buffer *sfx; NameBufferMap::const_iterator snd = mBufferNameMap.find(soundId); - if(snd != mBufferNameMap.end()) + if(LIKELY(snd != mBufferNameMap.end())) sfx = snd->second; else { @@ -196,6 +210,8 @@ namespace MWSound if(!sound) return nullptr; sfx = insertSound(soundId, sound); } +#undef LIKELY +#undef UNLIKELY if(!sfx->mHandle) { From 41bb35655bf6da3de0b2bf8ff546dac2ce1dcec2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 16 Sep 2017 04:24:01 -0700 Subject: [PATCH 075/505] Avoid an extra call to get the buffer size --- apps/openmw/mwsound/openal_output.cpp | 28 +++++++++++-------------- apps/openmw/mwsound/openal_output.hpp | 5 ++--- apps/openmw/mwsound/sound_output.hpp | 5 ++--- apps/openmw/mwsound/soundmanagerimp.cpp | 9 ++++---- 4 files changed, 21 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 77a14a398..3fb1c1c13 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -941,7 +941,7 @@ void OpenAL_Output::setHrtf(const std::string &hrtfname, HrtfMode hrtfmode) } -Sound_Handle OpenAL_Output::loadSound(const std::string &fname) +std::pair OpenAL_Output::loadSound(const std::string &fname) { getALError(); @@ -966,27 +966,31 @@ Sound_Handle OpenAL_Output::loadSound(const std::string &fname) decoder->getInfo(&srate, &chans, &type); format = getALFormat(chans, type); - if(!format) return nullptr; + if(!format) return std::make_pair(nullptr, 0); decoder->readAll(data); decoder->close(); + ALint size; ALuint buf = 0; alGenBuffers(1, &buf); - alBufferData(buf, format, &data[0], data.size(), srate); + alBufferData(buf, format, data.data(), data.size(), srate); + alGetBufferi(buf, AL_SIZE, &size); if(getALError() != AL_NO_ERROR) { if(buf && alIsBuffer(buf)) alDeleteBuffers(1, &buf); getALError(); - return nullptr; + return std::make_pair(nullptr, 0); } - return MAKE_PTRID(buf); + return std::make_pair(MAKE_PTRID(buf), size); } -void OpenAL_Output::unloadSound(Sound_Handle data) +size_t OpenAL_Output::unloadSound(Sound_Handle data) { ALuint buffer = GET_PTRID(data); + if(!buffer) return 0; + // Make sure no sources are playing this buffer before unloading it. SoundVec::const_iterator iter = mActiveSounds.begin(); for(;iter != mActiveSounds.end();++iter) @@ -1003,19 +1007,11 @@ void OpenAL_Output::unloadSound(Sound_Handle data) alSourcei(source, AL_BUFFER, 0); } } - alDeleteBuffers(1, &buffer); - getALError(); -} - -size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const -{ - ALuint buffer = GET_PTRID(data); ALint size = 0; - alGetBufferi(buffer, AL_SIZE, &size); + alDeleteBuffers(1, &buffer); getALError(); - - return (ALuint)size; + return size; } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 8a7b7b3b8..afc869733 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -66,9 +66,8 @@ namespace MWSound virtual std::vector enumerateHrtf(); virtual void setHrtf(const std::string &hrtfname, HrtfMode hrtfmode); - virtual Sound_Handle loadSound(const std::string &fname); - virtual void unloadSound(Sound_Handle data); - virtual size_t getSoundDataSize(Sound_Handle data) const; + virtual std::pair loadSound(const std::string &fname); + virtual size_t unloadSound(Sound_Handle data); virtual bool playSound(Sound *sound, Sound_Handle data, float offset); virtual bool playSound3D(Sound *sound, Sound_Handle data, float offset); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index ad18e0d40..871562dc0 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -36,9 +36,8 @@ namespace MWSound virtual std::vector enumerateHrtf() = 0; virtual void setHrtf(const std::string &hrtfname, HrtfMode hrtfmode) = 0; - virtual Sound_Handle loadSound(const std::string &fname) = 0; - virtual void unloadSound(Sound_Handle data) = 0; - virtual size_t getSoundDataSize(Sound_Handle data) const = 0; + virtual std::pair loadSound(const std::string &fname) = 0; + virtual size_t unloadSound(Sound_Handle data) = 0; virtual bool playSound(Sound *sound, Sound_Handle data, float offset) = 0; virtual bool playSound3D(Sound *sound, Sound_Handle data, float offset) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 949b724f1..ac87a2f06 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -215,10 +215,11 @@ namespace MWSound if(!sfx->mHandle) { - sfx->mHandle = mOutput->loadSound(sfx->mResourceName); + size_t size; + std::tie(sfx->mHandle, size) = mOutput->loadSound(sfx->mResourceName); if(!sfx->mHandle) return nullptr; - mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle); + mBufferCacheSize += size; if(mBufferCacheSize > mBufferCacheMax) { do { @@ -229,8 +230,8 @@ namespace MWSound } Sound_Buffer *unused = mUnusedBuffers.back(); - mBufferCacheSize -= mOutput->getSoundDataSize(unused->mHandle); - mOutput->unloadSound(unused->mHandle); + size = mOutput->unloadSound(unused->mHandle); + mBufferCacheSize -= size; unused->mHandle = 0; mUnusedBuffers.pop_back(); From 19d034f3705afb10064412f984a753af02085bc2 Mon Sep 17 00:00:00 2001 From: David Walley <31402617+loriel2@users.noreply.github.com> Date: Sun, 17 Sep 2017 07:43:26 +0100 Subject: [PATCH 076/505] Docs CS-Manual - tour - add ring to chest Extend the ring tutorial in the CS-Manual to put the ring in a chest. Images omitted pending decisions on style and where to store them --- docs/source/manuals/openmw-cs/tour.rst | 39 ++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/docs/source/manuals/openmw-cs/tour.rst b/docs/source/manuals/openmw-cs/tour.rst index fedd42462..923b1af36 100644 --- a/docs/source/manuals/openmw-cs/tour.rst +++ b/docs/source/manuals/openmw-cs/tour.rst @@ -304,3 +304,42 @@ already checked. Load a game and make your way to Seyda Neen - or start a new ga Check whether Arrille has one (or more) for sale, and whether Fargoth give you one when you return his healing ring. + +Placing in a chest +****************** + +For this example we will use the small chest intended for lockpick practice, +located in the Census and Excise Office in Seyda Neen. + +FIrst we need the ID of the chest - this can be obtained either by clicking on it in the console +in the game, or by applying a similar process in the CS - + +World/Cells + +Select "Seyda Neen, Census and Excise Office" + +Right-click and select "View" + +Use mouse wheel to zoon in/out, and mouse plus WASD keys to navigate + +Click on the small chest + +Either way, you should find the ID, which is "chest_small_02_lockprac". + +Open the Objects table (World/Objects) and scroll down to find this item. + +Alternatively use the Edit/Search facility, selecting ID rather than text, +enter "lockprac" (without the quotes) into the search box, press "Search", +which should return two rows, then select the "Container" one rather than the "Instance" + +Right-click and "Edit Record". + +Right-click the "Content" section and select "Add a row" + +Set the Item ID of the new row to be your new ring - simplest way is probably to open the Objects +table if it's not already open, sort on the "Modified" column which should bring the ring, +with its status of "Added" to the top, then drag and drop to the chest row. + +Increase the Count to 1. + +Save the addon, then test to ensure it works - e.g. start a new game and lockpick the chest. From 6b56f25f9ec5b7c58f055f0195ca4ff0397b3fc3 Mon Sep 17 00:00:00 2001 From: David Walley <31402617+loriel2@users.noreply.github.com> Date: Sun, 17 Sep 2017 07:47:27 +0100 Subject: [PATCH 077/505] Update tour.rst --- docs/source/manuals/openmw-cs/tour.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/manuals/openmw-cs/tour.rst b/docs/source/manuals/openmw-cs/tour.rst index 923b1af36..38915c95b 100644 --- a/docs/source/manuals/openmw-cs/tour.rst +++ b/docs/source/manuals/openmw-cs/tour.rst @@ -311,7 +311,7 @@ Placing in a chest For this example we will use the small chest intended for lockpick practice, located in the Census and Excise Office in Seyda Neen. -FIrst we need the ID of the chest - this can be obtained either by clicking on it in the console +First we need the ID of the chest - this can be obtained either by clicking on it in the console in the game, or by applying a similar process in the CS - World/Cells @@ -320,7 +320,7 @@ Select "Seyda Neen, Census and Excise Office" Right-click and select "View" -Use mouse wheel to zoon in/out, and mouse plus WASD keys to navigate +Use mouse wheel to zoom in/out, and mouse plus WASD keys to navigate Click on the small chest From 5e60fb7c10557864e06ab31f0f0de006f5f57f36 Mon Sep 17 00:00:00 2001 From: PlutonicOverkill Date: Sun, 17 Sep 2017 21:09:28 +1200 Subject: [PATCH 078/505] Fix preferences pane width --- apps/opencs/view/prefs/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp index 7f901c470..960ca74bc 100644 --- a/apps/opencs/view/prefs/dialogue.cpp +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -24,7 +24,7 @@ void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main) main->addWidget (list); - QFontMetrics metrics (QApplication::font()); + QFontMetrics metrics (QApplication::font(list)); int maxWidth = 1; From 3fb3c4c20f60e39903421f8b5aed0462192b994f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Sep 2017 14:06:01 +0400 Subject: [PATCH 079/505] Add scrollbar to a birth effect lists (bug #4105) --- apps/openmw/mwgui/birth.cpp | 8 +++++++- apps/openmw/mwgui/birth.hpp | 2 +- files/mygui/openmw_chargen_birth.layout | 4 +++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 69fb2c462..ecc011fc1 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -244,6 +245,11 @@ namespace MWGui } } } - } + // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden + mSpellArea->setVisibleVScroll(false); + mSpellArea->setCanvasSize(MyGUI::IntSize(mSpellArea->getWidth(), std::max(mSpellArea->getHeight(), coord.top))); + mSpellArea->setVisibleVScroll(true); + mSpellArea->setViewOffset(MyGUI::IntPoint(0, 0)); + } } diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index 0a84bb4e9..c8ec9da09 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -47,7 +47,7 @@ namespace MWGui void updateSpells(); MyGUI::ListBox* mBirthList; - MyGUI::Widget* mSpellArea; + MyGUI::ScrollView* mSpellArea; MyGUI::ImageBox* mBirthImage; std::vector mSpellItems; diff --git a/files/mygui/openmw_chargen_birth.layout b/files/mygui/openmw_chargen_birth.layout index 2375e5277..d93249c03 100644 --- a/files/mygui/openmw_chargen_birth.layout +++ b/files/mygui/openmw_chargen_birth.layout @@ -11,7 +11,9 @@ - + + + > From 4bb349a5259d534c34ef2017d2f941c5be838045 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Sep 2017 14:34:27 +0400 Subject: [PATCH 080/505] Use default 0 precision in the float formatting (bug #4096) --- components/misc/messageformatparser.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/misc/messageformatparser.cpp b/components/misc/messageformatparser.cpp index bfd8dd562..3a35c83ea 100644 --- a/components/misc/messageformatparser.cpp +++ b/components/misc/messageformatparser.cpp @@ -34,21 +34,19 @@ namespace Misc if (i < m.size()) { - int precision = 0; - bool precisionSet = false; + int precision = -1; if (m[i] == '.') { + precision = 0; while (++i < m.size() && m[i] >= '0' && m[i] <= '9') { precision = precision * 10 + (m[i] - '0'); - precisionSet = true; } } if (i < m.size()) { width = (widthSet) ? width : -1; - precision = (precisionSet) ? precision : -1; if (m[i] == 'S' || m[i] == 's') visitedPlaceholder(StringPlaceholder, pad, width, precision); From 5a5cb1a160d65b9b1d84a65bece4a7626daab3ec Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 17 Sep 2017 14:09:29 +0100 Subject: [PATCH 081/505] Check death counts are for valid actors before loading them --- apps/openmw/mwmechanics/actors.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index baa2470da..673304d30 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1767,9 +1767,12 @@ namespace MWMechanics while (reader.isNextSub("ID__")) { std::string id = reader.getHString(); - int count; - reader.getHNT (count, "COUN"); - mDeathCount[id] = count; + if (MWBase::Environment::get().getWorld()->getStore().find(id)) + { + int count; + reader.getHNT(count, "COUN"); + mDeathCount[id] = count; + } } } } From 10a0136b4aa561f1bba7bc42a24643523d364ce2 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Sep 2017 17:04:30 +0400 Subject: [PATCH 082/505] Cycle only through weapons which can be equipped by player (bug #4104) --- apps/openmw/mwgui/inventorywindow.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 6a2d3ff83..6eb0c554e 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -717,7 +717,9 @@ namespace MWGui lastId = item.getCellRef().getRefId(); - if (item.getClass().getTypeName() == typeid(ESM::Weapon).name() && isRightHandWeapon(item)) + if (item.getClass().getTypeName() == typeid(ESM::Weapon).name() && + isRightHandWeapon(item) && + item.getClass().canBeEquipped(item, player).first) { found = true; break; From 0be7e2a5a574354ebe7dc14c05ca22becf934315 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 17 Sep 2017 14:16:17 +0100 Subject: [PATCH 083/505] Fix really obvious flaw with ignored records not being skipped that I missed --- apps/openmw/mwmechanics/actors.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 673304d30..0cb7619db 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1767,12 +1767,10 @@ namespace MWMechanics while (reader.isNextSub("ID__")) { std::string id = reader.getHString(); + int count; + reader.getHNT(count, "COUN"); if (MWBase::Environment::get().getWorld()->getStore().find(id)) - { - int count; - reader.getHNT(count, "COUN"); mDeathCount[id] = count; - } } } } From fcb815f2c70df2b15088cf89a748bab7fd8e7f9d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 17 Sep 2017 23:03:02 +0000 Subject: [PATCH 084/505] Move fall height reset into PhysicsSystem (Fixes #4049) To avoid using onGround before it's actually set. --- apps/openmw/mwmechanics/character.cpp | 14 +------------- apps/openmw/mwphysics/physicssystem.cpp | 13 +++++++++---- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index bfe8812e6..75ecf00a8 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1704,20 +1704,11 @@ void CharacterController::update(float duration) if(sneak || inwater || flying) vec.z() = 0.0f; - if (inwater || flying) - cls.getCreatureStats(mPtr).land(); - bool inJump = true; if(!onground && !flying && !inwater) { // In the air (either getting up —ascending part of jump— or falling). - if (world->isSlowFalling(mPtr)) - { - // SlowFalling spell effect is active, do not keep previous fall height - cls.getCreatureStats(mPtr).land(); - } - forcestateupdate = (mJumpState != JumpState_InAir); jumpstate = JumpState_InAir; @@ -1763,7 +1754,7 @@ void CharacterController::update(float duration) } } } - else if(mJumpState == JumpState_InAir) + else if(mJumpState == JumpState_InAir && !inwater) { forcestateupdate = true; jumpstate = JumpState_Landing; @@ -1846,9 +1837,6 @@ void CharacterController::update(float duration) movestate = mMovementState; } - if (onground) - cls.getCreatureStats(mPtr).land(); - if(movestate != CharState_None && movestate != CharState_TurnLeft && movestate != CharState_TurnRight) clearAnimQueue(); diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 790ae2099..ee368ad24 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1404,14 +1404,16 @@ namespace MWPhysics // Slow fall reduces fall speed by a factor of (effect magnitude / 200) float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f)); + bool flying = world->isFlying(iter->first); + + bool wasOnGround = physicActor->getOnGround(); osg::Vec3f position = physicActor->getPosition(); float oldHeight = position.z(); bool positionChanged = false; for (int i=0; igetPtr(), physicActor, iter->second, physicsDt, - world->isFlying(iter->first), - waterlevel, slowFall, mCollisionWorld, mStandingCollisions); + flying, waterlevel, slowFall, mCollisionWorld, mStandingCollisions); if (position != physicActor->getPosition()) positionChanged = true; physicActor->setPosition(position); // always set even if unchanged to make sure interpolation is correct @@ -1424,8 +1426,11 @@ namespace MWPhysics float heightDiff = position.z() - oldHeight; - if (heightDiff < 0) - iter->first.getClass().getCreatureStats(iter->first).addToFallHeight(-heightDiff); + MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first); + if ((wasOnGround && physicActor->getOnGround()) || flying || world->isSwimming(iter->first) || slowFall < 1) + stats.land(); + else if (heightDiff < 0) + stats.addToFallHeight(-heightDiff); mMovementResults.push_back(std::make_pair(iter->first, interpolated)); } From 00034192dca8adc4f3f71ca6c2dc877bc3f6f7ce Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 17 Sep 2017 23:07:17 +0000 Subject: [PATCH 085/505] Fix player Ptr in RenderingManager not being updated on cell changes Noticed that 'setpos' wasn't working in the console with the player selected. --- apps/openmw/mwrender/renderingmanager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4d4a36f6c..5c22de12e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -530,8 +530,10 @@ namespace MWRender void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) { if(mPlayerAnimation.get()) + { + setupPlayer(ptr); mPlayerAnimation->updatePtr(ptr); - + } mCamera->attachTo(ptr); } @@ -834,6 +836,7 @@ namespace MWRender player.getRefData().setBaseNode(mPlayerNode); + mWater->removeEmitter(player); mWater->addEmitter(player); } From d294d7e284b74e9c9f16600371cf87b163546b34 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 17 Sep 2017 23:16:49 +0000 Subject: [PATCH 086/505] Fix possible fall damage when switching from falling to flying --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 75ecf00a8..cd14ec5a4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1754,7 +1754,7 @@ void CharacterController::update(float duration) } } } - else if(mJumpState == JumpState_InAir && !inwater) + else if(mJumpState == JumpState_InAir && !inwater && !flying) { forcestateupdate = true; jumpstate = JumpState_Landing; From 50d9d9f78f4f66b2721986bff2151f61282af216 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 17 Sep 2017 20:29:51 -0400 Subject: [PATCH 087/505] Get rid of some templates, exceptions instead of assert, and other small changes. --- apps/opencs/model/world/columnimp.cpp | 93 ++++++++++++++++++- apps/opencs/model/world/columnimp.hpp | 80 ++++------------ apps/opencs/model/world/columns.cpp | 2 +- apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/commands.cpp | 2 +- apps/opencs/model/world/data.cpp | 8 +- apps/opencs/view/world/landtexturecreator.cpp | 4 +- components/esm/loadland.cpp | 9 +- 8 files changed, 120 insertions(+), 80 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index 1ee7f8a03..6a19df0d5 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -1,7 +1,80 @@ #include "columnimp.hpp" +#include + namespace CSMWorld { + /* LandTextureNicknameColumn */ + LandTextureNicknameColumn::LandTextureNicknameColumn() + : Column(Columns::ColumnId_TextureNickname, ColumnBase::Display_String) + { + } + + QVariant LandTextureNicknameColumn::get(const Record& record) const + { + return QString::fromUtf8(record.get().mId.c_str()); + } + + void LandTextureNicknameColumn::set(Record& record, const QVariant& data) + { + LandTexture copy = record.get(); + copy.mId = data.toString().toUtf8().constData(); + record.setModified(copy); + } + + bool LandTextureNicknameColumn::isEditable() const + { + return true; + } + + /* LandTextureIndexColumn */ + LandTextureIndexColumn::LandTextureIndexColumn() + : Column(Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) + { + } + + QVariant LandTextureIndexColumn::get(const Record& record) const + { + return record.get().mIndex; + } + + bool LandTextureIndexColumn::isEditable() const + { + return false; + } + + /* LandPluginIndexColumn */ + LandPluginIndexColumn::LandPluginIndexColumn() + : Column(Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer, 0) + { + } + + QVariant LandPluginIndexColumn::get(const Record& record) const + { + return record.get().mPlugin; + } + + bool LandPluginIndexColumn::isEditable() const + { + return false; + } + + /* LandTexturePluginIndexColumn */ + LandTexturePluginIndexColumn::LandTexturePluginIndexColumn() + : Column(Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer, 0) + { + } + + QVariant LandTexturePluginIndexColumn::get(const Record& record) const + { + return record.get().mPluginIndex; + } + + bool LandTexturePluginIndexColumn::isEditable() const + { + return false; + } + /* LandMapLodColumn */ LandMapLodColumn::LandMapLodColumn() : Column(Columns::ColumnId_LandMapLodIndex, ColumnBase::Display_String, 0) @@ -30,7 +103,9 @@ namespace CSMWorld { QByteArray array = data.toByteArray(); const signed char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_GLOBAL_MAP_LOD_SIZE); + + if (array.count() != Land::LAND_GLOBAL_MAP_LOD_SIZE) + throw std::runtime_error("invalid land map LOD data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_WNAM); @@ -76,7 +151,9 @@ namespace CSMWorld { QByteArray array = data.toByteArray(); const signed char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * 3); + + if (array.count() != Land::LAND_NUM_VERTS * 3) + throw std::runtime_error("invalid land normals data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VNML); @@ -121,7 +198,9 @@ namespace CSMWorld { QByteArray array = data.toByteArray(); const float* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * sizeof(float)); + + if (array.count() != Land::LAND_NUM_VERTS * sizeof(float)) + throw std::runtime_error("invalid land heights data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VHGT); @@ -167,7 +246,9 @@ namespace CSMWorld { QByteArray array = data.toByteArray(); const unsigned char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * 3); + + if (array.count() != Land::LAND_NUM_VERTS * 3) + throw std::runtime_error("invalid land colours data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VCLR); @@ -212,7 +293,9 @@ namespace CSMWorld { QByteArray array = data.toByteArray(); const uint16_t* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); + + if (array.count() != Land::LAND_NUM_TEXTURES * sizeof(uint16_t)) + throw std::runtime_error("invalid land textures data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VTEX); diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 8e5908bd3..025b064c6 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -67,14 +67,14 @@ namespace CSMWorld inline QVariant StringIdColumn::get(const Record& record) const { const Land& land = record.get(); - return QString(Land::createUniqueRecordId(land.mX, land.mY).c_str()); + return QString::fromUtf8(Land::createUniqueRecordId(land.mX, land.mY).c_str()); } template<> inline QVariant StringIdColumn::get(const Record& record) const { const LandTexture& ltex = record.get(); - return QString(LandTexture::createUniqueRecordId(ltex.mPluginIndex, ltex.mIndex).c_str()); + return QString::fromUtf8(LandTexture::createUniqueRecordId(ltex.mPluginIndex, ltex.mIndex).c_str()); } template @@ -2435,78 +2435,38 @@ namespace CSMWorld } }; - template - struct TextureHandleColumn : public Column + struct LandTextureNicknameColumn : public Column { - TextureHandleColumn() - : Column (Columns::ColumnId_TextureHandle, ColumnBase::Display_String) - {} - - QVariant get(const Record& record) const override - { - return QString::fromUtf8(record.get().mId.c_str()); - } + LandTextureNicknameColumn(); - void set(Record& record, const QVariant& data) override - { - ESXRecordT copy = record.get(); - copy.mId = data.toString().toUtf8().constData(); - record.setModified(copy); - } - - bool isEditable() const override - { - return true; - } + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; }; - template - struct TextureIndexColumn : public Column + struct LandTextureIndexColumn : public Column { - TextureIndexColumn() - : Column (Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) - {} + LandTextureIndexColumn(); - QVariant get(const Record& record) const override - { - return record.get().mIndex; - } - - bool isEditable() const override - { - return false; - } + QVariant get(const Record& record) const override; + bool isEditable() const override; }; - template - struct PluginIndexColumn : public Column + struct LandPluginIndexColumn : public Column { - PluginIndexColumn() - : Column (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer,0) - {} - - QVariant get(const Record& record) const override - { - return -1; - } + LandPluginIndexColumn(); - bool isEditable() const override - { - return false; - } + QVariant get(const Record& record) const override; + bool isEditable() const override; }; - template<> - inline QVariant PluginIndexColumn::get (const Record& record) const + struct LandTexturePluginIndexColumn : public Column { - return record.get().mPlugin; - } + LandTexturePluginIndexColumn(); - template<> - inline QVariant PluginIndexColumn::get (const Record& record) const - { - return record.get().mPluginIndex; - } + QVariant get(const Record& record) const override; + bool isEditable() const override; + }; struct LandMapLodColumn : public Column { diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 63ccb6017..ec010ba36 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -330,7 +330,7 @@ namespace CSMWorld { ColumnId_WeatherChance, "Percent Chance" }, { ColumnId_Text, "Text" }, - { ColumnId_TextureHandle, "Texture Handle" }, + { ColumnId_TextureNickname, "Texture Nickname" }, { ColumnId_PluginIndex, "Plugin Index" }, { ColumnId_TextureIndex, "Texture Index" }, { ColumnId_LandMapLodIndex, "Land map height LOD" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 432597105..15018795c 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -329,7 +329,7 @@ namespace CSMWorld ColumnId_Text = 297, - ColumnId_TextureHandle = 298, + ColumnId_TextureNickname = 298, ColumnId_PluginIndex = 299, ColumnId_TextureIndex = 300, ColumnId_LandMapLodIndex = 301, diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 5bfcd6846..b654eb00d 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -48,7 +48,7 @@ CSMWorld::ImportLandTexturesCommand::ImportLandTexturesCommand(IdTable& landTabl , mLtexs(ltexTable) , mOldState(0) { - setText("Import land textures"); + setText("Copy land textures to current plugin"); } void CSMWorld::ImportLandTexturesCommand::redo() diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 0ffe5fa21..2216d5ca6 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -415,7 +415,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat mLand.addColumn (new StringIdColumn); mLand.addColumn (new RecordStateColumn); mLand.addColumn (new FixedRecordTypeColumn(UniversalId::Type_Land)); - mLand.addColumn (new PluginIndexColumn); + mLand.addColumn (new LandPluginIndexColumn); mLand.addColumn (new LandMapLodColumn); mLand.addColumn (new LandNormalsColumn); mLand.addColumn (new LandHeightsColumn); @@ -425,9 +425,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat mLandTextures.addColumn (new StringIdColumn(true)); mLandTextures.addColumn (new RecordStateColumn); mLandTextures.addColumn (new FixedRecordTypeColumn(UniversalId::Type_LandTexture)); - mLandTextures.addColumn (new TextureHandleColumn); - mLandTextures.addColumn (new PluginIndexColumn); - mLandTextures.addColumn (new TextureIndexColumn); + mLandTextures.addColumn (new LandTextureNicknameColumn); + mLandTextures.addColumn (new LandTexturePluginIndexColumn); + mLandTextures.addColumn (new LandTextureIndexColumn); mLandTextures.addColumn (new TextureColumn); mPathgrids.addColumn (new StringIdColumn); diff --git a/apps/opencs/view/world/landtexturecreator.cpp b/apps/opencs/view/world/landtexturecreator.cpp index fdabfb281..43d911e50 100644 --- a/apps/opencs/view/world/landtexturecreator.cpp +++ b/apps/opencs/view/world/landtexturecreator.cpp @@ -45,7 +45,7 @@ namespace CSVWorld CSMWorld::IdTable& table = dynamic_cast(*getData().getTableModel(getCollectionId())); - int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureHandle); + int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureNickname); mNameEdit->setText((table.data(table.getModelIndex(originId, column)).toString())); column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureIndex); @@ -79,7 +79,7 @@ namespace CSVWorld GenericCreator::configureCreateCommand(command); CSMWorld::IdTable& table = dynamic_cast(*getData().getTableModel(getCollectionId())); - int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureHandle); + int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureNickname); command.addValue(column, mName.c_str()); } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 083f27cef..f3f72e88a 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -177,17 +177,14 @@ namespace ESM void Land::blank() { - if (mLandData) - { - delete mLandData; - } - mPlugin = 0; for (int i = 0; i < LAND_GLOBAL_MAP_LOD_SIZE; ++i) mWnam[0] = 0; - mLandData = new LandData; + if (!mLandData) + mLandData = new LandData; + mLandData->mHeightOffset = 0; for (int i = 0; i < LAND_NUM_VERTS; ++i) mLandData->mHeights[i] = 0; From 074be7d7c62e8f437e9330378012e82acec6c74b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 17 Sep 2017 21:44:16 -0700 Subject: [PATCH 088/505] Remove a function from the sound manager interface --- apps/openmw/mwbase/soundmanager.hpp | 3 --- apps/openmw/mwsound/soundmanagerimp.cpp | 11 ++++++----- apps/openmw/mwsound/soundmanagerimp.hpp | 4 +--- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index f1c35df19..2b3cf1f0d 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -82,9 +82,6 @@ namespace MWBase ///< Play a soundifle /// \param filename name of a sound file in "Music/" in the data directory. - virtual void startRandomTitle() = 0; - ///< Starts a random track from the current playlist - virtual bool isMusicPlaying() = 0; ///< Returns true if music is playing diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index ac87a2f06..a798d350c 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -391,11 +391,6 @@ namespace MWSound mMusic->setFadeout(0.5f); } - void SoundManager::streamMusic(const std::string& filename) - { - advanceMusic("Music/"+filename); - } - void SoundManager::startRandomTitle() { std::vector filelist; @@ -446,6 +441,12 @@ namespace MWSound tracklist.pop_back(); } + + void SoundManager::streamMusic(const std::string& filename) + { + advanceMusic("Music/"+filename); + } + bool SoundManager::isMusicPlaying() { return mMusic && mOutput->isStreamPlaying(mMusic); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index d2dce3928..e31a0e575 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -127,6 +127,7 @@ namespace MWSound void streamMusicFull(const std::string& filename); void advanceMusic(const std::string& filename); + void startRandomTitle(); void updateSounds(float duration); void updateRegionSound(float duration); @@ -157,9 +158,6 @@ namespace MWSound ///< Play a soundifle /// \param filename name of a sound file in "Music/" in the data directory. - virtual void startRandomTitle(); - ///< Starts a random track from the current playlist - virtual bool isMusicPlaying(); ///< Returns true if music is playing From b770c1493fc73bc38d2ede20ca14fad09d8d6740 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Sep 2017 01:21:18 -0700 Subject: [PATCH 089/505] Don't spam about missing animations --- apps/openmw/mwmechanics/character.cpp | 79 +++++++++++++-------------- apps/openmw/mwrender/animation.cpp | 2 - 2 files changed, 37 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index cd14ec5a4..06916f989 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2025,58 +2025,53 @@ void CharacterController::unpersistAnimationState() bool CharacterController::playGroup(const std::string &groupname, int mode, int count, bool persist) { if(!mAnimation || !mAnimation->hasAnimation(groupname)) - { - std::cerr<< "Animation "<getTextKeyTime(mAnimQueue.front().mGroup + ": loop start") >= 0 && + mAnimation->isPlaying(groupname)) { - // If this animation is a looped animation (has a "loop start" key) that is already playing - // and has not yet reached the end of the loop, allow it to continue animating with its existing loop count - // and remove any other animations that were queued. - // This emulates observed behavior from the original allows the script "OutsideBanner" to animate banners correctly. - if (!mAnimQueue.empty() && mAnimQueue.front().mGroup == groupname && - mAnimation->getTextKeyTime(mAnimQueue.front().mGroup + ": loop start") >= 0 && - mAnimation->isPlaying(groupname)) - { - float endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": loop stop"); + float endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": loop stop"); - if (endOfLoop < 0) // if no Loop Stop key was found, use the Stop key - endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": stop"); + if (endOfLoop < 0) // if no Loop Stop key was found, use the Stop key + endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": stop"); - if (endOfLoop > 0 && (mAnimation->getCurrentTime(mAnimQueue.front().mGroup) < endOfLoop)) - { - mAnimQueue.resize(1); - return true; - } + if (endOfLoop > 0 && (mAnimation->getCurrentTime(mAnimQueue.front().mGroup) < endOfLoop)) + { + mAnimQueue.resize(1); + return true; } + } - count = std::max(count, 1); + count = std::max(count, 1); - AnimationQueueEntry entry; - entry.mGroup = groupname; - entry.mLoopCount = count-1; - entry.mPersist = persist; + AnimationQueueEntry entry; + entry.mGroup = groupname; + entry.mLoopCount = count-1; + entry.mPersist = persist; - if(mode != 0 || mAnimQueue.empty() || !isAnimPlaying(mAnimQueue.front().mGroup)) - { - clearAnimQueue(); - mAnimQueue.push_back(entry); + if(mode != 0 || mAnimQueue.empty() || !isAnimPlaying(mAnimQueue.front().mGroup)) + { + clearAnimQueue(); + mAnimQueue.push_back(entry); - mAnimation->disable(mCurrentIdle); - mCurrentIdle.clear(); + mAnimation->disable(mCurrentIdle); + mCurrentIdle.clear(); - mIdleState = CharState_SpecialIdle; - bool loopfallback = (entry.mGroup.compare(0,4,"idle") == 0); - mAnimation->play(groupname, Priority_Default, - MWRender::Animation::BlendMask_All, false, 1.0f, - ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1, loopfallback); - } - else if(mode == 0) - { - mAnimQueue.resize(1); - mAnimQueue.push_back(entry); - } + mIdleState = CharState_SpecialIdle; + bool loopfallback = (entry.mGroup.compare(0,4,"idle") == 0); + mAnimation->play(groupname, Priority_Default, + MWRender::Animation::BlendMask_All, false, 1.0f, + ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1, loopfallback); + } + else if(mode == 0) + { + mAnimQueue.resize(1); + mAnimQueue.push_back(entry); } return true; } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index df9b8545a..a8e0caed5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -757,8 +757,6 @@ namespace MWRender break; } } - if(iter == mAnimSources.rend()) - std::cerr<< "Failed to find animation "< Date: Mon, 18 Sep 2017 01:41:05 -0700 Subject: [PATCH 090/505] Avoid creating temp strings when looking for an animation stop key --- apps/openmw/mwrender/animation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a8e0caed5..90b69de8e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -793,7 +793,7 @@ namespace MWRender // We have to ignore extra garbage at the end. // The Scrib's idle3 animation has "Idle3: Stop." instead of "Idle3: Stop". // Why, just why? :( - && (stopkey->second.size() < stoptag.size() || stopkey->second.substr(0,stoptag.size()) != stoptag)) + && (stopkey->second.size() < stoptag.size() || stopkey->second.compare(0,stoptag.size(), stoptag) != 0)) ++stopkey; if(stopkey == keys.rend()) return false; From 021627bdf8d874dd2326ad94477bc4e78bddbc4a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Sep 2017 01:51:11 -0700 Subject: [PATCH 091/505] Mark some functions with override Fixes some Clang warnings about overriding a virtual function without the override keyword. --- components/resource/scenemanager.hpp | 6 +++--- components/terrain/chunkmanager.hpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 65524f76e..b223353c2 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -141,11 +141,11 @@ namespace Resource void setUnRefImageDataAfterApply(bool unref); /// @see ResourceManager::updateCache - virtual void updateCache(double referenceTime); + void updateCache(double referenceTime) override; - virtual void clearCache(); + void clearCache() override; - virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const; + void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; private: diff --git a/components/terrain/chunkmanager.hpp b/components/terrain/chunkmanager.hpp index 46531f23e..d8c4fd084 100644 --- a/components/terrain/chunkmanager.hpp +++ b/components/terrain/chunkmanager.hpp @@ -32,9 +32,9 @@ namespace Terrain osg::ref_ptr getChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags); - virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const; + void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; - virtual void clearCache(); + void clearCache() override; void releaseGLObjects(osg::State* state) override; From 65d8e2ff5d70aebb9c6f230ba2b26d5e7d420f98 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 18 Sep 2017 21:46:57 +0400 Subject: [PATCH 092/505] Allow to use GetDetected without a reference (bug #3110) --- apps/openmw/mwbase/mechanicsmanager.hpp | 4 +++ apps/openmw/mwmechanics/actors.cpp | 33 +++++++++++++++++++ apps/openmw/mwmechanics/actors.hpp | 4 +++ .../mwmechanics/mechanicsmanagerimp.cpp | 5 +++ .../mwmechanics/mechanicsmanagerimp.hpp | 4 +++ apps/openmw/mwscript/aiextensions.cpp | 13 ++------ 6 files changed, 53 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 84d43156e..d9068b285 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -225,6 +225,10 @@ namespace MWBase virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0; virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const = 0; + /// Check if the target actor was detected by an observer + /// If the observer is a non-NPC, check all actors in AI processing distance as observers + virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) = 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). diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index baa2470da..366954944 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1086,6 +1086,39 @@ namespace MWMechanics } } + bool Actors::isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) + { + if (!actor.getClass().isActor()) + return false; + + // If an observer is NPC, check if he detected an actor + if (!observer.isEmpty() && observer.getClass().isNpc()) + { + return + MWBase::Environment::get().getWorld()->getLOS(observer, actor) && + MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor, observer); + } + + // Otherwise check if any actor in AI processing range sees the target actor + std::vector actors; + osg::Vec3f position (actor.getRefData().getPosition().asVec3()); + getObjectsInRange(position, aiProcessingDistance, actors); + for(std::vector::iterator it = actors.begin(); it != actors.end(); ++it) + { + if (*it == actor) + continue; + + bool result = + MWBase::Environment::get().getWorld()->getLOS(*it, actor) && + MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor, *it); + + if (result) + return true; + } + + return false; + } + void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { PtrActorMap::iterator iter = mActors.find(old); diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 6eb3a2955..e433434a5 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -57,6 +57,10 @@ namespace MWMechanics PtrActorMap::const_iterator begin() { return mActors.begin(); } PtrActorMap::const_iterator end() { return mActors.end(); } + /// Check if the target actor was detected by an observer + /// If the observer is a non-NPC, check all actors in AI processing distance as observers + bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer); + /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently /// paused we may want to do it manually (after equipping permanent enchantment) void updateMagicEffects (const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 5f3dd58af..5d9ef726a 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -423,6 +423,11 @@ namespace MWMechanics mObjects.update(duration, paused); } + bool MechanicsManager::isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) + { + return mActors.isActorDetected(actor, observer); + } + bool MechanicsManager::isAttackPrepairing(const MWWorld::Ptr& ptr) { return mActors.isAttackPrepairing(ptr); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index adad21916..1bf3a8d22 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -191,6 +191,10 @@ namespace MWMechanics /// Is \a ptr casting spell or using weapon now? virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const; + /// Check if the target actor was detected by an observer + /// If the observer is a non-NPC, check all actors in AI processing distance as observers + virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer); + 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). diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 76130be24..c98e0fc5a 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -372,21 +372,14 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWWorld::Ptr observer = R()(runtime); + MWWorld::Ptr observer = R()(runtime, false); // required=false + std::string actorID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPtr(actorID, true); - if(!actor.getClass().isActor() || !observer.getClass().isActor()) - { - runtime.push(0); - return; - } - - Interpreter::Type_Integer value = - MWBase::Environment::get().getWorld()->getLOS(observer, actor) && - MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor, observer); + Interpreter::Type_Integer value = MWBase::Environment::get().getMechanicsManager()->isActorDetected(actor, observer); runtime.push (value); } From 2806a35a614d4ceb378f612f7c896ba02e7f994c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 18 Sep 2017 23:03:47 +0400 Subject: [PATCH 093/505] Fixed padding of MessageBox buttons --- apps/openmw/mwgui/messagebox.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index ab43df0f1..bfe173b47 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -206,7 +206,8 @@ namespace MWGui int textButtonPadding = 10; // padding between the text-widget und the button-widget int buttonLeftPadding = 10; // padding between the buttons if horizontal int buttonTopPadding = 10; // ^-- if vertical - int buttonPadding = 5; // padding between button label and button itself + int buttonLabelLeftPadding = 12; // padding between button label and button itself, from left + int buttonLabelTopPadding = 4; // padding between button label and button itself, from top int buttonMainPadding = 10; // padding between buttons and bottom of the main widget mMarkedToDelete = false; @@ -245,10 +246,10 @@ namespace MWGui if (buttonsWidth != 0) buttonsWidth += buttonLeftPadding; - int buttonWidth = button->getTextSize().width + 2*buttonPadding; + int buttonWidth = button->getTextSize().width + 2*buttonLabelLeftPadding; buttonsWidth += buttonWidth; - buttonHeight = button->getTextSize().height + 2*buttonPadding; + buttonHeight = button->getTextSize().height + 2*buttonLabelTopPadding; if (buttonsHeight != 0) buttonsHeight += buttonTopPadding; @@ -295,8 +296,8 @@ namespace MWGui buttonCord.left = left; buttonCord.top = messageWidgetCoord.top + textSize.height + textButtonPadding; - buttonSize.width = (*button)->getTextSize().width + 2*buttonPadding; - buttonSize.height = (*button)->getTextSize().height + 2*buttonPadding; + buttonSize.width = (*button)->getTextSize().width + 2*buttonLabelLeftPadding; + buttonSize.height = (*button)->getTextSize().height + 2*buttonLabelTopPadding; (*button)->setCoord(buttonCord); (*button)->setSize(buttonSize); @@ -322,8 +323,8 @@ namespace MWGui std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { - buttonSize.width = (*button)->getTextSize().width + buttonPadding*2; - buttonSize.height = (*button)->getTextSize().height + buttonPadding*2; + buttonSize.width = (*button)->getTextSize().width + buttonLabelLeftPadding*2; + buttonSize.height = (*button)->getTextSize().height + buttonLabelTopPadding*2; buttonCord.top = top; buttonCord.left = (mainWidgetSize.width - buttonSize.width)/2; From 9342a0254fc673ab1cf771cac33247f89c24e13d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 20 Sep 2017 10:44:24 +0400 Subject: [PATCH 094/505] Restack soulgems when use SoulTrap --- apps/openmw/mwmechanics/actors.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index baa2470da..eb2a97cbb 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -209,6 +209,9 @@ namespace MWMechanics gem->getContainerStore()->unstack(*gem, caster); gem->getCellRef().setSoul(mCreature.getCellRef().getRefId()); + // Restack the gem with other gems with the same soul + gem->getContainerStore()->restack(*gem); + mTrapped = true; if (caster == getPlayer()) From 9d826b2deb5f3a01821aec289d64eb1a5770dec6 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 20 Sep 2017 11:57:00 +0400 Subject: [PATCH 095/505] Improve item sorting in inventory and containers --- apps/openmw/mwgui/sortfilteritemmodel.cpp | 92 +++++++++++++++++++++-- 1 file changed, 86 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 68d95fb88..098029ce7 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -59,15 +59,95 @@ namespace if (mSortByType && left.mType != right.mType) return left.mType < right.mType; - if (left.mBase.getTypeName() == right.mBase.getTypeName()) + float result = 0; + + // compare items by type + std::string leftName = left.mBase.getTypeName(); + std::string rightName = right.mBase.getTypeName(); + + if (leftName != rightName) + return compareType(leftName, rightName); + + // compare items by name + leftName = Misc::StringUtils::lowerCase(left.mBase.getClass().getName(left.mBase)); + rightName = Misc::StringUtils::lowerCase(right.mBase.getClass().getName(right.mBase)); + + result = leftName.compare(rightName); + if (result != 0) + return result < 0; + + // compare items by enchantment: + // 1. enchanted items showed before non-enchanted + // 2. item with lesser charge percent comes after items with more charge percent + // 3. item with constant effect comes before items with non-constant effects + int leftChargePercent = -1; + int rightChargePercent = -1; + leftName = left.mBase.getClass().getEnchantment(left.mBase); + rightName = right.mBase.getClass().getEnchantment(right.mBase); + + if (!leftName.empty()) { - std::string leftName = Misc::StringUtils::lowerCase(left.mBase.getClass().getName(left.mBase)); - std::string rightName = Misc::StringUtils::lowerCase(right.mBase.getClass().getName(right.mBase)); + const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get().search(leftName); + if (ench) + { + if (ench->mData.mType == ESM::Enchantment::ConstantEffect) + leftChargePercent = 101; + else + leftChargePercent = (left.mBase.getCellRef().getEnchantmentCharge() == -1) ? 100 + : static_cast(left.mBase.getCellRef().getEnchantmentCharge() / static_cast(ench->mData.mCharge) * 100); + } + else + std::cerr << "Warning: Can't find enchantment '" << leftName << "' on item " << left.mBase.getCellRef().getRefId() << std::endl; + } - return leftName.compare(rightName) < 0; + if (!rightName.empty()) + { + const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get().search(rightName); + if (ench) + { + if (ench->mData.mType == ESM::Enchantment::ConstantEffect) + rightChargePercent = 101; + else + rightChargePercent = (right.mBase.getCellRef().getEnchantmentCharge() == -1) ? 100 + : static_cast(right.mBase.getCellRef().getEnchantmentCharge() / static_cast(ench->mData.mCharge) * 100); + } + else + std::cerr << "Warning: Can't find enchantment '" << rightName << "' on item " << right.mBase.getCellRef().getRefId() << std::endl; + } + + result = leftChargePercent - rightChargePercent; + if (result != 0) + return result > 0; + + // compare items by condition + if (left.mBase.getClass().hasItemHealth(left.mBase) && right.mBase.getClass().hasItemHealth(right.mBase)) + { + result = left.mBase.getClass().getItemHealth(left.mBase) - right.mBase.getClass().getItemHealth(right.mBase); + if (result != 0) + return result > 0; } - else - return compareType(left.mBase.getTypeName(), right.mBase.getTypeName()); + + // compare items by remaining usage time + result = left.mBase.getClass().getRemainingUsageTime(left.mBase) - right.mBase.getClass().getRemainingUsageTime(right.mBase); + if (result != 0) + return result > 0; + + // compare items by value + result = left.mBase.getClass().getValue(left.mBase) - right.mBase.getClass().getValue(right.mBase); + if (result != 0) + return result > 0; + + // compare items by weight + result = left.mBase.getClass().getWeight(left.mBase) - right.mBase.getClass().getWeight(right.mBase); + if (result != 0) + return result > 0; + + // compare items by Id + leftName = left.mBase.getCellRef().getRefId(); + rightName = right.mBase.getCellRef().getRefId(); + + result = leftName.compare(rightName); + return result < 0; } }; } From 2346c5338e93effffdaa6c281ef4c07ede421763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Wed, 20 Sep 2017 16:34:27 +0200 Subject: [PATCH 096/505] increase water fudge to get rid of artifacts --- apps/openmw/mwrender/water.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 0ed389bdf..2329e7afa 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -112,7 +112,7 @@ class ClipCullNode : public osg::Group } // move the plane back along its normal a little bit to prevent bleeding at the water shore - const float clipFudge = -5; + const float clipFudge = -30; modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * clipFudge); cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); @@ -336,8 +336,7 @@ public: void setWaterLevel(float waterLevel) { - setViewMatrix(osg::Matrix::translate(0,0,-waterLevel) * osg::Matrix::scale(1,1,-1) * osg::Matrix::translate(0,0,waterLevel)); - + setViewMatrix(osg::Matrix::scale(1,1,-1) * osg::Matrix::translate(0,0,2 * waterLevel)); mClipCullNode->setPlane(osg::Plane(osg::Vec3d(0,0,1), osg::Vec3d(0,0,waterLevel))); } From 771f58ce58e2089f88338acf01a51c1f02635e3f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 20 Sep 2017 19:47:14 +0400 Subject: [PATCH 097/505] Remove unwanted warnings --- apps/openmw/mwgui/sortfilteritemmodel.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 098029ce7..45aa261df 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -96,8 +96,6 @@ namespace leftChargePercent = (left.mBase.getCellRef().getEnchantmentCharge() == -1) ? 100 : static_cast(left.mBase.getCellRef().getEnchantmentCharge() / static_cast(ench->mData.mCharge) * 100); } - else - std::cerr << "Warning: Can't find enchantment '" << leftName << "' on item " << left.mBase.getCellRef().getRefId() << std::endl; } if (!rightName.empty()) @@ -111,8 +109,6 @@ namespace rightChargePercent = (right.mBase.getCellRef().getEnchantmentCharge() == -1) ? 100 : static_cast(right.mBase.getCellRef().getEnchantmentCharge() / static_cast(ench->mData.mCharge) * 100); } - else - std::cerr << "Warning: Can't find enchantment '" << rightName << "' on item " << right.mBase.getCellRef().getRefId() << std::endl; } result = leftChargePercent - rightChargePercent; From f15de6d3cad92fe3513ce9d328098f6b6ac134a5 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Wed, 20 Sep 2017 18:56:32 +0200 Subject: [PATCH 098/505] ESS-Importer: Convert magic projectiles (Closes #2320) --- apps/essimporter/CMakeLists.txt | 1 + apps/essimporter/converter.cpp | 53 +++++++++++---- apps/essimporter/converter.hpp | 12 ++++ apps/essimporter/importer.cpp | 3 +- apps/essimporter/importercontext.hpp | 4 +- apps/essimporter/importsplm.cpp | 43 ++++++++++++ apps/essimporter/importsplm.h | 81 +++++++++++++++++++++++ apps/openmw/mwbase/world.hpp | 3 +- apps/openmw/mwmechanics/spellcasting.cpp | 9 ++- apps/openmw/mwmechanics/spellcasting.hpp | 2 +- apps/openmw/mwworld/projectilemanager.cpp | 58 ++++++++++------ apps/openmw/mwworld/projectilemanager.hpp | 5 +- apps/openmw/mwworld/worldimp.cpp | 5 +- apps/openmw/mwworld/worldimp.hpp | 3 +- components/esm/projectilestate.cpp | 15 ++--- components/esm/projectilestate.hpp | 4 -- 16 files changed, 238 insertions(+), 63 deletions(-) create mode 100644 apps/essimporter/importsplm.cpp create mode 100644 apps/essimporter/importsplm.h diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index fc5fae72e..0e742ff54 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -17,6 +17,7 @@ set(ESSIMPORTER_FILES importscri.cpp importscpt.cpp importproj.cpp + importsplm.cpp importercontext.cpp converter.cpp convertacdt.cpp diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 5c65332be..2473daf95 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -1,12 +1,12 @@ #include "converter.hpp" #include +#include #include #include #include -#include #include "convertcrec.hpp" #include "convertcntc.hpp" @@ -461,11 +461,7 @@ namespace ESSImport if (!pnam.isMagic()) { ESM::ProjectileState out; - out.mId = pnam.mArrowId.toString(); - out.mPosition = pnam.mPosition; - out.mOrientation.mValues[0] = out.mOrientation.mValues[1] = out.mOrientation.mValues[2] = 0.0f; - out.mOrientation.mValues[3] = 1.0f; - out.mActorId = convertActorId(pnam.mActorId.toString(), *mContext); + convertBaseState(out, pnam); out.mBowId = pnam.mBowId.toString(); out.mVelocity = pnam.mVelocity; @@ -477,16 +473,49 @@ namespace ESSImport } else { - // TODO: Implement magic projectile conversion. + ESM::MagicBoltState out; + convertBaseState(out, pnam); - /*esm.startRecord(ESM::REC_MPRJ); - out.save(esm); - esm.endRecord(ESM::REC_MPRJ);*/ + auto it = std::find_if(mContext->mActiveSpells.begin(), mContext->mActiveSpells.end(), + [&pnam](const SPLM::ActiveSpell& spell) -> bool { return spell.mIndex == pnam.mSplmIndex; }); - std::cerr << "Warning: Skipped conversion for magic projectile \"" << pnam.mArrowId.toString() << "\" (not implemented)" << std::endl; - continue; + if (it == mContext->mActiveSpells.end()) + { + std::cerr << "Warning: Skipped conversion for magic projectile \"" << pnam.mArrowId.toString() << "\" (invalid spell link)" << std::endl; + continue; + } + + out.mSpellId = it->mSPDT.mId.toString(); + out.mSpeed = pnam.mSpeed * 0.001f; // not sure where this factor comes from + + esm.startRecord(ESM::REC_MPRJ); + out.save(esm); + esm.endRecord(ESM::REC_MPRJ); } } } + void ConvertPROJ::convertBaseState(ESM::BaseProjectileState& base, const PROJ::PNAM& pnam) + { + base.mId = pnam.mArrowId.toString(); + base.mPosition = pnam.mPosition; + + osg::Quat orient; + orient.makeRotate(osg::Vec3f(0,1,0), pnam.mVelocity); + base.mOrientation = orient; + + base.mActorId = convertActorId(pnam.mActorId.toString(), *mContext); + } + + void ConvertSPLM::read(ESM::ESMReader& esm) + { + mSPLM.load(esm); + mContext->mActiveSpells = mSPLM.mActiveSpells; + } + + void ConvertSPLM::write(ESM::ESMWriter& esm) + { + std::cerr << "Warning: Skipped active spell conversion (not implemented)" << std::endl; + } + } diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index a640d6756..621b85709 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "importcrec.hpp" #include "importcntc.hpp" @@ -36,6 +37,7 @@ #include "importjour.hpp" #include "importscpt.hpp" #include "importproj.h" +#include "importsplm.h" #include "convertacdt.hpp" #include "convertnpcc.hpp" @@ -602,9 +604,19 @@ public: virtual void read(ESM::ESMReader& esm) override; virtual void write(ESM::ESMWriter& esm) override; private: + void convertBaseState(ESM::BaseProjectileState& base, const PROJ::PNAM& pnam); PROJ mProj; }; +class ConvertSPLM : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) override; + virtual void write(ESM::ESMWriter& esm) override; +private: + SPLM mSPLM; +}; + } #endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 4c8222c56..73b15baae 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -271,6 +271,7 @@ namespace ESSImport const unsigned int recSTLN = ESM::FourCC<'S','T','L','N'>::value; const unsigned int recGAME = ESM::FourCC<'G','A','M','E'>::value; const unsigned int recJOUR = ESM::FourCC<'J','O','U','R'>::value; + const unsigned int recSPLM = ESM::FourCC<'S','P','L','M'>::value; std::map > converters; converters[ESM::REC_GLOB] = std::shared_ptr(new ConvertGlobal()); @@ -304,12 +305,12 @@ namespace ESSImport converters[recJOUR ] = std::shared_ptr(new ConvertJOUR()); converters[ESM::REC_SCPT] = std::shared_ptr(new ConvertSCPT()); converters[ESM::REC_PROJ] = std::shared_ptr(new ConvertPROJ()); + converters[recSPLM] = std::shared_ptr(new ConvertSPLM()); // TODO: // - REGN (weather in certain regions?) // - VFXM // - SPLM (active spell effects) - // - PROJ (magic projectiles in air) std::set unknownRecords; diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 4896f5594..86501b3cb 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -15,7 +15,7 @@ #include "importcrec.hpp" #include "importcntc.hpp" #include "importplayer.hpp" - +#include "importsplm.h" @@ -54,6 +54,8 @@ namespace ESSImport std::map mCreatures; std::map mNpcs; + std::vector mActiveSpells; + Context() : mDay(0) , mMonth(0) diff --git a/apps/essimporter/importsplm.cpp b/apps/essimporter/importsplm.cpp new file mode 100644 index 000000000..9fdba4ddb --- /dev/null +++ b/apps/essimporter/importsplm.cpp @@ -0,0 +1,43 @@ +#include "importsplm.h" + +#include + +namespace ESSImport +{ + +void SPLM::load(ESM::ESMReader& esm) +{ + while (esm.isNextSub("NAME")) + { + ActiveSpell spell; + esm.getHT(spell.mIndex); + esm.getHNT(spell.mSPDT, "SPDT"); + spell.mTarget = esm.getHNOString("TNAM"); + + while (esm.isNextSub("NPDT")) + { + ActiveEffect effect; + esm.getHT(effect.mNPDT); + + // Effect-specific subrecords can follow: + // - INAM for disintegration and bound effects + // - CNAM for summoning and command effects + // - VNAM for vampirism + // NOTE: There can be multiple INAMs per effect. + // TODO: Needs more research. + + esm.skipHSubUntil("NAM0"); // sentinel + esm.getSubName(); + esm.skipHSub(); + + spell.mActiveEffects.push_back(effect); + } + + unsigned char xnam; // sentinel + esm.getHNT(xnam, "XNAM"); + + mActiveSpells.push_back(spell); + } +} + +} diff --git a/apps/essimporter/importsplm.h b/apps/essimporter/importsplm.h new file mode 100644 index 000000000..8fd5c2bb5 --- /dev/null +++ b/apps/essimporter/importsplm.h @@ -0,0 +1,81 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTSPLM_H +#define OPENMW_ESSIMPORT_IMPORTSPLM_H + +#include +#include +#include + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + +struct SPLM +{ + +#pragma pack(push) +#pragma pack(1) + struct SPDT // 160 bytes + { + int mType; // 1 = spell, 2 = enchantment, 3 = potion + ESM::NAME32 mId; // base ID of a spell/enchantment/potion + unsigned char mUnknown[4*4]; + ESM::NAME32 mCasterId; + ESM::NAME32 mSourceId; // empty for spells + unsigned char mUnknown2[4*11]; + }; + + struct NPDT // 56 bytes + { + ESM::NAME32 mAffectedActorId; + unsigned char mUnknown[4*2]; + int mMagnitude; + float mSecondsActive; + unsigned char mUnknown2[4*2]; + }; + + struct INAM // 40 bytes + { + int mUnknown; + unsigned char mUnknown2; + ESM::FIXED_STRING<35> mItemId; // disintegrated item / bound item / item to re-equip after expiration + }; + + struct CNAM // 36 bytes + { + int mUnknown; // seems to always be 0 + ESM::NAME32 mSummonedOrCommandedActor[32]; + }; + + struct VNAM // 4 bytes + { + int mUnknown; + }; + + +#pragma pack(pop) + + struct ActiveEffect + { + NPDT mNPDT; + }; + + struct ActiveSpell + { + int mIndex; + SPDT mSPDT; + std::string mTarget; + std::vector mActiveEffects; + }; + + std::vector mActiveSpells; + + void load(ESM::ESMReader& esm); +}; + +} + +#endif diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 5e76d82eb..038535939 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -487,8 +487,7 @@ namespace MWBase virtual void castSpell (const MWWorld::Ptr& actor) = 0; - virtual void launchMagicBolt (const std::string& spellId, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) = 0; + virtual void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) = 0; virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) = 0; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index f7ee15bf4..a808b8285 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -329,7 +329,7 @@ namespace MWMechanics { } - void CastSpell::launchMagicBolt (const ESM::EffectList& effects) + void CastSpell::launchMagicBolt () { osg::Vec3f fallbackDirection (0,1,0); @@ -340,8 +340,7 @@ namespace MWMechanics osg::Vec3f(mTarget.getRefData().getPosition().asVec3())- osg::Vec3f(mCaster.getRefData().getPosition().asVec3()); - MWBase::Environment::get().getWorld()->launchMagicBolt(mId, false, effects, - mCaster, mSourceName, fallbackDirection); + MWBase::Environment::get().getWorld()->launchMagicBolt(mId, mCaster, fallbackDirection); } void CastSpell::inflict(const MWWorld::Ptr &target, const MWWorld::Ptr &caster, @@ -823,7 +822,7 @@ namespace MWMechanics inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch); if (launchProjectile) - launchMagicBolt(enchantment->mEffects); + launchMagicBolt(); else if (isProjectile || !mTarget.isEmpty()) inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Target); @@ -915,7 +914,7 @@ namespace MWMechanics if (!mTarget.isEmpty()) inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch); - launchMagicBolt(spell->mEffects); + launchMagicBolt(); return true; } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 9991c583d..2e368afcf 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -106,7 +106,7 @@ namespace MWMechanics void playSpellCastingEffects(const std::string &spellid); /// Launch a bolt with the given effects. - void launchMagicBolt (const ESM::EffectList& effects); + void launchMagicBolt (); /// @note \a target can be any type of object, not just actors. /// @note \a caster can be any type of object, or even an empty object. diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 5b15583bf..6e716cb54 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -1,6 +1,7 @@ #include "projectilemanager.hpp" #include +#include #include @@ -41,13 +42,29 @@ namespace { - ESM::EffectList getMagicBoltData(std::vector& projectileIDs, std::vector& sounds, float& speed, std::string& texture, const ESM::EffectList& effects) + ESM::EffectList getMagicBoltData(std::vector& projectileIDs, std::vector& sounds, float& speed, std::string& texture, std::string& sourceName, const std::string& id) { + const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); + const ESM::EffectList* effects; + if (const ESM::Spell* spell = esmStore.get().search(id)) // check if it's a spell + { + sourceName = spell->mName; + effects = &spell->mEffects; + } + else // check if it's an enchanted item + { + MWWorld::ManualRef ref(esmStore, id); + MWWorld::Ptr ptr = ref.getPtr(); + const ESM::Enchantment* ench = esmStore.get().find(ptr.getClass().getEnchantment(ptr)); + sourceName = ptr.getClass().getName(ptr); + effects = &ench->mEffects; + } + int count = 0; speed = 0.0f; ESM::EffectList projectileEffects; - for (std::vector::const_iterator iter (effects.mList.begin()); - iter!=effects.mList.end(); ++iter) + for (std::vector::const_iterator iter (effects->mList.begin()); + iter!=effects->mList.end(); ++iter) { const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find ( iter->mEffectID); @@ -82,14 +99,14 @@ namespace if (projectileEffects.mList.size() == 1) { const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find ( - effects.mList.begin()->mEffectID); + effects->mList.begin()->mEffectID); texture = magicEffect->mParticle; } if (projectileEffects.mList.size() > 1) // insert a VFX_Multiple projectile if there are multiple projectile effects { std::ostringstream ID; - ID << "VFX_Multiple" << effects.mList.size(); + ID << "VFX_Multiple" << effects->mList.size(); std::vector::iterator it; it = projectileIDs.begin(); it = projectileIDs.insert(it, ID.str()); @@ -235,8 +252,7 @@ namespace MWWorld state.mEffectAnimationTime->addTime(duration); } - void ProjectileManager::launchMagicBolt(const std::string &spellId, bool stack, const ESM::EffectList &effects, const Ptr &caster, - const std::string &sourceName, const osg::Vec3f& fallbackDirection) + void ProjectileManager::launchMagicBolt(const std::string &spellId, const Ptr &caster, const osg::Vec3f& fallbackDirection) { osg::Vec3f pos = caster.getRefData().getPosition().asVec3(); if (caster.getClass().isActor()) @@ -257,18 +273,16 @@ namespace MWWorld orient.makeRotate(osg::Vec3f(0,1,0), osg::Vec3f(fallbackDirection)); MagicBoltState state; - state.mSourceName = sourceName; state.mSpellId = spellId; state.mCasterHandle = caster; if (caster.getClass().isActor()) state.mActorId = caster.getClass().getCreatureStats(caster).getActorId(); else state.mActorId = -1; - state.mStack = stack; std::string texture = ""; - state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, texture, effects); + state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, texture, state.mSourceName, state.mSpellId); // Non-projectile should have been removed by getMagicBoltData if (state.mEffects.mList.empty()) @@ -277,7 +291,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0)); MWWorld::Ptr ptr = ref.getPtr(); - osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(effects); + osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects); createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, true, lightDiffuseColor, texture); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); @@ -364,7 +378,7 @@ namespace MWWorld cast.mHitPosition = pos; cast.mId = it->mSpellId; cast.mSourceName = it->mSourceName; - cast.mStack = it->mStack; + cast.mStack = false; cast.inflict(result.mHitObject, caster, it->mEffects, ESM::RT_Target, false, true); } } @@ -504,11 +518,7 @@ namespace MWWorld state.mActorId = it->mActorId; state.mSpellId = it->mSpellId; - state.mEffects = it->mEffects; - state.mSound = it->mSoundIds.at(0); - state.mSourceName = it->mSourceName; state.mSpeed = it->mSpeed; - state.mStack = it->mStack; state.save(writer); @@ -553,13 +563,21 @@ namespace MWWorld esm.load(reader); MagicBoltState state; - state.mSourceName = esm.mSourceName; state.mIdMagic.push_back(esm.mId); state.mSpellId = esm.mSpellId; state.mActorId = esm.mActorId; - state.mStack = esm.mStack; std::string texture = ""; - state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, texture, esm.mEffects); + + try + { + state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, texture, state.mSourceName, state.mSpellId); + } + catch(...) + { + std::cerr << "Warning: Failed to recreate magic projectile from saved data (id \"" << state.mSpellId << "\" no longer exists?)" << std::endl; + return true; + } + state.mSpeed = esm.mSpeed; // speed is derived from non-projectile effects as well as // projectile effects, so we can't calculate it from the save // file's effect list, which is already trimmed of non-projectile @@ -577,7 +595,7 @@ namespace MWWorld return true; } - osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(esm.mEffects); + osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects); createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, lightDiffuseColor, texture); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index c7025a3a0..1ef72a048 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -49,8 +49,7 @@ namespace MWWorld MWRender::RenderingManager* rendering, MWPhysics::PhysicsSystem* physics); /// If caster is an actor, the actor's facing orientation is used. Otherwise fallbackDirection is used. - void launchMagicBolt (const std::string &spellId, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); + void launchMagicBolt (const std::string &spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection); void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& pos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength); @@ -101,8 +100,6 @@ namespace MWWorld float mSpeed; - bool mStack; - std::vector mSounds; std::vector mSoundIds; }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a9506385d..40bc13c94 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2816,10 +2816,9 @@ namespace MWWorld mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed, attackStrength); } - void World::launchMagicBolt (const std::string &spellId, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) + void World::launchMagicBolt (const std::string &spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) { - mProjectileManager->launchMagicBolt(spellId, stack, effects, caster, sourceName, fallbackDirection); + mProjectileManager->launchMagicBolt(spellId, caster, fallbackDirection); } const std::vector& World::getContentFiles() const diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index a15dcaf3d..774753b6c 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -601,8 +601,7 @@ namespace MWWorld */ virtual void castSpell (const MWWorld::Ptr& actor); - virtual void launchMagicBolt (const std::string& spellId, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); + virtual void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) override; virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength); diff --git a/components/esm/projectilestate.cpp b/components/esm/projectilestate.cpp index 70ae4c5ee..8ade9d5b2 100644 --- a/components/esm/projectilestate.cpp +++ b/components/esm/projectilestate.cpp @@ -27,11 +27,7 @@ namespace ESM BaseProjectileState::save(esm); esm.writeHNString ("SPEL", mSpellId); - esm.writeHNString ("SRCN", mSourceName); - mEffects.save(esm); esm.writeHNT ("SPED", mSpeed); - esm.writeHNT ("STCK", mStack); - esm.writeHNString ("SOUN", mSound); } void MagicBoltState::load(ESMReader &esm) @@ -39,11 +35,14 @@ namespace ESM BaseProjectileState::load(esm); mSpellId = esm.getHNString("SPEL"); - mSourceName = esm.getHNString ("SRCN"); - mEffects.load(esm); + if (esm.isNextSub("SRCN")) // for backwards compatibility + esm.skipHSub(); + ESM::EffectList().load(esm); // for backwards compatibility esm.getHNT (mSpeed, "SPED"); - esm.getHNT (mStack, "STCK"); - mSound = esm.getHNString ("SOUN"); + if (esm.isNextSub("STCK")) // for backwards compatibility + esm.skipHSub(); + if (esm.isNextSub("SOUN")) // for backwards compatibility + esm.skipHSub(); } void ProjectileState::save(ESMWriter &esm) const diff --git a/components/esm/projectilestate.hpp b/components/esm/projectilestate.hpp index 3471fbfc7..67ec89bb6 100644 --- a/components/esm/projectilestate.hpp +++ b/components/esm/projectilestate.hpp @@ -31,11 +31,7 @@ namespace ESM struct MagicBoltState : public BaseProjectileState { std::string mSpellId; - std::string mSourceName; - ESM::EffectList mEffects; float mSpeed; - bool mStack; - std::string mSound; void load (ESMReader &esm); void save (ESMWriter &esm) const; From 186cc1e37066abe92c2117f5b14deb5fb1da4fe6 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 22:29:34 +0200 Subject: [PATCH 099/505] Fix skins incorrectly named 'Client' to avoid a collision with new MyGUI feature cfdaf5f --- .../openmw_chargen_class_description.layout | 2 +- files/mygui/openmw_dialogue_window.layout | 2 +- files/mygui/openmw_hud_box.skin.xml | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/files/mygui/openmw_chargen_class_description.layout b/files/mygui/openmw_chargen_class_description.layout index 43b0518fd..906ca2352 100644 --- a/files/mygui/openmw_chargen_class_description.layout +++ b/files/mygui/openmw_chargen_class_description.layout @@ -4,7 +4,7 @@ - + diff --git a/files/mygui/openmw_dialogue_window.layout b/files/mygui/openmw_dialogue_window.layout index a85bd5b02..1ed399572 100644 --- a/files/mygui/openmw_dialogue_window.layout +++ b/files/mygui/openmw_dialogue_window.layout @@ -4,7 +4,7 @@ - + diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index e53493bb1..a1c4f608b 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -8,27 +8,27 @@ - + - + - + - + - + @@ -36,11 +36,11 @@ - + - + @@ -48,11 +48,11 @@ - + - + From fb975d02dba79d9eb73ce3be14cb1127a8ce47ea Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 22:41:50 +0200 Subject: [PATCH 100/505] Use client coordinates in HBox/VBox --- components/widgets/box.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/components/widgets/box.cpp b/components/widgets/box.cpp index 0ce8ce951..eeddc22dd 100644 --- a/components/widgets/box.cpp +++ b/components/widgets/box.cpp @@ -171,9 +171,11 @@ namespace Gui total_width += mSpacing; } - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + if (mAutoResize && (total_width+mPadding*2 != getClientCoord().width || total_height+mPadding*2 != getClientCoord().height)) { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + int xmargin = getSize().width - getClientCoord().width; + int ymargin = getSize().height - getClientCoord().height; + setSize(MyGUI::IntSize(total_width+mPadding*2 + xmargin, total_height+mPadding*2 + ymargin)); return; } @@ -191,19 +193,19 @@ namespace Gui continue; bool vstretch = w->getUserString ("VStretch") == "true"; - int max_height = getSize().height - mPadding*2; + int max_height = getClientCoord().height - mPadding*2; int height = vstretch ? max_height : sizes[i].first.height; MyGUI::IntCoord widgetCoord; widgetCoord.left = curX; - widgetCoord.top = mPadding + (getSize().height-mPadding*2 - height) / 2; + widgetCoord.top = mPadding + (getClientCoord().height-mPadding*2 - height) / 2; int width = 0; if (sizes[i].second) { if (h_stretched_count == 0) throw std::logic_error("unexpected"); - width = sizes[i].first.width + (getSize().width-mPadding*2 - total_width)/h_stretched_count; + width = sizes[i].first.width + (getClientCoord().width-mPadding*2 - total_width)/h_stretched_count; } else width = sizes[i].first.width; @@ -317,13 +319,14 @@ namespace Gui total_height += mSpacing; } - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + if (mAutoResize && (total_width+mPadding*2 != getClientCoord().width || total_height+mPadding*2 != getClientCoord().height)) { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + int xmargin = getSize().width - getClientCoord().width; + int ymargin = getSize().height - getClientCoord().height; + setSize(MyGUI::IntSize(total_width+mPadding*2 + xmargin, total_height+mPadding*2 + ymargin)); return; } - int curY = 0; for (unsigned int i = 0; i < count; ++i) { @@ -337,19 +340,19 @@ namespace Gui continue; bool hstretch = w->getUserString ("HStretch") == "true"; - int maxWidth = getSize().width - mPadding*2; + int maxWidth = getClientCoord().width - mPadding*2; int width = hstretch ? maxWidth : sizes[i].first.width; MyGUI::IntCoord widgetCoord; widgetCoord.top = curY; - widgetCoord.left = mPadding + (getSize().width-mPadding*2 - width) / 2; + widgetCoord.left = mPadding + (getClientCoord().width-mPadding*2 - width) / 2; int height = 0; if (sizes[i].second) { if (v_stretched_count == 0) throw std::logic_error("unexpected"); - height = sizes[i].first.height + (getSize().height-mPadding*2 - total_height)/v_stretched_count; + height = sizes[i].first.height + (getClientCoord().height-mPadding*2 - total_height)/v_stretched_count; } else height = sizes[i].first.height; From d07fe91cfef85dc8a530bd12237bf3ece7ef6388 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 22:53:59 +0200 Subject: [PATCH 101/505] Don't use MW_Dialog skin with plain Widgets After MyGUI commit cfdaf5f , the 'Client' area will be used for every type of widget, whereas previously it would only be used for some widgets like 'Window'. Use 'Window' widget where the client was always used. This fixes a wrong margin when built with cfdaf5f or later. --- files/mygui/openmw_hud.layout | 10 +++++----- files/mygui/openmw_jail_screen.layout | 6 +++--- files/mygui/openmw_loading_screen.layout | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 8fe25a5dc..366b0c4c6 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -32,19 +32,19 @@ - + - + - - + + - + diff --git a/files/mygui/openmw_jail_screen.layout b/files/mygui/openmw_jail_screen.layout index ef37c73d8..76aa05b86 100644 --- a/files/mygui/openmw_jail_screen.layout +++ b/files/mygui/openmw_jail_screen.layout @@ -1,14 +1,14 @@ - + - + - + diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 89b35d05e..69df20022 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -4,13 +4,13 @@ - + - + - + From 7dec773ea95379538aa02a8907381c3864cabcf5 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 23:03:14 +0200 Subject: [PATCH 102/505] Fix global map arrow/button not showing for a split second when the window is opened for the first time --- apps/openmw/mwgui/mapwindow.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 7d81b6ab3..ed9dabd2d 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1002,6 +1002,9 @@ namespace MWGui mGlobalMapOverlayTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getOverlayTexture())); mGlobalMapOverlay->setRenderItemTexture(mGlobalMapOverlayTexture.get()); mGlobalMapOverlay->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + + // Redraw children in proper order + mGlobalMap->getParent()->_updateChilds(); } } From fe6f9ffff439e685ce0dea794543a2ac4ea348c1 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 22:29:34 +0200 Subject: [PATCH 103/505] Fix skins incorrectly named 'Client' to avoid a collision with new MyGUI feature cfdaf5f --- .../openmw_chargen_class_description.layout | 2 +- files/mygui/openmw_dialogue_window.layout | 2 +- files/mygui/openmw_hud_box.skin.xml | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/files/mygui/openmw_chargen_class_description.layout b/files/mygui/openmw_chargen_class_description.layout index 43b0518fd..906ca2352 100644 --- a/files/mygui/openmw_chargen_class_description.layout +++ b/files/mygui/openmw_chargen_class_description.layout @@ -4,7 +4,7 @@ - + diff --git a/files/mygui/openmw_dialogue_window.layout b/files/mygui/openmw_dialogue_window.layout index a85bd5b02..1ed399572 100644 --- a/files/mygui/openmw_dialogue_window.layout +++ b/files/mygui/openmw_dialogue_window.layout @@ -4,7 +4,7 @@ - + diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index e53493bb1..a1c4f608b 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -8,27 +8,27 @@ - + - + - + - + - + @@ -36,11 +36,11 @@ - + - + @@ -48,11 +48,11 @@ - + - + From 58f96884332bea595ef4b1ec51896a92c7d9ae28 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 22:41:50 +0200 Subject: [PATCH 104/505] Use client coordinates in HBox/VBox --- components/widgets/box.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/components/widgets/box.cpp b/components/widgets/box.cpp index 0ce8ce951..eeddc22dd 100644 --- a/components/widgets/box.cpp +++ b/components/widgets/box.cpp @@ -171,9 +171,11 @@ namespace Gui total_width += mSpacing; } - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + if (mAutoResize && (total_width+mPadding*2 != getClientCoord().width || total_height+mPadding*2 != getClientCoord().height)) { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + int xmargin = getSize().width - getClientCoord().width; + int ymargin = getSize().height - getClientCoord().height; + setSize(MyGUI::IntSize(total_width+mPadding*2 + xmargin, total_height+mPadding*2 + ymargin)); return; } @@ -191,19 +193,19 @@ namespace Gui continue; bool vstretch = w->getUserString ("VStretch") == "true"; - int max_height = getSize().height - mPadding*2; + int max_height = getClientCoord().height - mPadding*2; int height = vstretch ? max_height : sizes[i].first.height; MyGUI::IntCoord widgetCoord; widgetCoord.left = curX; - widgetCoord.top = mPadding + (getSize().height-mPadding*2 - height) / 2; + widgetCoord.top = mPadding + (getClientCoord().height-mPadding*2 - height) / 2; int width = 0; if (sizes[i].second) { if (h_stretched_count == 0) throw std::logic_error("unexpected"); - width = sizes[i].first.width + (getSize().width-mPadding*2 - total_width)/h_stretched_count; + width = sizes[i].first.width + (getClientCoord().width-mPadding*2 - total_width)/h_stretched_count; } else width = sizes[i].first.width; @@ -317,13 +319,14 @@ namespace Gui total_height += mSpacing; } - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + if (mAutoResize && (total_width+mPadding*2 != getClientCoord().width || total_height+mPadding*2 != getClientCoord().height)) { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + int xmargin = getSize().width - getClientCoord().width; + int ymargin = getSize().height - getClientCoord().height; + setSize(MyGUI::IntSize(total_width+mPadding*2 + xmargin, total_height+mPadding*2 + ymargin)); return; } - int curY = 0; for (unsigned int i = 0; i < count; ++i) { @@ -337,19 +340,19 @@ namespace Gui continue; bool hstretch = w->getUserString ("HStretch") == "true"; - int maxWidth = getSize().width - mPadding*2; + int maxWidth = getClientCoord().width - mPadding*2; int width = hstretch ? maxWidth : sizes[i].first.width; MyGUI::IntCoord widgetCoord; widgetCoord.top = curY; - widgetCoord.left = mPadding + (getSize().width-mPadding*2 - width) / 2; + widgetCoord.left = mPadding + (getClientCoord().width-mPadding*2 - width) / 2; int height = 0; if (sizes[i].second) { if (v_stretched_count == 0) throw std::logic_error("unexpected"); - height = sizes[i].first.height + (getSize().height-mPadding*2 - total_height)/v_stretched_count; + height = sizes[i].first.height + (getClientCoord().height-mPadding*2 - total_height)/v_stretched_count; } else height = sizes[i].first.height; From aaa727757d63c2c626355d0491adedb1c2a8f8cc Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 22:53:59 +0200 Subject: [PATCH 105/505] Don't use MW_Dialog skin with plain Widgets After MyGUI commit cfdaf5f , the 'Client' area will be used for every type of widget, whereas previously it would only be used for some widgets like 'Window'. Use 'Window' widget where the client was always used. This fixes a wrong margin when built with cfdaf5f or later. --- files/mygui/openmw_hud.layout | 10 +++++----- files/mygui/openmw_jail_screen.layout | 6 +++--- files/mygui/openmw_loading_screen.layout | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 8fe25a5dc..366b0c4c6 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -32,19 +32,19 @@ - + - + - - + + - + diff --git a/files/mygui/openmw_jail_screen.layout b/files/mygui/openmw_jail_screen.layout index ef37c73d8..76aa05b86 100644 --- a/files/mygui/openmw_jail_screen.layout +++ b/files/mygui/openmw_jail_screen.layout @@ -1,14 +1,14 @@ - + - + - + diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 89b35d05e..69df20022 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -4,13 +4,13 @@ - + - + - + From f004622530f6c690dbc687652e975701bb47767c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 23:03:14 +0200 Subject: [PATCH 106/505] Fix global map arrow/button not showing for a split second when the window is opened for the first time --- apps/openmw/mwgui/mapwindow.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 7d81b6ab3..ed9dabd2d 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1002,6 +1002,9 @@ namespace MWGui mGlobalMapOverlayTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getOverlayTexture())); mGlobalMapOverlay->setRenderItemTexture(mGlobalMapOverlayTexture.get()); mGlobalMapOverlay->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + + // Redraw children in proper order + mGlobalMap->getParent()->_updateChilds(); } } From c72aa19d6d8a91c3ce34659e5d5a8bb4826bc0db Mon Sep 17 00:00:00 2001 From: Date: Wed, 20 Sep 2017 23:53:12 -0500 Subject: [PATCH 107/505] first pass on optimization of nif parsing functions from the file stream --- components/files/constrainedfilestream.cpp | 2 +- components/nif/nifstream.cpp | 132 +--------------- components/nif/nifstream.hpp | 170 ++++++++++++++++++--- 3 files changed, 151 insertions(+), 153 deletions(-) diff --git a/components/files/constrainedfilestream.cpp b/components/files/constrainedfilestream.cpp index 4f76139d9..b239ec6a1 100644 --- a/components/files/constrainedfilestream.cpp +++ b/components/files/constrainedfilestream.cpp @@ -8,7 +8,7 @@ namespace { // somewhat arbitrary though 64KB buffers didn't seem to improve performance any -const size_t sBufferSize = 4096; +const size_t sBufferSize = 8192; } namespace Files diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index d0fc9bab0..08a7466fa 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -6,138 +6,8 @@ namespace Nif { //Private functions -uint8_t NIFStream::read_byte() -{ - uint8_t byte; - inp->read((char*)&byte, 1); - return byte; -} -uint16_t NIFStream::read_le16() -{ - uint8_t buffer[2]; - inp->read((char*)buffer, 2); - return buffer[0] | (buffer[1]<<8); -} -uint32_t NIFStream::read_le32() -{ - uint8_t buffer[4]; - inp->read((char*)buffer, 4); - return buffer[0] | (buffer[1]<<8) | (buffer[2]<<16) | (buffer[3]<<24); -} -float NIFStream::read_le32f() -{ - union { - uint32_t i; - float f; - } u = { read_le32() }; - return u.f; -} -//Public functions -osg::Vec2f NIFStream::getVector2() -{ - osg::Vec2f vec; - for(size_t i = 0;i < 2;i++) - vec._v[i] = getFloat(); - return vec; -} -osg::Vec3f NIFStream::getVector3() -{ - osg::Vec3f vec; - for(size_t i = 0;i < 3;i++) - vec._v[i] = getFloat(); - return vec; -} -osg::Vec4f NIFStream::getVector4() -{ - osg::Vec4f vec; - for(size_t i = 0;i < 4;i++) - vec._v[i] = getFloat(); - return vec; -} -Matrix3 NIFStream::getMatrix3() -{ - Matrix3 mat; - for(size_t i = 0;i < 3;i++) - { - for(size_t j = 0;j < 3;j++) - mat.mValues[i][j] = getFloat(); - } - return mat; -} -osg::Quat NIFStream::getQuaternion() -{ - osg::Quat quat; - quat.w() = getFloat(); - quat.x() = getFloat(); - quat.y() = getFloat(); - quat.z() = getFloat(); - return quat; -} -Transformation NIFStream::getTrafo() -{ - Transformation t; - t.pos = getVector3(); - t.rotation = getMatrix3(); - t.scale = getFloat(); - return t; -} -std::string NIFStream::getString(size_t length) -{ - std::vector str (length+1, 0); - - inp->read(&str[0], length); - - return &str[0]; -} -std::string NIFStream::getString() -{ - size_t size = read_le32(); - return getString(size); -} -std::string NIFStream::getVersionString() -{ - std::string result; - std::getline(*inp, result); - return result; -} - -void NIFStream::getUShorts(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getUShort(); -} -void NIFStream::getFloats(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getFloat(); -} -void NIFStream::getVector2s(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector2(); -} -void NIFStream::getVector3s(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector3(); -} -void NIFStream::getVector4s(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector4(); -} -void NIFStream::getQuaternions(std::vector &quat, size_t size) -{ - quat.resize(size); - for(size_t i = 0;i < quat.size();i++) - quat[i] = getQuaternion(); -} +//Public functions } diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 860c62e64..d33771f45 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -2,7 +2,7 @@ #ifndef OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP #define OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP - +#include #include #include #include @@ -26,10 +26,44 @@ class NIFStream { /// Input stream Files::IStreamPtr inp; - uint8_t read_byte(); - uint16_t read_le16(); - uint32_t read_le32(); - float read_le32f(); + uint8_t read_byte() { + uint8_t byte; + inp->read((char*)&byte, 1); + return byte; + } + + uint16_t read_le16() { + alignas(2) uint8_t buffer[2]; + inp->read((char*)buffer, 2); + return static_cast(*((uint16_t*)buffer)); + } + uint32_t read_le32() { + alignas(4) uint8_t buffer[4]; + inp->read((char*)buffer, 4); + return static_cast(*((uint32_t*)buffer)); + } + uint64_t read_le64() { + alignas(8) uint8_t buffer[8]; + inp->read((char*)buffer, 8); + return static_cast(*((uint64_t*)buffer)); + } + __m128 read_le96() { + alignas(8) uint8_t buffer[16]; + inp->read((char*)buffer, 12); + return static_cast<__m128>(*((__m128*)buffer)); + } + __m128 read_le128() { + alignas(16) uint8_t buffer[16]; + inp->read((char*)buffer, 16); + return static_cast<__m128>(*((__m128*)buffer)); + } + float read_le32f() { + union { + uint32_t i; + float f; + } u = { read_le32() }; + return u.f; + } public: @@ -46,26 +80,120 @@ public: unsigned int getUInt() { return read_le32(); } float getFloat() { return read_le32f(); } - osg::Vec2f getVector2(); - osg::Vec3f getVector3(); - osg::Vec4f getVector4(); - Matrix3 getMatrix3(); - osg::Quat getQuaternion(); - Transformation getTrafo(); + osg::Vec2f getVector2() { + union { + uint64_t i; + float f[2]; + } u = { read_le64() }; + osg::Vec2f vec; + for (size_t i = 0;i < 2;i++) + vec._v[i] = u.f[i]; + return vec; + } + osg::Vec3f getVector3() { + union { + __m128 i; + float f[4]; + } u = { read_le96() }; + osg::Vec3f vec; + for (size_t i = 0;i < 3;i++) + vec._v[i] = u.f[i]; + return vec; + } + osg::Vec4f getVector4() { + union { + __m128 i; + float f[4]; + } u = { read_le128() }; + osg::Vec4f vec; + for (size_t i = 0;i < 4;i++) + vec._v[i] = u.f[i]; + return vec; + } + Matrix3 getMatrix3() { + Matrix3 mat; + alignas(16) union { + float f[9]; + uint8_t buffer[36]; + } u; + inp->read((char*)u.buffer, 36); + for (size_t i = 0;i < 3;i++) + { + for (size_t j = 0;j < 3;j++) + mat.mValues[i][j] = u.f[3*i+j]; + } + return mat; + } + osg::Quat getQuaternion() { + union { + __m128 i; + float f[4]; + } u = { read_le128() }; + osg::Quat quat; + quat.w() = u.f[0]; + quat.x() = u.f[1]; + quat.y() = u.f[2]; + quat.z() = u.f[3]; + return quat; + } + Transformation getTrafo() { + Transformation t; + t.pos = getVector3(); + t.rotation = getMatrix3(); + t.scale = getFloat(); + return t; + } ///Read in a string of the given length - std::string getString(size_t length); + std::string getString(size_t length) { + std::vector str(length + 1, 0); + + inp->read(&str[0], length); + + return &str[0]; + } ///Read in a string of the length specified in the file - std::string getString(); + std::string getString() { + size_t size = read_le32(); + return getString(size); + } ///This is special since the version string doesn't start with a number, and ends with "\n" - std::string getVersionString(); - - void getUShorts(std::vector &vec, size_t size); - void getFloats(std::vector &vec, size_t size); - void getVector2s(std::vector &vec, size_t size); - void getVector3s(std::vector &vec, size_t size); - void getVector4s(std::vector &vec, size_t size); - void getQuaternions(std::vector &quat, size_t size); + std::string getVersionString() { + std::string result; + std::getline(*inp, result); + return result; + } + + void getUShorts(std::vector &vec, size_t size) { + vec.resize(size); + for (size_t i = 0;i < vec.size();i++) + vec[i] = getUShort(); + } + void getFloats(std::vector &vec, size_t size) { + vec.resize(size); + for (size_t i = 0;i < vec.size();i++) + vec[i] = getFloat(); + } + void getVector2s(std::vector &vec, size_t size) { + vec.resize(size); + for (size_t i = 0;i < vec.size();i++) + vec[i] = getVector2(); + } + void getVector3s(std::vector &vec, size_t size) { + vec.resize(size); + for (size_t i = 0;i < vec.size();i++) + vec[i] = getVector3(); + } + void getVector4s(std::vector &vec, size_t size) { + vec.resize(size); + for (size_t i = 0;i < vec.size();i++) + vec[i] = getVector4(); + } + void getQuaternions(std::vector &quat, size_t size) { + quat.resize(size); + for (size_t i = 0;i < quat.size();i++) + quat[i] = getQuaternion(); + } }; } From 5da532a36c696cad5b226c22f5de2847daaac320 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 21 Sep 2017 10:32:34 +0400 Subject: [PATCH 108/505] Do not play draw weapon animation when equip a new weapon (bug #4056) --- apps/openmw/mwmechanics/character.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index bfe8812e6..861135dfb 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1116,6 +1116,11 @@ bool CharacterController::updateWeaponState() priorityWeapon[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody; bool forcestateupdate = false; + + // We should not play equipping animation and sound during weapon->weapon transition + bool isStillWeapon = weaptype > WeapType_HandToHand && weaptype < WeapType_Spell && + mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell; + if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut && mHitState != CharState_Hit) { @@ -1138,13 +1143,16 @@ bool CharacterController::updateWeaponState() else { getWeaponGroup(weaptype, weapgroup); - mAnimation->showWeapons(false); mAnimation->setWeaponGroup(weapgroup); - mAnimation->play(weapgroup, priorityWeapon, - MWRender::Animation::BlendMask_All, true, - 1.0f, "equip start", "equip stop", 0.0f, 0); - mUpperBodyState = UpperCharState_EquipingWeap; + if (!isStillWeapon) + { + mAnimation->showWeapons(false); + mAnimation->play(weapgroup, priorityWeapon, + MWRender::Animation::BlendMask_All, true, + 1.0f, "equip start", "equip stop", 0.0f, 0); + mUpperBodyState = UpperCharState_EquipingWeap; + } if(isWerewolf) { @@ -1158,7 +1166,7 @@ bool CharacterController::updateWeaponState() } } - if(!soundid.empty()) + if(!soundid.empty() && !isStillWeapon) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); sndMgr->playSound3D(mPtr, soundid, 1.0f, 1.0f); From 16d9773c6c75e2069104da1302d3a31a3620a7c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 21 Sep 2017 22:25:36 +0200 Subject: [PATCH 109/505] fix water shader artifacts at shores --- apps/openmw/mwrender/water.cpp | 2 +- files/shaders/water_fragment.glsl | 29 ++++++++++++++++++++++++----- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 2329e7afa..68c07c1ab 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -112,7 +112,7 @@ class ClipCullNode : public osg::Group } // move the plane back along its normal a little bit to prevent bleeding at the water shore - const float clipFudge = -30; + const float clipFudge = -5; modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * clipFudge); cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index c04233fcf..b5d7d1a6a 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -31,6 +31,8 @@ const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction const float SPEC_HARDNESS = 256.0; // specular highlights hardness +const float REFLECTION_BUMP_SUPRESS_DEPTH = 150.0; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) + const vec2 WIND_DIR = vec2(0.5f, -0.8f); const float WIND_SPEED = 0.2f; @@ -74,6 +76,13 @@ uniform float near; uniform float far; uniform vec3 nodePosition; +float transformDepth(float depth) // helper for transforming refraction depth + { + float z_n = 2.0 * depth - 1.0; + depth = 2.0 * near * far / (far + near - z_n * (far - near)); + return depth - depthPassthrough; + } + void main(void) { vec3 worldPos = position.xyz + nodePosition.xyz; @@ -147,8 +156,12 @@ void main(void) fresnel = clamp(fresnel, 0.0, 1.0); + float realWaterDepth = transformDepth(texture2D(refractionDepthMap, screenCoords).x); + + float shore = clamp(realWaterDepth / REFLECTION_BUMP_SUPRESS_DEPTH,0,1); + // reflection - vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP)).rgb; + vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP*shore)).rgb; // refraction #if REFRACTION @@ -165,10 +178,7 @@ void main(void) vec3 waterColor = WATER_COLOR; waterColor = waterColor * length(gl_LightModel.ambient.xyz); #if REFRACTION - float refractionDepth = texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x; - float z_n = 2.0 * refractionDepth - 1.0; - refractionDepth = 2.0 * near * far / (far + near - z_n * (far - near)); - + float refractionDepth = transformDepth(texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x); float waterDepth = refractionDepth - depthPassthrough; if (cameraPos.z > 0.0) @@ -185,6 +195,15 @@ void main(void) #if REFRACTION gl_FragData[0].w = 1.0; + +/*float nonRefractionDepth = texture2D(refractionDepthMap, screenCoords).x; +z_n = 2.0 * nonRefractionDepth - 1.0; +nonRefractionDepth = 2.0 * near * far / (far + near - z_n * (far - near)); + +float realWaterDepth = nonRefractionDepth - depthPassthrough; +*/ +//gl_FragData[0] = vec4(refractionSuppressor,0,0,0); + #else gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); #endif From c43baf6e946efa4a4baf25e1aba048a3d660abbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 21 Sep 2017 22:31:26 +0200 Subject: [PATCH 110/505] remove commented code --- files/shaders/water_fragment.glsl | 9 --------- 1 file changed, 9 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index b5d7d1a6a..6e4edfb84 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -195,15 +195,6 @@ void main(void) #if REFRACTION gl_FragData[0].w = 1.0; - -/*float nonRefractionDepth = texture2D(refractionDepthMap, screenCoords).x; -z_n = 2.0 * nonRefractionDepth - 1.0; -nonRefractionDepth = 2.0 * near * far / (far + near - z_n * (far - near)); - -float realWaterDepth = nonRefractionDepth - depthPassthrough; -*/ -//gl_FragData[0] = vec4(refractionSuppressor,0,0,0); - #else gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); #endif From 658fa0fdae4039714bd7563a2312c82c9db9124a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 21 Sep 2017 22:33:57 +0200 Subject: [PATCH 111/505] fix typo --- files/shaders/water_fragment.glsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 6e4edfb84..867a24a70 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -31,7 +31,7 @@ const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction const float SPEC_HARDNESS = 256.0; // specular highlights hardness -const float REFLECTION_BUMP_SUPRESS_DEPTH = 150.0; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) +const float REFLECTION_BUMP_SUPPRESS_DEPTH = 150; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) const vec2 WIND_DIR = vec2(0.5f, -0.8f); const float WIND_SPEED = 0.2f; @@ -158,7 +158,7 @@ void main(void) float realWaterDepth = transformDepth(texture2D(refractionDepthMap, screenCoords).x); - float shore = clamp(realWaterDepth / REFLECTION_BUMP_SUPRESS_DEPTH,0,1); + float shore = clamp(realWaterDepth / REFLECTION_BUMP_SUPPRESS_DEPTH,0,1); // reflection vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP*shore)).rgb; From 090a8408b828192498209342bcab29d8bdd12357 Mon Sep 17 00:00:00 2001 From: Date: Thu, 21 Sep 2017 22:37:19 -0500 Subject: [PATCH 112/505] made nif basic type read optimizations more portable --- components/nif/nifstream.hpp | 146 +++++++++++++++-------------------- 1 file changed, 63 insertions(+), 83 deletions(-) diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index d33771f45..35c042e7d 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -2,7 +2,7 @@ #ifndef OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP #define OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP -#include + #include #include #include @@ -21,50 +21,38 @@ namespace Nif class NIFFile; +template inline void readLittleEndianBufferOfType(Files::IStreamPtr &pIStream, T* dest) +{ +#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) + pIStream->read((char*)dest, numInstances * sizeof(T)); +#else + char buffer[numInstances * sizeof(T)]; + pIStream->read((char*)buffer, numInstances * sizeof(T)); + /* + Due to the loop iterations being known at compile time, + this nested loop will most likely be unrolled + */ + for (uint32_t i = 0; i < numInstances; i++) + { + dest[i] = 0; + for (uint32_t byte = 0; byte < sizeof(T); byte++) + dest[i] |= ((T)buffer[i * sizeof(T) + byte]) << (byte * 8); + } +#endif +} + +template type inline readLittleEndianType(Files::IStreamPtr &pIStream) +{ + type val; + readLittleEndianBufferOfType<1,type>(pIStream, (type*)&val); + return val; +} + class NIFStream { /// Input stream Files::IStreamPtr inp; - uint8_t read_byte() { - uint8_t byte; - inp->read((char*)&byte, 1); - return byte; - } - - uint16_t read_le16() { - alignas(2) uint8_t buffer[2]; - inp->read((char*)buffer, 2); - return static_cast(*((uint16_t*)buffer)); - } - uint32_t read_le32() { - alignas(4) uint8_t buffer[4]; - inp->read((char*)buffer, 4); - return static_cast(*((uint32_t*)buffer)); - } - uint64_t read_le64() { - alignas(8) uint8_t buffer[8]; - inp->read((char*)buffer, 8); - return static_cast(*((uint64_t*)buffer)); - } - __m128 read_le96() { - alignas(8) uint8_t buffer[16]; - inp->read((char*)buffer, 12); - return static_cast<__m128>(*((__m128*)buffer)); - } - __m128 read_le128() { - alignas(16) uint8_t buffer[16]; - inp->read((char*)buffer, 16); - return static_cast<__m128>(*((__m128*)buffer)); - } - float read_le32f() { - union { - uint32_t i; - float f; - } u = { read_le32() }; - return u.f; - } - public: NIFFile * const file; @@ -73,67 +61,59 @@ public: void skip(size_t size) { inp->ignore(size); } - char getChar() { return read_byte(); } - short getShort() { return read_le16(); } - unsigned short getUShort() { return read_le16(); } - int getInt() { return read_le32(); } - unsigned int getUInt() { return read_le32(); } - float getFloat() { return read_le32f(); } + char getChar() + { + return readLittleEndianType(inp); + } + short getShort() + { + return readLittleEndianType(inp); + } + unsigned short getUShort() + { + return readLittleEndianType(inp); + } + int getInt() + { + return readLittleEndianType(inp); + } + unsigned int getUInt() + { + return readLittleEndianType(inp); + } + float getFloat() + { + return readLittleEndianType(inp); + } osg::Vec2f getVector2() { - union { - uint64_t i; - float f[2]; - } u = { read_le64() }; osg::Vec2f vec; - for (size_t i = 0;i < 2;i++) - vec._v[i] = u.f[i]; + readLittleEndianBufferOfType<2,float>(inp, (float*)&vec._v[0]); return vec; } osg::Vec3f getVector3() { - union { - __m128 i; - float f[4]; - } u = { read_le96() }; osg::Vec3f vec; - for (size_t i = 0;i < 3;i++) - vec._v[i] = u.f[i]; + readLittleEndianBufferOfType<3, float>(inp, (float*)&vec._v[0]); return vec; } osg::Vec4f getVector4() { - union { - __m128 i; - float f[4]; - } u = { read_le128() }; osg::Vec4f vec; - for (size_t i = 0;i < 4;i++) - vec._v[i] = u.f[i]; + readLittleEndianBufferOfType<4, float>(inp, (float*)&vec._v[0]); return vec; } Matrix3 getMatrix3() { Matrix3 mat; - alignas(16) union { - float f[9]; - uint8_t buffer[36]; - } u; - inp->read((char*)u.buffer, 36); - for (size_t i = 0;i < 3;i++) - { - for (size_t j = 0;j < 3;j++) - mat.mValues[i][j] = u.f[3*i+j]; - } + readLittleEndianBufferOfType<9, float>(inp, (float*)&mat.mValues); return mat; } osg::Quat getQuaternion() { - union { - __m128 i; - float f[4]; - } u = { read_le128() }; + float f[4]; + readLittleEndianBufferOfType<4, float>(inp, (float*)&f); osg::Quat quat; - quat.w() = u.f[0]; - quat.x() = u.f[1]; - quat.y() = u.f[2]; - quat.z() = u.f[3]; + quat.w() = f[0]; + quat.x() = f[1]; + quat.y() = f[2]; + quat.z() = f[3]; return quat; } Transformation getTrafo() { @@ -154,7 +134,7 @@ public: } ///Read in a string of the length specified in the file std::string getString() { - size_t size = read_le32(); + size_t size = readLittleEndianType(inp); return getString(size); } ///This is special since the version string doesn't start with a number, and ends with "\n" From 8834066dea932defa23f8345210eca2ecf2739c3 Mon Sep 17 00:00:00 2001 From: Date: Thu, 21 Sep 2017 23:47:09 -0500 Subject: [PATCH 113/505] make streaming to a type array in nif a direct copy from the file into the vector --- components/nif/nifstream.hpp | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 35c042e7d..4d7e39ecb 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -41,6 +41,25 @@ template inline void readLittleEndianBufferO #endif } +template inline void readLittleEndianDynamicBufferOfType(Files::IStreamPtr &pIStream, T* dest, uint32_t numInstances) +{ +#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) + pIStream->read((char*)dest, numInstances * sizeof(T)); +#else + char buffer[numInstances * sizeof(T)]; + pIStream->read((char*)buffer, numInstances * sizeof(T)); + /* + Due to the loop iterations being known at compile time, + this nested loop will most likely be unrolled + */ + for (uint32_t i = 0; i < numInstances; i++) + { + dest[i] = 0; + for (uint32_t byte = 0; byte < sizeof(T); byte++) + dest[i] |= ((T)buffer[i * sizeof(T) + byte]) << (byte * 8); + } +#endif +} template type inline readLittleEndianType(Files::IStreamPtr &pIStream) { type val; @@ -146,28 +165,23 @@ public: void getUShorts(std::vector &vec, size_t size) { vec.resize(size); - for (size_t i = 0;i < vec.size();i++) - vec[i] = getUShort(); + readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); } void getFloats(std::vector &vec, size_t size) { vec.resize(size); - for (size_t i = 0;i < vec.size();i++) - vec[i] = getFloat(); + readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); } void getVector2s(std::vector &vec, size_t size) { vec.resize(size); - for (size_t i = 0;i < vec.size();i++) - vec[i] = getVector2(); + readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); } void getVector3s(std::vector &vec, size_t size) { vec.resize(size); - for (size_t i = 0;i < vec.size();i++) - vec[i] = getVector3(); + readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); } void getVector4s(std::vector &vec, size_t size) { vec.resize(size); - for (size_t i = 0;i < vec.size();i++) - vec[i] = getVector4(); + readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); } void getQuaternions(std::vector &quat, size_t size) { quat.resize(size); From 4580024d76cbff2b3de7313f3ae13793f6e16637 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 11 Sep 2017 14:49:55 +0400 Subject: [PATCH 114/505] Unequip all items from dead corpse when take all items (bug #4095) --- apps/openmw/mwgui/container.cpp | 50 +++++++++++++------- apps/openmw/mwgui/inventoryitemmodel.cpp | 32 +++++++++++-- apps/openmw/mwscript/containerextensions.cpp | 3 +- apps/openmw/mwworld/containerstore.cpp | 6 +-- apps/openmw/mwworld/containerstore.hpp | 4 +- apps/openmw/mwworld/inventorystore.cpp | 5 ++ apps/openmw/mwworld/inventorystore.hpp | 3 +- 7 files changed, 74 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index c9be21322..0ba4839e7 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -11,6 +11,7 @@ #include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwmechanics/pickpocket.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -211,31 +212,48 @@ namespace MWGui void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) { - if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) + if(mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop) + return; + + // transfer everything into the player's inventory + ItemModel* playerModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getModel(); + mModel->update(); + + // unequip all items to avoid unequipping/reequipping + if (mPtr.getClass().hasInventoryStore(mPtr)) { - // transfer everything into the player's inventory - ItemModel* playerModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getModel(); - mModel->update(); + MWWorld::InventoryStore& invStore = mPtr.getClass().getInventoryStore(mPtr); for (size_t i=0; igetItemCount(); ++i) { - if (i==0) - { - // play the sound of the first object - MWWorld::Ptr item = mModel->getItem(i).mBase; - std::string sound = item.getClass().getUpSoundId(item); - MWBase::Environment::get().getWindowManager()->playSound(sound); - } - const ItemStack& item = mModel->getItem(i); + if (invStore.isEquipped(item.mBase) == false) + continue; + + invStore.unequipItem(item.mBase, mPtr); + } + } - if (!onTakeItem(item, item.mCount)) - break; + mModel->update(); - mModel->moveItem(item, item.mCount, playerModel); + for (size_t i=0; igetItemCount(); ++i) + { + if (i==0) + { + // play the sound of the first object + MWWorld::Ptr item = mModel->getItem(i).mBase; + std::string sound = item.getClass().getUpSoundId(item); + MWBase::Environment::get().getWindowManager()->playSound(sound); } - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); + const ItemStack& item = mModel->getItem(i); + + if (!onTakeItem(item, item.mCount)) + break; + + mModel->moveItem(item, item.mCount, playerModel); } + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } void ContainerWindow::onDisposeCorpseButtonClicked(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index 2fe540f22..222243ec1 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -1,5 +1,10 @@ #include "inventoryitemmodel.hpp" +#include + +#include "../mwmechanics/actorutil.hpp" +#include "../mwmechanics/npcstats.hpp" + #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" @@ -45,16 +50,33 @@ MWWorld::Ptr InventoryItemModel::copyItem (const ItemStack& item, size_t count, return *mActor.getClass().getContainerStore(mActor).add(item.mBase, count, mActor, setNewOwner); } - void InventoryItemModel::removeItem (const ItemStack& item, size_t count) { - MWWorld::ContainerStore& store = mActor.getClass().getContainerStore(mActor); - int removed = store.remove(item.mBase, count, mActor); + int removed = 0; + // Re-equipping makes sense only if a target has inventory + if (mActor.getClass().hasInventoryStore(mActor)) + { + MWWorld::InventoryStore& store = mActor.getClass().getInventoryStore(mActor); + removed = store.remove(item.mBase, count, mActor, true); + } + else + { + MWWorld::ContainerStore& store = mActor.getClass().getContainerStore(mActor); + removed = store.remove(item.mBase, count, mActor); + } + + std::stringstream error; if (removed == 0) - throw std::runtime_error("Item to remove not found in container store"); + { + error << "Item '" << item.mBase.getCellRef().getRefId() << "' was not found in container store to remove"; + throw std::runtime_error(error.str()); + } else if (removed < static_cast(count)) - throw std::runtime_error("Not enough items in the stack to remove"); + { + error << "Not enough items '" << item.mBase.getCellRef().getRefId() << "' in the stack to remove (" << static_cast(count) << " requested, " << removed << " found)"; + throw std::runtime_error(error.str()); + } } MWWorld::Ptr InventoryItemModel::moveItem(const ItemStack &item, size_t count, ItemModel *otherModel) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index dfc066bcd..8457b33cb 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -143,8 +143,7 @@ namespace MWScript if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item)) itemName = iter->getClass().getName(*iter); - // Actors should not equip a replacement when items are removed with RemoveItem - int numRemoved = store.remove(item, count, ptr, false); + int numRemoved = store.remove(item, count, ptr); // Spawn a messagebox (only for items removed from player's inventory) if ((numRemoved > 0) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index eef10b905..cd04a425b 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -408,13 +408,13 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addNewStack (const Cons return it; } -int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const Ptr& actor, bool equipReplacement) +int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const Ptr& actor) { int toRemove = count; for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter) if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), itemId)) - toRemove -= remove(*iter, toRemove, actor, equipReplacement); + toRemove -= remove(*iter, toRemove, actor); flagAsModified(); @@ -422,7 +422,7 @@ int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const return count - toRemove; } -int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement) +int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor) { assert(this == item.getContainerStore()); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index f27ff1db9..dbb82cbda 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -142,12 +142,12 @@ namespace MWWorld ContainerStoreIterator add(const std::string& id, int count, const Ptr& actorPtr); ///< Utility to construct a ManualRef and call add(ptr, count, actorPtr, true) - int remove(const std::string& itemId, int count, const Ptr& actor, bool equipReplacement = true); + int remove(const std::string& itemId, int count, const Ptr& actor); ///< Remove \a count item(s) designated by \a itemId from this container. /// /// @return the number of items actually removed - virtual int remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement = true); + virtual int remove(const Ptr& item, int count, const Ptr& actor); ///< Remove \a count item(s) designated by \a item from this inventory. /// /// @return the number of items actually removed diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index a6394757f..b599b3583 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -654,6 +654,11 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSelectedEnchantItem( return mSelectedEnchantItem; } +int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor) +{ + return remove(item, count, actor, false); +} + int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement) { int retCount = ContainerStore::remove(item, count, actor); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 90f7f7788..851abf408 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -177,7 +177,8 @@ namespace MWWorld virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2) const; ///< @return true if the two specified objects can stack with each other - virtual int remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement = true); + virtual int remove(const Ptr& item, int count, const Ptr& actor); + virtual int remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement); ///< Remove \a count item(s) designated by \a item from this inventory. /// /// @return the number of items actually removed From 8df79625e8d691109ea8dc0e53500d769ebe8373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 22 Sep 2017 10:53:02 +0200 Subject: [PATCH 115/505] fix water shader --- apps/openmw/mwrender/water.cpp | 2 +- files/shaders/water_fragment.glsl | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 68c07c1ab..9679533be 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -112,7 +112,7 @@ class ClipCullNode : public osg::Group } // move the plane back along its normal a little bit to prevent bleeding at the water shore - const float clipFudge = -5; + const float clipFudge = -6; modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * clipFudge); cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 867a24a70..bb56e95c6 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -76,7 +76,7 @@ uniform float near; uniform float far; uniform vec3 nodePosition; -float transformDepth(float depth) // helper for transforming refraction depth +float transformDepth(float depth) // helper for transforming water depth { float z_n = 2.0 * depth - 1.0; depth = 2.0 * near * far / (far + near - z_n * (far - near)); @@ -156,27 +156,30 @@ void main(void) fresnel = clamp(fresnel, 0.0, 1.0); +#if REFRACTION float realWaterDepth = transformDepth(texture2D(refractionDepthMap, screenCoords).x); - float shore = clamp(realWaterDepth / REFLECTION_BUMP_SUPPRESS_DEPTH,0,1); +#else + float shore = 1.0; +#endif // reflection vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP*shore)).rgb; // refraction #if REFRACTION - vec3 refraction = texture2D(refractionMap, screenCoords-(normal.xy*REFR_BUMP)).rgb; + vec3 refraction = texture2D(refractionMap, screenCoords-(normal.xy*REFR_BUMP*shore)).rgb; // brighten up the refraction underwater refraction = (cameraPos.z < 0.0) ? clamp(refraction * 1.5, 0.0, 1.0) : refraction; #endif - // specular vec3 R = reflect(vVec, normal); float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS) * shadow; vec3 waterColor = WATER_COLOR; waterColor = waterColor * length(gl_LightModel.ambient.xyz); + #if REFRACTION float refractionDepth = transformDepth(texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x); float waterDepth = refractionDepth - depthPassthrough; From 6260bb1366c91240d391d2c4e0e2b367422a7c12 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 22 Sep 2017 14:51:06 +0400 Subject: [PATCH 116/505] Implement SwimAttack1-3 and SwimDeathKnockDown/Out animations --- apps/openmw/mwmechanics/character.cpp | 39 +++++++++++++++++++-------- apps/openmw/mwmechanics/character.hpp | 2 ++ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index df62ca490..681ca7f07 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -621,6 +621,12 @@ void CharacterController::playDeath(float startpoint, CharacterState death) case CharState_SwimDeath: mCurrentDeath = "swimdeath"; break; + case CharState_SwimDeathKnockDown: + mCurrentDeath = "swimdeathknockdown"; + break; + case CharState_SwimDeathKnockOut: + mCurrentDeath = "swimdeathknockout"; + break; case CharState_DeathKnockDown: mCurrentDeath = "deathknockdown"; break; @@ -674,7 +680,16 @@ void CharacterController::playRandomDeath(float startpoint) MWBase::Environment::get().getWorld()->useDeathCamera(); } - if(MWBase::Environment::get().getWorld()->isSwimming(mPtr) && mAnimation->hasAnimation("swimdeath")) + bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr); + if(isSwimming && mAnimation->hasAnimation("swimdeathknockdown") && mHitState == CharState_KnockDown) + { + mDeathState = CharState_SwimDeathKnockDown; + } + else if(isSwimming && mAnimation->hasAnimation("swimdeathknockout") && mHitState == CharState_KnockOut) + { + mDeathState = CharState_SwimDeathKnockOut; + } + else if(isSwimming && mAnimation->hasAnimation("swimdeath")) { mDeathState = CharState_SwimDeath; } @@ -876,16 +891,17 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Thrust); else if(evt.compare(off, len, "hit") == 0) { - if (groupname == "attack1") + if (groupname == "attack1" || groupname == "swimattack1") mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Chop); - else if (groupname == "attack2") + else if (groupname == "attack2" || groupname == "swimattack2") mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Slash); - else if (groupname == "attack3") + else if (groupname == "attack3" || groupname == "swimattack1") mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Thrust); else mPtr.getClass().hit(mPtr, mAttackStrength); } - else if (!groupname.empty() && groupname.compare(0, groupname.size()-1, "attack") == 0 + else if (!groupname.empty() + && (groupname.compare(0, groupname.size()-1, "attack") == 0 || groupname.compare(0, groupname.size()-1, "swimattack") == 0) && evt.compare(off, len, "start") == 0) { std::multimap::const_iterator hitKey = key; @@ -905,11 +921,11 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: } if (!hasHitKey) { - if (groupname == "attack1") + if (groupname == "attack1" || groupname == "swimattack1") mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Chop); - else if (groupname == "attack2") + else if (groupname == "attack2" || groupname == "swimattack2") mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Slash); - else if (groupname == "attack3") + else if (groupname == "attack3" || groupname == "swimattack3") mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Thrust); } } @@ -1035,13 +1051,14 @@ bool CharacterController::updateCreatureState() } if (weapType != WeapType_Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation { + bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr); int roll = Misc::Rng::rollDice(3); // [0, 2] if (roll == 0) - mCurrentWeapon = "attack1"; + mCurrentWeapon = isSwimming && mAnimation->hasAnimation("swimattack1") ? "swimattack1" : "attack1"; else if (roll == 1) - mCurrentWeapon = "attack2"; + mCurrentWeapon = isSwimming && mAnimation->hasAnimation("swimattack2") ? "swimattack2" : "attack2"; else - mCurrentWeapon = "attack3"; + mCurrentWeapon = isSwimming && mAnimation->hasAnimation("swimattack3") ? "swimattack3" : "attack3"; } if (!mCurrentWeapon.empty()) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 9bcad0994..cc057e50d 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -97,6 +97,8 @@ enum CharacterState { CharState_Death4, CharState_Death5, CharState_SwimDeath, + CharState_SwimDeathKnockDown, + CharState_SwimDeathKnockOut, CharState_DeathKnockDown, CharState_DeathKnockOut, From 3eb1308c0de1c291fbcabd1fcfbd5de0a9d64ef6 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 22 Sep 2017 15:26:35 +0400 Subject: [PATCH 117/505] Implement SwimKnockdown/out animations --- apps/openmw/mwmechanics/character.cpp | 61 +++++++++++++++++++-------- apps/openmw/mwmechanics/character.hpp | 3 ++ 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 681ca7f07..02da5ea56 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -245,21 +245,40 @@ void CharacterController::refreshHitRecoilAnims() bool recovery = mPtr.getClass().getCreatureStats(mPtr).getHitRecovery(); bool knockdown = mPtr.getClass().getCreatureStats(mPtr).getKnockedDown(); bool block = mPtr.getClass().getCreatureStats(mPtr).getBlock(); + bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr); if(mHitState == CharState_None) { if ((mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0 || mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0) && mAnimation->hasAnimation("knockout")) { - mHitState = CharState_KnockOut; - mCurrentHit = "knockout"; + if (isSwimming && mAnimation->hasAnimation("swimknockout")) + { + mHitState = CharState_SwimKnockOut; + mCurrentHit = "swimknockout"; + } + else + { + mHitState = CharState_KnockOut; + mCurrentHit = "knockout"; + } + mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, false, 1, "start", "stop", 0.0f, ~0ul); mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(true); } else if(knockdown && mAnimation->hasAnimation("knockdown")) { - mHitState = CharState_KnockDown; - mCurrentHit = "knockdown"; + if (isSwimming && mAnimation->hasAnimation("swimknockdown")) + { + mHitState = CharState_SwimKnockDown; + mCurrentHit = "swimknockdown"; + } + else + { + mHitState = CharState_KnockDown; + mCurrentHit = "knockdown"; + } + mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); } else if (recovery) @@ -282,7 +301,7 @@ void CharacterController::refreshHitRecoilAnims() } // Cancel upper body animations - if (mHitState == CharState_KnockDown || mHitState == CharState_KnockOut) + if (isKnockedOut() || isKnockedDown()) { if (mUpperBodyState > UpperCharState_WeapEquiped) { @@ -307,9 +326,9 @@ void CharacterController::refreshHitRecoilAnims() mPtr.getClass().getCreatureStats(mPtr).setBlock(false); mHitState = CharState_None; } - else if (mHitState == CharState_KnockOut && mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() > 0) + else if (isKnockedOut() && mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() > 0) { - mHitState = CharState_KnockDown; + mHitState = isSwimming ? CharState_SwimKnockDown : CharState_KnockDown; mAnimation->disable(mCurrentHit); mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "loop stop", "stop", 0.0f, 0); } @@ -680,16 +699,15 @@ void CharacterController::playRandomDeath(float startpoint) MWBase::Environment::get().getWorld()->useDeathCamera(); } - bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr); - if(isSwimming && mAnimation->hasAnimation("swimdeathknockdown") && mHitState == CharState_KnockDown) + if(mHitState == CharState_SwimKnockDown && mAnimation->hasAnimation("swimdeathknockdown")) { mDeathState = CharState_SwimDeathKnockDown; } - else if(isSwimming && mAnimation->hasAnimation("swimdeathknockout") && mHitState == CharState_KnockOut) + else if(mHitState == CharState_SwimKnockOut && mAnimation->hasAnimation("swimdeathknockout")) { mDeathState = CharState_SwimDeathKnockOut; } - else if(isSwimming && mAnimation->hasAnimation("swimdeath")) + else if(MWBase::Environment::get().getWorld()->isSwimming(mPtr) && mAnimation->hasAnimation("swimdeath")) { mDeathState = CharState_SwimDeath; } @@ -1138,8 +1156,8 @@ bool CharacterController::updateWeaponState() bool isStillWeapon = weaptype > WeapType_HandToHand && weaptype < WeapType_Spell && mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell; - if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut - && mHitState != CharState_Hit) + if(weaptype != mWeaponType && !isKnockedOut() && + !isKnockedDown() && mHitState != CharState_Hit) { forcestateupdate = true; @@ -1372,13 +1390,13 @@ bool CharacterController::updateWeaponState() } animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); - if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && mHitState != CharState_KnockDown) + if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown()) mAttackStrength = complete; } else { animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); - if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && mHitState != CharState_KnockDown) + if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown()) { float attackStrength = complete; if (!mPtr.getClass().isNpc()) @@ -1416,7 +1434,7 @@ bool CharacterController::updateWeaponState() complete = 0.f; mUpperBodyState = UpperCharState_MaxAttackToMinHit; } - else if (mHitState == CharState_KnockDown) + else if (isKnockedDown()) { if (mUpperBodyState > UpperCharState_WeapEquiped) mUpperBodyState = UpperCharState_WeapEquiped; @@ -1900,7 +1918,7 @@ void CharacterController::update(float duration) if (!mSkipAnim) { - if(mHitState != CharState_KnockDown && mHitState != CharState_KnockOut) + if(!isKnockedDown() && !isKnockedOut()) { if (rot != osg::Vec3f()) world->rotateObject(mPtr, rot.x(), rot.y(), rot.z(), true); @@ -2237,9 +2255,16 @@ bool CharacterController::isReadyToBlock() const return updateCarriedLeftVisible(mWeaponType); } +bool CharacterController::isKnockedDown() const +{ + return mHitState == CharState_KnockDown || + mHitState == CharState_SwimKnockDown; +} + bool CharacterController::isKnockedOut() const { - return mHitState == CharState_KnockOut; + return mHitState == CharState_KnockOut || + mHitState == CharState_SwimKnockOut; } bool CharacterController::isAttackingOrSpell() const diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index cc057e50d..3944c0278 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -105,6 +105,8 @@ enum CharacterState { CharState_Hit, CharState_KnockDown, CharState_KnockOut, + CharState_SwimKnockDown, + CharState_SwimKnockOut, CharState_Block }; @@ -267,6 +269,7 @@ public: bool isAttackPrepairing() const; bool isReadyToBlock() const; + bool isKnockedDown() const; bool isKnockedOut() const; bool isSneaking() const; bool isRunning() const; From 1c6cfad3cc28354774def881e3afb518141f90a0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 22 Sep 2017 15:49:42 +0400 Subject: [PATCH 118/505] Implement SwimHit animation --- apps/openmw/mwmechanics/character.cpp | 24 ++++++++++++++++++++---- apps/openmw/mwmechanics/character.hpp | 2 ++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 02da5ea56..adcd0ad68 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -283,13 +283,23 @@ void CharacterController::refreshHitRecoilAnims() } else if (recovery) { - std::string anim = chooseRandomGroup("hit"); - if (mAnimation->hasAnimation(anim)) + std::string anim = isSwimming ? chooseRandomGroup("swimhit") : chooseRandomGroup("hit"); + if (isSwimming && mAnimation->hasAnimation(anim)) { - mHitState = CharState_Hit; + mHitState = CharState_SwimHit; mCurrentHit = anim; mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); } + else + { + anim = chooseRandomGroup("hit"); + if (mAnimation->hasAnimation(anim)) + { + mHitState = CharState_Hit; + mCurrentHit = anim; + mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); + } + } } else if (block && mAnimation->hasAnimation("shield")) { @@ -1157,7 +1167,7 @@ bool CharacterController::updateWeaponState() mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell; if(weaptype != mWeaponType && !isKnockedOut() && - !isKnockedDown() && mHitState != CharState_Hit) + !isKnockedDown() && !isRecovery()) { forcestateupdate = true; @@ -2267,6 +2277,12 @@ bool CharacterController::isKnockedOut() const mHitState == CharState_SwimKnockOut; } +bool CharacterController::isRecovery() const +{ + return mHitState == CharState_Hit || + mHitState == CharState_SwimHit; +} + bool CharacterController::isAttackingOrSpell() const { return mUpperBodyState != UpperCharState_Nothing && diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 3944c0278..b6dc96776 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -103,6 +103,7 @@ enum CharacterState { CharState_DeathKnockOut, CharState_Hit, + CharState_SwimHit, CharState_KnockDown, CharState_KnockOut, CharState_SwimKnockDown, @@ -271,6 +272,7 @@ public: bool isReadyToBlock() const; bool isKnockedDown() const; bool isKnockedOut() const; + bool isRecovery() const; bool isSneaking() const; bool isRunning() const; bool isAttackingOrSpell() const; From bcad431cc52be0185f0238b8b0f9071b9ab5f04c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 22 Sep 2017 16:07:00 +0400 Subject: [PATCH 119/505] Implement SwimTurnLeft/Right animations --- apps/openmw/mwmechanics/character.cpp | 24 +++++++++++++++++------- apps/openmw/mwmechanics/character.hpp | 3 +++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index adcd0ad68..0e53f77df 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -186,6 +186,8 @@ static const StateInfo sMovementList[] = { { CharState_TurnLeft, "turnleft" }, { CharState_TurnRight, "turnright" }, + { CharState_SwimTurnLeft, "swimturnleft" }, + { CharState_SwimTurnRight, "swimturnright" }, }; static const StateInfo *sMovementListEnd = &sMovementList[sizeof(sMovementList)/sizeof(sMovementList[0])]; @@ -564,7 +566,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat // FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming update), // the idle animation should be displayed if ((mUpperBodyState != UpperCharState_Nothing - || (mMovementState != CharState_None && mMovementState != CharState_TurnLeft && mMovementState != CharState_TurnRight) + || (mMovementState != CharState_None && !isTurning()) || mHitState != CharState_None) && !mPtr.getClass().isBipedal(mPtr)) idle = CharState_None; @@ -1875,22 +1877,22 @@ void CharacterController::update(float duration) else if(rot.z() != 0.0f && !inwater && !sneak && !(mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())) { if(rot.z() > 0.0f) - movestate = CharState_TurnRight; + movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight; else if(rot.z() < 0.0f) - movestate = CharState_TurnLeft; + movestate = inwater ? CharState_SwimTurnLeft : CharState_TurnLeft; } } mTurnAnimationThreshold -= duration; - if (movestate == CharState_TurnRight || movestate == CharState_TurnLeft) + if (isTurning()) mTurnAnimationThreshold = 0.05f; - else if (movestate == CharState_None && (mMovementState == CharState_TurnRight || mMovementState == CharState_TurnLeft) + else if (movestate == CharState_None && isTurning() && mTurnAnimationThreshold > 0) { movestate = mMovementState; } - if(movestate != CharState_None && movestate != CharState_TurnLeft && movestate != CharState_TurnRight) + if(!isTurning()) clearAnimQueue(); if(mAnimQueue.empty() || inwater || sneak) @@ -1915,7 +1917,7 @@ void CharacterController::update(float duration) if (inJump) mMovementAnimationControlled = false; - if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight) + if (isTurning()) { if (duration > 0) mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z()) / duration / static_cast(osg::PI))); @@ -2277,6 +2279,14 @@ bool CharacterController::isKnockedOut() const mHitState == CharState_SwimKnockOut; } +bool CharacterController::isTurning() const +{ + return mMovementState == CharState_TurnLeft || + mMovementState == CharState_TurnRight || + mMovementState == CharState_SwimTurnLeft || + mMovementState == CharState_SwimTurnRight; +} + bool CharacterController::isRecovery() const { return mHitState == CharState_Hit || diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index b6dc96776..af90c18b8 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -88,6 +88,8 @@ enum CharacterState { CharState_TurnLeft, CharState_TurnRight, + CharState_SwimTurnLeft, + CharState_SwimTurnRight, CharState_Jump, @@ -275,6 +277,7 @@ public: bool isRecovery() const; bool isSneaking() const; bool isRunning() const; + bool isTurning() const; bool isAttackingOrSpell() const; void setAttackingOrSpell(bool attackingOrSpell); From f274bc84cc16fd3f7e8519421a3807751c6b8a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 22 Sep 2017 21:03:09 +0200 Subject: [PATCH 120/505] fix depth computation in water shader --- files/shaders/water_fragment.glsl | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index bb56e95c6..88ca33335 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -31,7 +31,7 @@ const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction const float SPEC_HARDNESS = 256.0; // specular highlights hardness -const float REFLECTION_BUMP_SUPPRESS_DEPTH = 150; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) +const float REFLECTION_BUMP_SUPPRESS_DEPTH = 0.03; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) const vec2 WIND_DIR = vec2(0.5f, -0.8f); const float WIND_SPEED = 0.2f; @@ -76,7 +76,7 @@ uniform float near; uniform float far; uniform vec3 nodePosition; -float transformDepth(float depth) // helper for transforming water depth +float linearizeDepth(float depth) // helper for transforming water depth { float z_n = 2.0 * depth - 1.0; depth = 2.0 * near * far / (far + near - z_n * (far - near)); @@ -157,12 +157,11 @@ void main(void) fresnel = clamp(fresnel, 0.0, 1.0); #if REFRACTION - float realWaterDepth = transformDepth(texture2D(refractionDepthMap, screenCoords).x); - float shore = clamp(realWaterDepth / REFLECTION_BUMP_SUPPRESS_DEPTH,0,1); + float realWaterDepth = linearizeDepth(texture2D(refractionDepthMap, screenCoords).x); + float shore = clamp(realWaterDepth / (REFLECTION_BUMP_SUPPRESS_DEPTH * (far - near)),0,1); #else float shore = 1.0; #endif - // reflection vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP*shore)).rgb; @@ -181,8 +180,7 @@ void main(void) waterColor = waterColor * length(gl_LightModel.ambient.xyz); #if REFRACTION - float refractionDepth = transformDepth(texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x); - float waterDepth = refractionDepth - depthPassthrough; + float waterDepth = linearizeDepth(texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x); if (cameraPos.z > 0.0) refraction = mix(refraction, waterColor, clamp(waterDepth/VISIBILITY, 0.0, 1.0)); @@ -200,5 +198,5 @@ void main(void) gl_FragData[0].w = 1.0; #else gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); -#endif +#endi } From 28f58d5a3251c8ab21792674979d24ee64d601d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 22 Sep 2017 21:06:03 +0200 Subject: [PATCH 121/505] add deleted letter in macro --- files/shaders/water_fragment.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 88ca33335..db319ac70 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -198,5 +198,5 @@ void main(void) gl_FragData[0].w = 1.0; #else gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); -#endi +#endif } From 9dececcbd25ddcd67394cd0b1f59bc138c18a178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 22 Sep 2017 21:10:05 +0200 Subject: [PATCH 122/505] rename a constant in water shader --- files/shaders/water_fragment.glsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index db319ac70..1e3a1e17b 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -31,7 +31,7 @@ const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction const float SPEC_HARDNESS = 256.0; // specular highlights hardness -const float REFLECTION_BUMP_SUPPRESS_DEPTH = 0.03; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) +const float BUMP_SUPPRESS_DEPTH = 0.03; // at what water depth bumpmap will be supressed for reflections and refractions (prevents artifacts at shores) const vec2 WIND_DIR = vec2(0.5f, -0.8f); const float WIND_SPEED = 0.2f; @@ -158,7 +158,7 @@ void main(void) #if REFRACTION float realWaterDepth = linearizeDepth(texture2D(refractionDepthMap, screenCoords).x); - float shore = clamp(realWaterDepth / (REFLECTION_BUMP_SUPPRESS_DEPTH * (far - near)),0,1); + float shore = clamp(realWaterDepth / (BUMP_SUPPRESS_DEPTH * (far - near)),0,1); #else float shore = 1.0; #endif From 30a213a9b3bccfcfad3e50b5eb96ecb50c6e8d70 Mon Sep 17 00:00:00 2001 From: Date: Fri, 22 Sep 2017 21:08:25 -0500 Subject: [PATCH 123/505] updates for nifstream optimization including fixing the non-x86 path for little endian reads --- components/nif/nifstream.hpp | 84 ++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 4d7e39ecb..290800042 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -14,6 +14,8 @@ #include #include +#include + #include "niftypes.hpp" namespace Nif @@ -21,49 +23,62 @@ namespace Nif class NIFFile; -template inline void readLittleEndianBufferOfType(Files::IStreamPtr &pIStream, T* dest) +/* + readLittleEndianBufferOfType: This template should only be used with non POD data types +*/ +template inline void readLittleEndianBufferOfType(Files::IStreamPtr &pIStream, T* dest) { #if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) pIStream->read((char*)dest, numInstances * sizeof(T)); #else - char buffer[numInstances * sizeof(T)]; - pIStream->read((char*)buffer, numInstances * sizeof(T)); + uint8_t* destByteBuffer = (uint8_t*)dest; + pIStream->read((char*)dest, numInstances * sizeof(T)); /* Due to the loop iterations being known at compile time, this nested loop will most likely be unrolled + For example, for 2 instances of a 4 byte data type, you should get the below result */ + union { + IntegerT i; + T t; + } u; for (uint32_t i = 0; i < numInstances; i++) { - dest[i] = 0; + u = { 0 }; for (uint32_t byte = 0; byte < sizeof(T); byte++) - dest[i] |= ((T)buffer[i * sizeof(T) + byte]) << (byte * 8); + u.i |= (((IntegerT)destByteBuffer[i * sizeof(T) + byte]) << (byte * 8)); + dest[i] = u.t; } #endif } -template inline void readLittleEndianDynamicBufferOfType(Files::IStreamPtr &pIStream, T* dest, uint32_t numInstances) +/* + readLittleEndianDynamicBufferOfType: This template should only be used with non POD data types +*/ +template inline void readLittleEndianDynamicBufferOfType(Files::IStreamPtr &pIStream, T* dest, uint32_t numInstances) { #if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) pIStream->read((char*)dest, numInstances * sizeof(T)); #else - char buffer[numInstances * sizeof(T)]; - pIStream->read((char*)buffer, numInstances * sizeof(T)); - /* - Due to the loop iterations being known at compile time, - this nested loop will most likely be unrolled - */ + uint8_t* destByteBuffer = (uint8_t*)dest; + pIStream->read((char*)dest, numInstances * sizeof(T)); + union { + IntegerT i; + T t; + } u; for (uint32_t i = 0; i < numInstances; i++) { - dest[i] = 0; + u.i = 0; for (uint32_t byte = 0; byte < sizeof(T); byte++) - dest[i] |= ((T)buffer[i * sizeof(T) + byte]) << (byte * 8); + u.i |= ((IntegerT)destByteBuffer[i * sizeof(T) + byte]) << (byte * 8); + dest[i] = u.t; } #endif } -template type inline readLittleEndianType(Files::IStreamPtr &pIStream) +template type inline readLittleEndianType(Files::IStreamPtr &pIStream) { type val; - readLittleEndianBufferOfType<1,type>(pIStream, (type*)&val); + readLittleEndianBufferOfType<1,type,IntegerT>(pIStream, (type*)&val); return val; } @@ -82,52 +97,52 @@ public: char getChar() { - return readLittleEndianType(inp); + return readLittleEndianType(inp); } short getShort() { - return readLittleEndianType(inp); + return readLittleEndianType(inp); } unsigned short getUShort() { - return readLittleEndianType(inp); + return readLittleEndianType(inp); } int getInt() { - return readLittleEndianType(inp); + return readLittleEndianType(inp); } unsigned int getUInt() { - return readLittleEndianType(inp); + return readLittleEndianType(inp); } float getFloat() { - return readLittleEndianType(inp); + return readLittleEndianType(inp); } osg::Vec2f getVector2() { osg::Vec2f vec; - readLittleEndianBufferOfType<2,float>(inp, (float*)&vec._v[0]); + readLittleEndianBufferOfType<2,float,uint32_t>(inp, (float*)&vec._v[0]); return vec; } osg::Vec3f getVector3() { osg::Vec3f vec; - readLittleEndianBufferOfType<3, float>(inp, (float*)&vec._v[0]); + readLittleEndianBufferOfType<3, float,uint32_t>(inp, (float*)&vec._v[0]); return vec; } osg::Vec4f getVector4() { osg::Vec4f vec; - readLittleEndianBufferOfType<4, float>(inp, (float*)&vec._v[0]); + readLittleEndianBufferOfType<4, float,uint32_t>(inp, (float*)&vec._v[0]); return vec; } Matrix3 getMatrix3() { Matrix3 mat; - readLittleEndianBufferOfType<9, float>(inp, (float*)&mat.mValues); + readLittleEndianBufferOfType<9, float,uint32_t>(inp, (float*)&mat.mValues); return mat; } osg::Quat getQuaternion() { float f[4]; - readLittleEndianBufferOfType<4, float>(inp, (float*)&f); + readLittleEndianBufferOfType<4, float,uint32_t>(inp, (float*)&f); osg::Quat quat; quat.w() = f[0]; quat.x() = f[1]; @@ -153,7 +168,7 @@ public: } ///Read in a string of the length specified in the file std::string getString() { - size_t size = readLittleEndianType(inp); + size_t size = readLittleEndianType(inp); return getString(size); } ///This is special since the version string doesn't start with a number, and ends with "\n" @@ -165,23 +180,26 @@ public: void getUShorts(std::vector &vec, size_t size) { vec.resize(size); - readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); + readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); } void getFloats(std::vector &vec, size_t size) { vec.resize(size); - readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); + readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); } void getVector2s(std::vector &vec, size_t size) { vec.resize(size); - readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); + /* The packed storage of each Vec2f is 2 floats exactly */ + readLittleEndianDynamicBufferOfType(inp,(float*) &vec.front(), size*2); } void getVector3s(std::vector &vec, size_t size) { vec.resize(size); - readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); + /* The packed storage of each Vec3f is 3 floats exactly */ + readLittleEndianDynamicBufferOfType(inp, (float*) &vec.front(), size*3); } void getVector4s(std::vector &vec, size_t size) { vec.resize(size); - readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); + /* The packed storage of each Vec4f is 4 floats exactly */ + readLittleEndianDynamicBufferOfType(inp, (float*) &vec.front(), size*4); } void getQuaternions(std::vector &quat, size_t size) { quat.resize(size); From 4921e7f5c1e2be8c4820bf8228ce83851ceccb16 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 22 Sep 2017 21:29:40 -0400 Subject: [PATCH 124/505] Get rid of reinterpret cast. --- apps/opencs/model/world/columnimp.cpp | 129 +++++++++++++------------- apps/opencs/model/world/columnimp.hpp | 12 +++ apps/opencs/model/world/commands.cpp | 24 ++--- apps/opencs/model/world/commands.hpp | 6 +- 4 files changed, 93 insertions(+), 78 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index 6a19df0d5..18da81b53 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -1,6 +1,7 @@ #include "columnimp.hpp" #include +#include namespace CSMWorld { @@ -86,33 +87,32 @@ namespace CSMWorld const int Size = Land::LAND_GLOBAL_MAP_LOD_SIZE; const Land& land = record.get(); + DataType values(Size, 0); + if (land.isDataLoaded(Land::DATA_WNAM)) { - // Note: original data is signed - const char* rawData = reinterpret_cast(&land.mWnam[0]); - return QByteArray(rawData, Size); - } - else - { - // Return a blank array - return QByteArray(Size, 0); + for (int i = 0; i < Size; ++i) + values[i] = land.mWnam[i]; } + + QVariant variant; + variant.setValue(values); + return variant; } void LandMapLodColumn::set(Record& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const signed char* rawData = reinterpret_cast(array.data()); + DataType values = data.value(); - if (array.count() != Land::LAND_GLOBAL_MAP_LOD_SIZE) + if (values.size() != Land::LAND_GLOBAL_MAP_LOD_SIZE) throw std::runtime_error("invalid land map LOD data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_WNAM); - for (int i = 0; i < array.count(); ++i) + for (int i = 0; i < values.size(); ++i) { - copy.mWnam[i] = rawData[i]; + copy.mWnam[i] = values[i]; } record.setModified(copy); @@ -134,33 +134,32 @@ namespace CSMWorld const int Size = Land::LAND_NUM_VERTS * 3; const Land& land = record.get(); + DataType values(Size, 0); + if (land.isDataLoaded(Land::DATA_VNML)) { - // Note: original data is signed - const char* rawData = reinterpret_cast(&land.getLandData()->mNormals[0]); - return QByteArray(rawData, Size); - } - else - { - // Return a blank array - return QByteArray(Size, 0); + for (int i = 0; i < Size; ++i) + values[i] = land.getLandData()->mNormals[i]; } + + QVariant variant; + variant.setValue(values); + return variant; } void LandNormalsColumn::set(Record& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const signed char* rawData = reinterpret_cast(array.data()); + DataType values = data.value(); - if (array.count() != Land::LAND_NUM_VERTS * 3) + if (values.size() != Land::LAND_NUM_VERTS * 3) throw std::runtime_error("invalid land normals data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VNML); - for (int i = 0; i < array.count(); ++i) + for (int i = 0; i < values.size(); ++i) { - copy.getLandData()->mNormals[i] = rawData[i]; + copy.getLandData()->mNormals[i] = values[i]; } record.setModified(copy); @@ -179,36 +178,35 @@ namespace CSMWorld QVariant LandHeightsColumn::get(const Record& record) const { - const int Size = Land::LAND_NUM_VERTS * sizeof(float); + const int Size = Land::LAND_NUM_VERTS; const Land& land = record.get(); + DataType values(Size, 0); + if (land.isDataLoaded(Land::DATA_VHGT)) { - // Note: original data is float - const char* rawData = reinterpret_cast(&land.getLandData()->mHeights[0]); - return QByteArray(rawData, Size); - } - else - { - return QByteArray(Size, 0); + for (int i = 0; i < Size; ++i) + values[i] = land.getLandData()->mHeights[i]; } + + QVariant variant; + variant.setValue(values); + return variant; } void LandHeightsColumn::set(Record& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const float* rawData = reinterpret_cast(array.data()); + DataType values = data.value(); - if (array.count() != Land::LAND_NUM_VERTS * sizeof(float)) + if (values.size() != Land::LAND_NUM_VERTS) throw std::runtime_error("invalid land heights data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VHGT); - int count = array.count() / sizeof(float); - for (int i = 0; i < count; ++i) + for (int i = 0; i < values.size(); ++i) { - copy.getLandData()->mHeights[i] = rawData[i]; + copy.getLandData()->mHeights[i] = values[i]; } record.setModified(copy); @@ -230,32 +228,32 @@ namespace CSMWorld const int Size = Land::LAND_NUM_VERTS * 3; const Land& land = record.get(); + DataType values(Size, 0); + if (land.isDataLoaded(Land::DATA_VCLR)) { - // Note: original data is unsigned char - const char* rawData = reinterpret_cast(&land.getLandData()->mColours[0]); - return QByteArray(rawData, Size); - } - else - { - return QByteArray(Size, 0); + for (int i = 0; i < Size; ++i) + values[i] = land.getLandData()->mColours[i]; } + + QVariant variant; + variant.setValue(values); + return variant; } void LandColoursColumn::set(Record& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const unsigned char* rawData = reinterpret_cast(array.data()); + DataType values = data.value(); - if (array.count() != Land::LAND_NUM_VERTS * 3) + if (values.size() != Land::LAND_NUM_VERTS * 3) throw std::runtime_error("invalid land colours data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VCLR); - for (int i = 0; i < array.count(); ++i) + for (int i = 0; i < values.size(); ++i) { - copy.getLandData()->mColours[i] = rawData[i]; + copy.getLandData()->mColours[i] = values[i]; } record.setModified(copy); @@ -274,36 +272,35 @@ namespace CSMWorld QVariant LandTexturesColumn::get(const Record& record) const { - const int Size = Land::LAND_NUM_TEXTURES * sizeof(uint16_t); + const int Size = Land::LAND_NUM_TEXTURES; const Land& land = record.get(); + DataType values(Size, 0); + if (land.isDataLoaded(Land::DATA_VTEX)) { - // Note: original data is uint16_t - const char* rawData = reinterpret_cast(&land.getLandData()->mTextures[0]); - return QByteArray(rawData, Size); - } - else - { - return QByteArray(Size, 0); + for (int i = 0; i < Size; ++i) + values[i] = land.getLandData()->mTextures[i]; } + + QVariant variant; + variant.setValue(values); + return variant; } void LandTexturesColumn::set(Record& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const uint16_t* rawData = reinterpret_cast(array.data()); + DataType values = data.value(); - if (array.count() != Land::LAND_NUM_TEXTURES * sizeof(uint16_t)) + if (values.size() != Land::LAND_NUM_TEXTURES) throw std::runtime_error("invalid land textures data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VTEX); - int count = array.count() / sizeof(uint16_t); - for (int i = 0; i < count; ++i) + for (int i = 0; i < values.size(); ++i) { - copy.getLandData()->mTextures[i] = rawData[i]; + copy.getLandData()->mTextures[i] = values[i]; } record.setModified(copy); diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 025b064c6..d653ddece 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2,10 +2,12 @@ #define CSM_WOLRD_COLUMNIMP_H #include +#include #include #include #include +#include #include #include @@ -2470,6 +2472,8 @@ namespace CSMWorld struct LandMapLodColumn : public Column { + using DataType = QVector; + LandMapLodColumn(); QVariant get(const Record& record) const override; @@ -2479,6 +2483,8 @@ namespace CSMWorld struct LandNormalsColumn : public Column { + using DataType = QVector; + LandNormalsColumn(); QVariant get(const Record& record) const override; @@ -2488,6 +2494,8 @@ namespace CSMWorld struct LandHeightsColumn : public Column { + using DataType = QVector; + LandHeightsColumn(); QVariant get(const Record& record) const override; @@ -2497,6 +2505,8 @@ namespace CSMWorld struct LandColoursColumn : public Column { + using DataType = QVector; + LandColoursColumn(); QVariant get(const Record& record) const override; @@ -2506,6 +2516,8 @@ namespace CSMWorld struct LandTexturesColumn : public Column { + using DataType = QVector; + LandTexturesColumn(); QVariant get(const Record& record) const override; diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index b654eb00d..79900c6c4 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -58,23 +58,21 @@ void CSMWorld::ImportLandTexturesCommand::redo() // Original data int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); - mOld = mLands.data(mLands.getModelIndex(getOriginId(), textureColumn)).toByteArray(); - const uint16_t* textureData = reinterpret_cast(mOld.data()); + mOld = mLands.data(mLands.getModelIndex(getOriginId(), textureColumn)).value(); // Need to make a copy so the old values can be looked up - QByteArray newTextureByteArray(mOld.data(), mOld.size()); - uint16_t* newTextureData = reinterpret_cast(newTextureByteArray.data()); + DataType copy(mOld); // Perform touch/copy/etc... onRedo(); // Find all indices used std::unordered_set texIndices; - for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) + for (int i = 0; i < mOld.size(); ++i) { // All indices are offset by 1 for a default texture - if (textureData[i] > 0) - texIndices.insert(textureData[i] - 1); + if (mOld[i] > 0) + texIndices.insert(mOld[i] - 1); } std::vector oldTextures; @@ -97,8 +95,8 @@ void CSMWorld::ImportLandTexturesCommand::redo() for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) { // All indices are offset by 1 for a default texture - if (textureData[i] == oldIndex + 1) - newTextureData[i] = newIndex + 1; + if (mOld[i] == oldIndex + 1) + copy[i] = newIndex + 1; } } } @@ -107,14 +105,18 @@ void CSMWorld::ImportLandTexturesCommand::redo() int stateColumn = mLands.findColumnIndex(Columns::ColumnId_Modification); mOldState = mLands.data(mLands.getModelIndex(getDestinationId(), stateColumn)).toInt(); - mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), newTextureByteArray); + QVariant variant; + variant.setValue(copy); + mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), variant); } void CSMWorld::ImportLandTexturesCommand::undo() { // Restore to previous int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); - mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), mOld); + QVariant variant; + variant.setValue(mOld); + mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), variant); int stateColumn = mLands.findColumnIndex(Columns::ColumnId_Modification); mLands.setData(mLands.getModelIndex(getDestinationId(), stateColumn), mOldState); diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index aab0c5410..0f9d3591c 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -3,12 +3,14 @@ #include "record.hpp" +#include #include #include #include #include #include +#include #include #include @@ -55,6 +57,8 @@ namespace CSMWorld protected: + using DataType = QVector; + virtual const std::string& getOriginId() const = 0; virtual const std::string& getDestinationId() const = 0; @@ -63,7 +67,7 @@ namespace CSMWorld IdTable& mLands; IdTable& mLtexs; - QByteArray mOld; + DataType mOld; int mOldState; std::vector mCreatedTextures; }; From 054e6a780e2c8fa4bbf1863751020ab036e5ad96 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 22 Sep 2017 22:43:45 -0400 Subject: [PATCH 125/505] Use map for texture lookup. --- apps/opencs/model/world/idtable.cpp | 39 ++++++++++++++++------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index b41eea8f8..2c066ff6c 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -340,6 +341,15 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import { ImportResults results; + // Map existing textures to ids + std::map reverseLookupMap; + for (int i = 0; i < idCollection()->getSize(); ++i) + { + auto& record = static_cast&>(idCollection()->getRecord(i)); + if (record.isModified()) + reverseLookupMap.emplace(record.get().mTexture, idCollection()->getId(i)); + } + for (const std::string& id : ids) { int plugin, index; @@ -354,8 +364,16 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import continue; } - // Try a direct mapping to the current plugin first. Otherwise iterate until one is found. - // Iteration is deterministic to avoid duplicates. + // Look for a pre-existing record + auto& record = static_cast&>(idCollection()->getRecord(oldRow)); + auto searchIt = reverseLookupMap.find(record.get().mTexture); + if (searchIt != reverseLookupMap.end()) + { + results.recordMapping.push_back(std::make_pair(id, searchIt->second)); + continue; + } + + // Iterate until an unused index or found, or the index has completely wrapped around. int startIndex = index; do { std::string newId = LandTexture::createUniqueRecordId(0, index); @@ -370,21 +388,8 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import break; } - // Id is taken, check if same handle and texture. Note that mId is the handle. - const LandTexture& oldLtex = dynamic_cast&>(idCollection()->getRecord(oldRow)).get(); - const LandTexture& newLtex = dynamic_cast&>(idCollection()->getRecord(newRow)).get(); - if (oldLtex.mId == newLtex.mId && oldLtex.mTexture == newLtex.mTexture) - { - // It's a match - results.recordMapping.push_back(std::make_pair(id, newId)); - break; - } - - // Determine next index. Spread out the indices to reduce conflicts. - size_t MaxIndex = std::numeric_limits::max() - 1; - size_t Prime = (1 << 13) - 1; // A mersenne prime - - index = (index + Prime) % MaxIndex; + const size_t MaxIndex = std::numeric_limits::max() - 1; + index = (index + 1) % MaxIndex; } while (index != startIndex); } From 3981f79d38af642f423b4adb5666b98a596a24f9 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 22 Sep 2017 22:59:50 -0400 Subject: [PATCH 126/505] Change flag for base land textures --- apps/opencs/model/world/idtable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 2c066ff6c..54d65ac3f 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -332,7 +332,7 @@ Qt::ItemFlags CSMWorld::LandTextureIdTable::flags(const QModelIndex& index) cons Qt::ItemFlags flags = IdTable::flags(index); if (!idCollection()->getRecord(index.row()).isModified()) - flags &= ~Qt::ItemIsEditable; + flags &= ~Qt::ItemIsEnabled; return flags; } From 1fe1ec63c43af800d3988081b802e690ad8d0a34 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 22 Sep 2017 23:33:50 -0400 Subject: [PATCH 127/505] Fix Qt4 build --- apps/opencs/model/world/columnimp.hpp | 7 +++++++ apps/opencs/model/world/commands.hpp | 5 ++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index d653ddece..e36e386c9 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2537,4 +2537,11 @@ namespace CSMWorld }; } +// This is required to access the type as a QVariant. +Q_DECLARE_METATYPE(CSMWorld::LandMapLodColumn::DataType) +//Q_DECLARE_METATYPE(CSMWorld::LandNormalsColumn::DataType) // Same as LandMapLodColumn::DataType +Q_DECLARE_METATYPE(CSMWorld::LandHeightsColumn::DataType) +Q_DECLARE_METATYPE(CSMWorld::LandColoursColumn::DataType) +Q_DECLARE_METATYPE(CSMWorld::LandTexturesColumn::DataType) + #endif diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 0f9d3591c..be86dd508 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -3,17 +3,16 @@ #include "record.hpp" -#include #include #include #include #include #include -#include #include #include +#include "columnimp.hpp" #include "universalid.hpp" #include "nestedtablewrapper.hpp" @@ -57,7 +56,7 @@ namespace CSMWorld protected: - using DataType = QVector; + using DataType = LandTexturesColumn::DataType; virtual const std::string& getOriginId() const = 0; virtual const std::string& getDestinationId() const = 0; From a57f6ac2af8fdb759b9f93c15bc451969fac598a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 23 Sep 2017 08:25:58 +0400 Subject: [PATCH 128/505] Fix a typo in attack animation name --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 0e53f77df..6e1e075fb 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -925,7 +925,7 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Chop); else if (groupname == "attack2" || groupname == "swimattack2") mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Slash); - else if (groupname == "attack3" || groupname == "swimattack1") + else if (groupname == "attack3" || groupname == "swimattack3") mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Thrust); else mPtr.getClass().hit(mPtr, mAttackStrength); From 825de71b294867a177cfd44543da10b0f4d45fa2 Mon Sep 17 00:00:00 2001 From: Date: Sat, 23 Sep 2017 11:10:05 -0500 Subject: [PATCH 129/505] removed an iostream include used for debug prints from nifstream.hpp --- components/nif/nifstream.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 290800042..d00069be7 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -14,8 +14,6 @@ #include #include -#include - #include "niftypes.hpp" namespace Nif From b5f5268ff347a6730cac4526829c12ef3a2c44ba Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 23 Sep 2017 18:54:17 +0200 Subject: [PATCH 130/505] Clean up faraway projectiles --- apps/openmw/mwworld/projectilemanager.cpp | 62 ++++++++++++++++++++--- apps/openmw/mwworld/projectilemanager.hpp | 5 ++ 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 6e716cb54..ede8c34c4 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -149,6 +149,7 @@ namespace MWWorld , mResourceSystem(resourceSystem) , mRendering(rendering) , mPhysics(physics) + , mCleanupTimer(0.0f) { } @@ -326,10 +327,49 @@ namespace MWWorld void ProjectileManager::update(float dt) { + periodicCleanup(dt); moveProjectiles(dt); moveMagicBolts(dt); } + void ProjectileManager::periodicCleanup(float dt) + { + mCleanupTimer -= dt; + if (mCleanupTimer <= 0.0f) + { + mCleanupTimer = 2.0f; + + auto isCleanable = [](const ProjectileManager::State& state) -> bool + { + const float farawayThreshold = 72000.0f; + osg::Vec3 playerPos = MWMechanics::getPlayer().getRefData().getPosition().asVec3(); + return (state.mNode->getPosition() - playerPos).length2() >= farawayThreshold*farawayThreshold; + }; + + for (std::vector::iterator it = mProjectiles.begin(); it != mProjectiles.end();) + { + if (isCleanable(*it)) + { + cleanupProjectile(*it); + it = mProjectiles.erase(it); + } + else + ++it; + } + + for (std::vector::iterator it = mMagicBolts.begin(); it != mMagicBolts.end();) + { + if (isCleanable(*it)) + { + cleanupMagicBolt(*it); + it = mMagicBolts.erase(it); + } + else + ++it; + } + } + } + void ProjectileManager::moveMagicBolts(float duration) { for (std::vector::iterator it = mMagicBolts.begin(); it != mMagicBolts.end();) @@ -468,20 +508,30 @@ namespace MWWorld } } + void ProjectileManager::cleanupProjectile(ProjectileManager::ProjectileState& state) + { + mParent->removeChild(state.mNode); + } + + void ProjectileManager::cleanupMagicBolt(ProjectileManager::MagicBoltState& state) + { + mParent->removeChild(state.mNode); + for (size_t soundIter = 0; soundIter != state.mSounds.size(); soundIter++) + { + MWBase::Environment::get().getSoundManager()->stopSound(state.mSounds.at(soundIter)); + } + } + void ProjectileManager::clear() { for (std::vector::iterator it = mProjectiles.begin(); it != mProjectiles.end(); ++it) { - mParent->removeChild(it->mNode); + cleanupProjectile(*it); } mProjectiles.clear(); for (std::vector::iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it) { - mParent->removeChild(it->mNode); - for (size_t soundIter = 0; soundIter != it->mSounds.size(); soundIter++) - { - MWBase::Environment::get().getSoundManager()->stopSound(it->mSounds.at(soundIter)); - } + cleanupMagicBolt(*it); } mMagicBolts.clear(); } diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 1ef72a048..0dfbf6080 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -68,6 +68,7 @@ namespace MWWorld Resource::ResourceSystem* mResourceSystem; MWRender::RenderingManager* mRendering; MWPhysics::PhysicsSystem* mPhysics; + float mCleanupTimer; struct State { @@ -116,6 +117,10 @@ namespace MWWorld std::vector mMagicBolts; std::vector mProjectiles; + void cleanupProjectile(ProjectileState& state); + void cleanupMagicBolt(MagicBoltState& state); + void periodicCleanup(float dt); + void moveProjectiles(float dt); void moveMagicBolts(float dt); From 91adfc9fc0d91afb373b243ee18f81458356de8d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 23 Sep 2017 20:59:06 +0400 Subject: [PATCH 131/505] AiWander: reset spawn position, if an actor was moved to another cell (bug #4010) --- apps/openmw/mwmechanics/aiwander.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b44b187ad..7f412b4d2 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -200,6 +200,7 @@ namespace MWMechanics stopWalking(actor, storage); currentCell = actor.getCell(); storage.mPopulateAvailableNodes = true; + mStoredInitialActorPosition = false; } mRemainingDuration -= ((duration*MWBase::Environment::get().getWorld()->getTimeScaleFactor()) / 3600); From 9b04a7c1e66c5f090f78c3ad0c4ad44bc46d9e4b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 24 Sep 2017 16:26:41 +0400 Subject: [PATCH 132/505] Fix idle animations playing --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6e1e075fb..ec65255bc 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1892,7 +1892,7 @@ void CharacterController::update(float duration) movestate = mMovementState; } - if(!isTurning()) + if(movestate != CharState_None && !isTurning()) clearAnimQueue(); if(mAnimQueue.empty() || inwater || sneak) From 7d703a13a3024e2428928fb34f246cc3838d4fa7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 24 Sep 2017 16:28:05 +0400 Subject: [PATCH 133/505] Fix a crash in the World::isUnderwater() if the cell is empty --- 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 40bc13c94..2a25d5bbc 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2123,6 +2123,9 @@ namespace MWWorld bool World::isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const { + if (!cell) + return false; + if (!(cell->getCell()->hasWater())) { return false; } From b22fedf4ae922a0b3dab3c9f7d7b3374a921fdc8 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 16:13:22 +0200 Subject: [PATCH 134/505] Check 'sYes' in addition to 'sOk' for message box's default keyfocus --- apps/openmw/mwgui/messagebox.cpp | 30 +++++++++++------------------- apps/openmw/mwgui/messagebox.hpp | 1 - 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index ab43df0f1..f9c445d36 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -228,8 +228,7 @@ namespace MWGui int buttonHeight = 0; MyGUI::IntCoord dummyCoord(0, 0, 0, 0); - std::vector::const_iterator it; - for(it = buttons.begin(); it != buttons.end(); ++it) + for(std::vector::const_iterator it = buttons.begin(); it != buttons.end(); ++it) { MyGUI::Button* button = mButtonsWidget->createWidget( MyGUI::WidgetStyle::Child, @@ -289,8 +288,7 @@ namespace MWGui MyGUI::IntSize buttonSize(0, buttonHeight); int left = (mainWidgetSize.width - buttonsWidth)/2; - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) + for(std::vector::const_iterator button = mButtons.begin(); button != mButtons.end(); ++button) { buttonCord.left = left; buttonCord.top = messageWidgetCoord.top + textSize.height + textButtonPadding; @@ -319,8 +317,7 @@ namespace MWGui int top = textPadding + textSize.height + textButtonPadding; - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) + for(std::vector::const_iterator button = mButtons.begin(); button != mButtons.end(); ++button) { buttonSize.width = (*button)->getTextSize().width + buttonPadding*2; buttonSize.height = (*button)->getTextSize().height + buttonPadding*2; @@ -354,25 +351,20 @@ namespace MWGui } // Set key focus to "Ok" button - std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) + std::vector keywords { "sOk", "sYes" }; + for(std::vector::const_iterator button = mButtons.begin(); button != mButtons.end(); ++button) { - if(Misc::StringUtils::ciEqual((*button)->getCaption(), ok)) + for (const std::string& keyword : keywords) { - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(*button); - (*button)->eventKeyButtonPressed += MyGUI::newDelegate(this, &InteractiveMessageBox::onKeyPressed); - break; + if(Misc::StringUtils::ciEqual(MyGUI::LanguageManager::getInstance().replaceTags("#{" + keyword + "}"), (*button)->getCaption())) + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(*button); + return; + } } } } - void InteractiveMessageBox::onKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) - { - if (_key == MyGUI::KeyCode::Return || _key == MyGUI::KeyCode::NumpadEnter || _key == MyGUI::KeyCode::Space) - buttonActivated(_sender); - } - void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed) { buttonActivated (pressed); diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index b4121fed3..38e6590b7 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -81,7 +81,6 @@ namespace MWGui private: void buttonActivated (MyGUI::Widget* _widget); - void onKeyPressed(MyGUI::Widget* _sender, MyGUI::KeyCode _key, MyGUI::Char _char); MessageBoxManager& mMessageBoxManager; MyGUI::EditBox* mMessageWidget; From e7ad01297753e0184bd34c817a4ee79552560052 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 16:34:34 +0200 Subject: [PATCH 135/505] Pass repeat key events to the GUI For example, one can scroll to the last element in a list by holding down the 'Down Arrow' key. --- apps/openmw/mwinput/inputmanagerimp.cpp | 3 +++ components/sdlutil/sdlinputwrapper.cpp | 11 ++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index e4fa8fc2b..cc41b3831 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -679,6 +679,9 @@ namespace MWInput bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); setPlayerControlsEnabled(!guiFocus); } + if (arg.repeat) + return; + if (!mControlsDisabled && !consumed) mInputBinder->keyPressed (arg); mJoystickLastUsed = false; diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index a76de00d1..634c4884f 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -85,14 +85,11 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mMouseListener->mouseReleased(evt.button, evt.button.button); break; case SDL_KEYDOWN: - if (!evt.key.repeat) - { - mKeyboardListener->keyPressed(evt.key); + mKeyboardListener->keyPressed(evt.key); - if (!isModifierHeld(KMOD_ALT) && evt.key.keysym.sym >= SDLK_F1 && evt.key.keysym.sym <= SDLK_F12) - { - mViewer->getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_F1 + (evt.key.keysym.sym - SDLK_F1)); - } + if (!isModifierHeld(KMOD_ALT) && evt.key.keysym.sym >= SDLK_F1 && evt.key.keysym.sym <= SDLK_F12) + { + mViewer->getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_F1 + (evt.key.keysym.sym - SDLK_F1)); } break; From c11fe6788fff68a73444c60409d6551f13678995 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 16:52:39 +0200 Subject: [PATCH 136/505] Add basic keyboard navigation for the GUI (Shift)Tab cycles, arrow keys move to the next button in that direction, Enter/Space accepts. Note: Unless MyGUI is hacked to bits, clicking on an empty space will annoyingly reset the key focus. Not sure how to deal with that yet. The visual highlight for selected buttons requires MyGUI commit 632d007429d0bf0c7d7f6c5db4a08353a63dd839 or later to appear (to be released in 3.2.3). --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/windowmanager.hpp | 4 + apps/openmw/mwgui/keyboardnavigation.cpp | 140 +++++++++++++++++++++++ apps/openmw/mwgui/keyboardnavigation.hpp | 27 +++++ apps/openmw/mwgui/windowmanagerimp.cpp | 12 ++ apps/openmw/mwgui/windowmanagerimp.hpp | 5 + apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- files/mygui/openmw_button.skin.xml | 1 + 8 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 apps/openmw/mwgui/keyboardnavigation.cpp create mode 100644 apps/openmw/mwgui/keyboardnavigation.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 00ae2fa4a..43952afdb 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -42,7 +42,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 timeadvancer jailscreen itemchargeview + draganddrop timeadvancer jailscreen itemchargeview keyboardnavigation ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4560ab270..37c3ce0d3 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -7,6 +7,8 @@ #include #include +#include + #include "../mwgui/mode.hpp" namespace Loading @@ -368,6 +370,8 @@ namespace MWBase virtual void writeFog(MWWorld::CellStore* cell) = 0; virtual const MWGui::TextColours& getTextColours() = 0; + + virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text) = 0; }; } diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp new file mode 100644 index 000000000..840a12f1e --- /dev/null +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -0,0 +1,140 @@ +#include "keyboardnavigation.hpp" + +#include +#include +#include + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/environment.hpp" + +namespace MWGui +{ + +/// Recursively get all child widgets that accept keyboard input +void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& results) +{ + MyGUI::EnumeratorWidgetPtr enumerator = parent->getEnumerator(); + while (enumerator.next()) + { + MyGUI::Widget* w = enumerator.current(); + if (!w->getVisible() || !w->getEnabled()) + continue; + if (w->getNeedKeyFocus()) + results.push_back(w); + else + getKeyFocusWidgets(w, results); + } +} + +KeyboardNavigation::KeyboardNavigation() +{ +} + +KeyboardNavigation::~KeyboardNavigation() +{ +} + +bool isButtonFocus() +{ + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + return focus->getTypeName().find("Button") != std::string::npos; +} + +enum Direction +{ + D_Left, + D_Up, + D_Right, + D_Down, + D_Next, + D_Prev +}; + +bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text) +{ + switch (key.getValue()) + { + case MyGUI::KeyCode::ArrowLeft: + return switchFocus(D_Left, false); + case MyGUI::KeyCode::ArrowRight: + return switchFocus(D_Right, false); + case MyGUI::KeyCode::ArrowUp: + return switchFocus(D_Up, false); + case MyGUI::KeyCode::ArrowDown: + return switchFocus(D_Down, false); + case MyGUI::KeyCode::Tab: + return switchFocus(MyGUI::InputManager::getInstance().isShiftPressed() ? D_Prev : D_Next, true); + case MyGUI::KeyCode::Return: + case MyGUI::KeyCode::NumpadEnter: + case MyGUI::KeyCode::Space: + return accept(); + default: + return false; + } +} + +bool KeyboardNavigation::switchFocus(int direction, bool wrap) +{ + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + if (!focus) + return false; + + if (!isButtonFocus() && direction != D_Prev && direction != D_Next) + return false; + + MyGUI::Widget* window = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + while (window->getParent()) + window = window->getParent(); + + MyGUI::VectorWidgetPtr keyFocusList; + getKeyFocusWidgets(window, keyFocusList); + + if (keyFocusList.empty()) + return false; + + MyGUI::VectorWidgetPtr::iterator found = std::find(keyFocusList.begin(), keyFocusList.end(), focus); + if (found == keyFocusList.end()) + return false; + + bool forward = (direction == D_Next || direction == D_Right || direction == D_Down); + + int index = found - keyFocusList.begin(); + index = forward ? (index+1) : (index-1); + if (wrap) + index = (index + keyFocusList.size())%keyFocusList.size(); + else + index = std::min(std::max(0, index), static_cast(keyFocusList.size())-1); + + MyGUI::Widget* next = keyFocusList[index]; + int vertdiff = next->getTop() - focus->getTop(); + int horizdiff = next->getLeft() - focus->getLeft(); + if (direction == D_Right && horizdiff <= 0) + return false; + else if (direction == D_Left && horizdiff >= 0) + return false; + else if (direction == D_Down && vertdiff <= 0) + return false; + else if (direction == D_Up && vertdiff >= 0) + return false; + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[index]); + return true; +} + +bool KeyboardNavigation::accept() +{ + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + if (!focus) + return false; + //MyGUI::Button* button = focus->castType(false); + //if (button && button->getEnabled()) + if (focus->getTypeName().find("Button") != std::string::npos && focus->getEnabled()) + { + focus->eventMouseButtonClick(focus); + return true; + } + return false; +} + + +} diff --git a/apps/openmw/mwgui/keyboardnavigation.hpp b/apps/openmw/mwgui/keyboardnavigation.hpp new file mode 100644 index 000000000..86cc67962 --- /dev/null +++ b/apps/openmw/mwgui/keyboardnavigation.hpp @@ -0,0 +1,27 @@ +#ifndef OPENMW_MWGUI_KEYBOARDNAVIGATION_H +#define OPENMW_MWGUI_KEYBOARDNAVIGATION_H + +#include + +namespace MWGui +{ + + class KeyboardNavigation + { + public: + KeyboardNavigation(); + ~KeyboardNavigation(); + + /// @return Was the key handled by this class? + bool injectKeyPress(MyGUI::KeyCode key, unsigned int text); + + private: + bool switchFocus(int direction, bool wrap); + + /// Send button press event to focused button + bool accept(); + }; + +} + +#endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1526949a3..5d7a54735 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -112,6 +112,7 @@ #include "controllers.hpp" #include "jailscreen.hpp" #include "itemchargeview.hpp" +#include "keyboardnavigation.hpp" namespace { @@ -248,6 +249,8 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); MyGUI::ResourceManager::getInstance().load("core.xml"); + mKeyboardNavigation.reset(new KeyboardNavigation()); + mLoadingScreen = new LoadingScreen(mResourceSystem->getVFS(), mViewer); //set up the hardware cursor manager @@ -433,6 +436,8 @@ namespace MWGui WindowManager::~WindowManager() { + mKeyboardNavigation.reset(); + MyGUI::LanguageManager::getInstance().eventRequestTag.clear(); MyGUI::PointerManager::getInstance().eventChangeMousePointer.clear(); MyGUI::InputManager::getInstance().eventChangeKeyFocus.clear(); @@ -2202,4 +2207,11 @@ namespace MWGui return mTextColours; } + bool WindowManager::injectKeyPress(MyGUI::KeyCode key, unsigned int text) + { + if (!mKeyboardNavigation->injectKeyPress(key, text)) + return MyGUI::InputManager::getInstance().injectKeyPress(key, text); + else + return true; + } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 4f06afb7d..3e17046df 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -122,6 +122,7 @@ namespace MWGui class ScreenFader; class DebugWindow; class JailScreen; + class KeyboardNavigation; class WindowManager : public MWBase::WindowManager { @@ -397,6 +398,8 @@ namespace MWGui virtual const MWGui::TextColours& getTextColours(); + virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text); + private: const MWWorld::ESMStore* mStore; Resource::ResourceSystem* mResourceSystem; @@ -522,6 +525,8 @@ namespace MWGui MWGui::TextColours mTextColours; + std::unique_ptr mKeyboardNavigation; + /** * Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property. * Supported syntax: diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index cc41b3831..33f1edb6c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -676,7 +676,7 @@ namespace MWInput { consumed = SDL_IsTextInputActive() && ( !(SDLK_SCANCODE_MASK & arg.keysym.sym) && std::isprint(arg.keysym.sym)); // Little trick to check if key is printable - bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + bool guiFocus = MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); setPlayerControlsEnabled(!guiFocus); } if (arg.repeat) diff --git a/files/mygui/openmw_button.skin.xml b/files/mygui/openmw_button.skin.xml index 5aee8de7a..ac9bf042d 100644 --- a/files/mygui/openmw_button.skin.xml +++ b/files/mygui/openmw_button.skin.xml @@ -71,6 +71,7 @@ + From 1ad14b232fd93d4f96493169830969f42b2fe498 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 16:57:01 +0200 Subject: [PATCH 137/505] Adjust ImageButton to accept key focus and use the 'highlighted' texture --- components/widgets/imagebutton.cpp | 54 +++++++++++++++++++++++++----- components/widgets/imagebutton.hpp | 11 ++++++ 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/components/widgets/imagebutton.cpp b/components/widgets/imagebutton.cpp index 8e3f8ed69..ab0739c2c 100644 --- a/components/widgets/imagebutton.cpp +++ b/components/widgets/imagebutton.cpp @@ -5,6 +5,15 @@ namespace Gui { + ImageButton::ImageButton() + : Base() + , mMouseFocus(false) + , mMousePress(false) + , mKeyFocus(false) + { + setNeedKeyFocus(true); + } + void ImageButton::setPropertyOverride(const std::string &_key, const std::string &_value) { if (_key == "ImageHighlighted") @@ -24,22 +33,36 @@ namespace Gui } void ImageButton::onMouseSetFocus(Widget* _old) { - setImageTexture(mImageHighlighted); - ImageBox::onMouseSetFocus(_old); + mMouseFocus = true; + updateImage(); + Base::onMouseSetFocus(_old); } void ImageButton::onMouseLostFocus(Widget* _new) { - setImageTexture(mImageNormal); - ImageBox::onMouseLostFocus(_new); + mMouseFocus = false; + updateImage(); + Base::onMouseLostFocus(_new); } void ImageButton::onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id) { if (_id == MyGUI::MouseButton::Left) - setImageTexture(mImagePushed); + { + mMousePress = true; + updateImage(); + } + Base::onMouseButtonPressed(_left, _top, _id); + } - ImageBox::onMouseButtonPressed(_left, _top, _id); + void ImageButton::updateImage() + { + if (mMousePress) + setImageTexture(mImagePushed); + else if (mMouseFocus || mKeyFocus) + setImageTexture(mImageHighlighted); + else + setImageTexture(mImageNormal); } MyGUI::IntSize ImageButton::getRequestedSize() @@ -70,8 +93,23 @@ namespace Gui void ImageButton::onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id) { if (_id == MyGUI::MouseButton::Left) - setImageTexture(mImageHighlighted); + { + mMousePress = false; + updateImage(); + } + + Base::onMouseButtonReleased(_left, _top, _id); + } - ImageBox::onMouseButtonReleased(_left, _top, _id); + void ImageButton::onKeySetFocus(MyGUI::Widget *_old) + { + mKeyFocus = true; + updateImage(); + } + + void ImageButton::onKeyLostFocus(MyGUI::Widget *_new) + { + mKeyFocus = false; + updateImage(); } } diff --git a/components/widgets/imagebutton.hpp b/components/widgets/imagebutton.hpp index a539f15c9..509b1c8c2 100644 --- a/components/widgets/imagebutton.hpp +++ b/components/widgets/imagebutton.hpp @@ -16,19 +16,30 @@ namespace Gui public: MyGUI::IntSize getRequestedSize(); + ImageButton(); + /// Set mImageNormal, mImageHighlighted and mImagePushed based on file convention (image_idle.ext, image_over.ext and image_pressed.ext) void setImage(const std::string& image); + private: + void updateImage(); + protected: virtual void setPropertyOverride(const std::string& _key, const std::string& _value); virtual void onMouseLostFocus(MyGUI::Widget* _new); virtual void onMouseSetFocus(MyGUI::Widget* _old); virtual void onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id); virtual void onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id); + virtual void onKeySetFocus(MyGUI::Widget* _old); + virtual void onKeyLostFocus(MyGUI::Widget* _new); std::string mImageHighlighted; std::string mImageNormal; std::string mImagePushed; + + bool mMouseFocus; + bool mMousePress; + bool mKeyFocus; }; } From c203a0774a5cabd46919c149b82c3c38895de90b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 16:58:05 +0200 Subject: [PATCH 138/505] Adjust some layouts to take better advantage of keyboard navigation --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 +-- apps/openmw/mwgui/confirmationdialog.cpp | 5 ++++ apps/openmw/mwgui/dialogue.cpp | 11 ++++----- apps/openmw/mwgui/dialogue.hpp | 1 + apps/openmw/mwgui/mainmenu.cpp | 24 +++++++++++++++---- files/mygui/openmw_confirmation_dialog.layout | 1 + .../openmw_interactive_messagebox.layout | 1 + files/mygui/openmw_savegame_dialog.layout | 1 + files/mygui/openmw_trade_window.layout | 7 +++--- 9 files changed, 39 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index fa5bfbe2f..6da1f7806 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -139,8 +139,6 @@ namespace MWDialogue // If the dialogue window was already open, keep the existing history bool resetHistory = (!MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Dialogue)); - win->startDialogue(actor, actor.getClass().getName (actor), resetHistory); - //greeting const MWWorld::Store &dialogs = MWBase::Environment::get().getWorld()->getStore().get(); @@ -156,6 +154,7 @@ namespace MWDialogue { //initialise the GUI MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); + win->startDialogue(actor, actor.getClass().getName (actor), resetHistory); creatureStats.talkedToPlayer(); diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 33f8dbe3e..f3a06f245 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -3,6 +3,9 @@ #include #include +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + namespace MWGui { ConfirmationDialog::ConfirmationDialog() : @@ -38,6 +41,8 @@ namespace MWGui mMessage->setSize(mMessage->getWidth(), mMessage->getTextSize().height + 24); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mOkButton); + center(); } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 2e80301d2..9f59cd443 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -259,9 +259,8 @@ namespace MWGui getWidget(mTopicsList, "TopicsList"); mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); - MyGUI::Button* byeButton; - getWidget(byeButton, "ByeButton"); - byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); + getWidget(mGoodbyeButton, "ByeButton"); + mGoodbyeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); getWidget(mDispositionBar, "Disposition"); getWidget(mDispositionText,"DispositionText"); @@ -360,6 +359,8 @@ namespace MWGui void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName, bool resetHistory) { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); + mGoodbye = false; mEnabled = true; bool sameActor = (mPtr == actor); @@ -528,10 +529,8 @@ namespace MWGui onScrollbarMoved(mScrollBar, 0); } - MyGUI::Button* byeButton; - getWidget(byeButton, "ByeButton"); bool goodbyeEnabled = !MWBase::Environment::get().getDialogueManager()->isInChoice() || mGoodbye; - byeButton->setEnabled(goodbyeEnabled); + mGoodbyeButton->setEnabled(goodbyeEnabled); bool topicsEnabled = !MWBase::Environment::get().getDialogueManager()->isInChoice() && !mGoodbye; mTopicsList->setEnabled(topicsEnabled); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 5b5ae5b68..9f0b2245a 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -169,6 +169,7 @@ namespace MWGui MyGUI::ScrollBar* mScrollBar; MyGUI::ProgressBar* mDispositionBar; MyGUI::TextBox* mDispositionText; + MyGUI::Button* mGoodbyeButton; PersuasionDialog mPersuasionDialog; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 5a435b9cf..265b08fd6 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -56,9 +56,24 @@ namespace MWGui if (visible) updateMenu(); - showBackground( - MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) && - MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); + bool isMainMenu = + MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) && + MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame; + + showBackground(isMainMenu); + + if (visible) + { + if (isMainMenu) + { + if (mButtons["loadgame"]->getVisible()) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["loadgame"]); + else + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["newgame"]); + } + else + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["return"]); + } Layout::setVisible (visible); } @@ -231,7 +246,8 @@ namespace MWGui buttons.push_back("exitgame"); // Create new buttons if needed - for (std::vector::iterator it = buttons.begin(); it != buttons.end(); ++it) + std::vector allButtons { "return", "newgame", "savegame", "loadgame", "options", "credits", "exitgame"}; + for (std::vector::iterator it = allButtons.begin(); it != allButtons.end(); ++it) { if (mButtons.find(*it) == mButtons.end()) { diff --git a/files/mygui/openmw_confirmation_dialog.layout b/files/mygui/openmw_confirmation_dialog.layout index 39e77cb93..c5eb573a7 100644 --- a/files/mygui/openmw_confirmation_dialog.layout +++ b/files/mygui/openmw_confirmation_dialog.layout @@ -10,6 +10,7 @@ + diff --git a/files/mygui/openmw_interactive_messagebox.layout b/files/mygui/openmw_interactive_messagebox.layout index 50bc178ed..410426656 100644 --- a/files/mygui/openmw_interactive_messagebox.layout +++ b/files/mygui/openmw_interactive_messagebox.layout @@ -9,6 +9,7 @@ + diff --git a/files/mygui/openmw_savegame_dialog.layout b/files/mygui/openmw_savegame_dialog.layout index f18218430..a7b7703de 100644 --- a/files/mygui/openmw_savegame_dialog.layout +++ b/files/mygui/openmw_savegame_dialog.layout @@ -46,6 +46,7 @@ + diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index 6d5dfb89b..f9f24581f 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -48,6 +48,10 @@ + + + + @@ -60,9 +64,6 @@ - - - From 5482ad0482cc242069a80df6a3adb21bd38b8600 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 17:03:31 +0200 Subject: [PATCH 139/505] Fix tab completion in console to not cycle key focus --- apps/openmw/mwgui/keyboardnavigation.cpp | 3 +++ files/mygui/openmw_console.layout | 1 + 2 files changed, 4 insertions(+) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index 840a12f1e..ba09ce369 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -82,6 +82,9 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) if (!isButtonFocus() && direction != D_Prev && direction != D_Next) return false; + if ((direction == D_Prev || direction == D_Next) && focus->getUserString("AcceptTab") == "true") + return false; + MyGUI::Widget* window = MyGUI::InputManager::getInstance().getKeyFocusWidget(); while (window->getParent()) window = window->getParent(); diff --git a/files/mygui/openmw_console.layout b/files/mygui/openmw_console.layout index 854568f9b..103cdcf14 100644 --- a/files/mygui/openmw_console.layout +++ b/files/mygui/openmw_console.layout @@ -18,6 +18,7 @@ + From 01391b7eed79925623348a29cdd1ee4abe35edb8 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 17:10:53 +0200 Subject: [PATCH 140/505] Rename WindowBase's open/close to onOpen/onClose --- apps/openmw/mwgui/alchemywindow.cpp | 2 +- apps/openmw/mwgui/alchemywindow.hpp | 2 +- apps/openmw/mwgui/birth.cpp | 4 ++-- apps/openmw/mwgui/birth.hpp | 2 +- apps/openmw/mwgui/class.cpp | 8 ++++---- apps/openmw/mwgui/class.hpp | 4 ++-- apps/openmw/mwgui/console.cpp | 4 ++-- apps/openmw/mwgui/console.hpp | 4 ++-- apps/openmw/mwgui/container.cpp | 4 ++-- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 4 ++-- apps/openmw/mwgui/dialogue.hpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 2 +- apps/openmw/mwgui/enchantingdialog.hpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/journalwindow.cpp | 4 ++-- apps/openmw/mwgui/levelupdialog.cpp | 2 +- apps/openmw/mwgui/levelupdialog.hpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 6 +++--- apps/openmw/mwgui/mapwindow.hpp | 4 ++-- apps/openmw/mwgui/merchantrepair.cpp | 2 +- apps/openmw/mwgui/merchantrepair.hpp | 2 +- apps/openmw/mwgui/messagebox.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 4 ++-- apps/openmw/mwgui/quickkeysmenu.hpp | 2 +- apps/openmw/mwgui/race.cpp | 6 +++--- apps/openmw/mwgui/race.hpp | 4 ++-- apps/openmw/mwgui/recharge.cpp | 2 +- apps/openmw/mwgui/recharge.hpp | 2 +- apps/openmw/mwgui/repair.cpp | 2 +- apps/openmw/mwgui/repair.hpp | 2 +- apps/openmw/mwgui/review.cpp | 4 ++-- apps/openmw/mwgui/review.hpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 4 ++-- apps/openmw/mwgui/savegamedialog.hpp | 2 +- apps/openmw/mwgui/settingswindow.cpp | 2 +- apps/openmw/mwgui/settingswindow.hpp | 2 +- apps/openmw/mwgui/spellcreationdialog.cpp | 6 +++--- apps/openmw/mwgui/spellcreationdialog.hpp | 4 ++-- apps/openmw/mwgui/spellwindow.cpp | 2 +- apps/openmw/mwgui/spellwindow.hpp | 2 +- apps/openmw/mwgui/statswindow.hpp | 2 +- apps/openmw/mwgui/textinput.cpp | 4 ++-- apps/openmw/mwgui/textinput.hpp | 2 +- apps/openmw/mwgui/trainingwindow.cpp | 2 +- apps/openmw/mwgui/trainingwindow.hpp | 2 +- apps/openmw/mwgui/waitdialog.cpp | 4 ++-- apps/openmw/mwgui/waitdialog.hpp | 4 ++-- apps/openmw/mwgui/windowbase.cpp | 8 ++++---- apps/openmw/mwgui/windowbase.hpp | 8 ++++---- 51 files changed, 82 insertions(+), 82 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 7379f3613..c68bad02a 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -101,7 +101,7 @@ namespace MWGui update(); } - void AlchemyWindow::open() + void AlchemyWindow::onOpen() { mAlchemy->setAlchemist (MWMechanics::getPlayer()); diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index e1f48d4a3..8b7bcaaca 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -24,7 +24,7 @@ namespace MWGui public: AlchemyWindow(); - virtual void open(); + virtual void onOpen(); virtual void exit(); private: diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index ecc011fc1..b4a6b7d2f 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -64,9 +64,9 @@ namespace MWGui okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } - void BirthDialog::open() + void BirthDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); updateBirths(); updateSpells(); } diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index c8ec9da09..c13d49838 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -20,7 +20,7 @@ namespace MWGui void setBirthId(const std::string &raceId); void setNextButtonShow(bool shown); - virtual void open(); + virtual void onOpen(); // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index e1f5a165e..2278b5141 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -125,9 +125,9 @@ namespace MWGui okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } - void PickClassDialog::open() + void PickClassDialog::onOpen() { - WindowModal::open (); + WindowModal::onOpen (); updateClasses(); updateStats(); } @@ -341,9 +341,9 @@ namespace MWGui } } - void InfoBoxDialog::open() + void InfoBoxDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); // Fix layout layoutVertically(mTextBox, 4); layoutVertically(mButtonBar, 6); diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 8206d6b03..2b205d12f 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -21,7 +21,7 @@ namespace MWGui std::string getText() const; void setButtons(ButtonList &buttons); - virtual void open(); + virtual void onOpen(); // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Int; @@ -100,7 +100,7 @@ namespace MWGui void setClassId(const std::string &classId); void setNextButtonShow(bool shown); - virtual void open(); + virtual void onOpen(); // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index aeff7dc39..62690a0f1 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -145,14 +145,14 @@ namespace MWGui mCompilerContext.setExtensions (&mExtensions); } - void Console::open() + void Console::onOpen() { // Give keyboard focus to the combo box whenever the console is // turned on MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine); } - void Console::close() + void Console::onClose() { // Apparently, hidden widgets can retain key focus // Remove for MyGUI 3.2.2 diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 98e46a559..1232036ca 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -39,8 +39,8 @@ namespace MWGui Console(int w, int h, bool consoleOnlyScripts); - virtual void open(); - virtual void close(); + virtual void onOpen(); + virtual void onClose(); virtual void exit(); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index c9be21322..4f9201f06 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -172,9 +172,9 @@ namespace MWGui mSortModel = NULL; } - void ContainerWindow::close() + void ContainerWindow::onClose() { - WindowBase::close(); + WindowBase::onClose(); if (dynamic_cast(mModel) // Make sure we were actually closed, rather than just temporarily hidden (e.g. console or main menu opened) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 520bce9d9..65cfa35c7 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -34,7 +34,7 @@ namespace MWGui ContainerWindow(DragAndDrop* dragAndDrop); void openContainer(const MWWorld::Ptr& container, bool loot=false); - virtual void close(); + virtual void onClose(); virtual void resetReference(); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 9f59cd443..d9954a792 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -73,9 +73,9 @@ namespace MWGui setVisible(false); } - void PersuasionDialog::open() + void PersuasionDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); center(); MWWorld::Ptr player = MWMechanics::getPlayer(); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 9f0b2245a..682baef3c 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -28,7 +28,7 @@ namespace MWGui public: PersuasionDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); private: diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index c7d2ef7de..25568da07 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -60,7 +60,7 @@ namespace MWGui delete mItemSelectionDialog; } - void EnchantingDialog::open() + void EnchantingDialog::onOpen() { center(); } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index cb7c6c0d0..7c49ae54a 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -19,7 +19,7 @@ namespace MWGui EnchantingDialog(); virtual ~EnchantingDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 6eb0c554e..dcfb075db 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -363,7 +363,7 @@ namespace MWGui dirtyPreview(); } - void InventoryWindow::open() + void InventoryWindow::onOpen() { if (!mPtr.isEmpty()) { diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 761464540..fb5be3493 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -35,7 +35,7 @@ namespace MWGui public: InventoryWindow(DragAndDrop* dragAndDrop, osg::Group* parent, Resource::ResourceSystem* resourceSystem); - virtual void open(); + virtual void onOpen(); /// start trading, disables item drag&drop void setTrading(bool trading); diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index e96cc8b70..73b196cf8 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -211,7 +211,7 @@ namespace button->setPosition(button->getPosition() + MyGUI::IntPoint(diff.width,0)); } - void open() + void onOpen() { if (!MWBase::Environment::get().getWindowManager ()->getJournalAllowed ()) { @@ -240,7 +240,7 @@ namespace updateShowingPages(); } - void close() + void onClose() { mModel->unload (); diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index da8e93279..a068d71f3 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -128,7 +128,7 @@ namespace MWGui setAttributeValues(); } - void LevelupDialog::open() + void LevelupDialog::onOpen() { MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); diff --git a/apps/openmw/mwgui/levelupdialog.hpp b/apps/openmw/mwgui/levelupdialog.hpp index d49f7536d..36810665e 100644 --- a/apps/openmw/mwgui/levelupdialog.hpp +++ b/apps/openmw/mwgui/levelupdialog.hpp @@ -11,7 +11,7 @@ namespace MWGui public: LevelupDialog(); - virtual void open(); + virtual void onOpen(); private: MyGUI::Button* mOkButton; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index ed9dabd2d..7bc66fab4 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -943,7 +943,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Map); } - void MapWindow::open() + void MapWindow::onOpen() { ensureGlobalMapLoaded(); @@ -1107,9 +1107,9 @@ namespace MWGui return MyGUI::TextIterator::getOnlyText(mTextEdit->getCaption()); } - void EditNoteDialog::open() + void EditNoteDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); center(); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 312447a24..eae1cec7e 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -169,7 +169,7 @@ namespace MWGui public: EditNoteDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); void showDeleteButton(bool show); @@ -218,7 +218,7 @@ namespace MWGui void ensureGlobalMapLoaded(); - virtual void open(); + virtual void onOpen(); void onFrame(float dt); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 9e27c0154..9c706851f 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -111,7 +111,7 @@ void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel) mList->setViewOffset(MyGUI::IntPoint(0, static_cast(mList->getViewOffset().top + _rel*0.3f))); } -void MerchantRepair::open() +void MerchantRepair::onOpen() { center(); // Reset scrollbars diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 8dcdfee12..5006b08a4 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -12,7 +12,7 @@ class MerchantRepair : public WindowBase public: MerchantRepair(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index f9c445d36..6b5ba506b 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -200,7 +200,7 @@ namespace MWGui , mMessageBoxManager(parMessageBoxManager) , mButtonPressed(-1) { - WindowModal::open(); + WindowModal::onOpen(); int textPadding = 10; // padding between text-widget and main-widget int textButtonPadding = 10; // padding between the text-widget und the button-widget diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index e912193bf..19dd6fa03 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -590,9 +590,9 @@ namespace MWGui mParent->onAssignMagicCancel(); } - void MagicSelectionDialog::open () + void MagicSelectionDialog::onOpen () { - WindowModal::open(); + WindowModal::onOpen(); mMagicList->setModel(new SpellModel(MWMechanics::getPlayer())); mMagicList->resetScrollbars(); diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 64db9043e..d07cdef3d 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -94,7 +94,7 @@ namespace MWGui public: MagicSelectionDialog(QuickKeysMenu* parent); - virtual void open(); + virtual void onOpen(); virtual void exit(); private: diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 047f65263..374a5d3d8 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -120,9 +120,9 @@ namespace MWGui okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } - void RaceDialog::open() + void RaceDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); updateRaces(); updateSkills(); @@ -183,7 +183,7 @@ namespace MWGui updateSpellPowers(); } - void RaceDialog::close() + void RaceDialog::onClose() { mPreviewImage->setRenderItemTexture(NULL); diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index b762745cd..911bce577 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -51,8 +51,8 @@ namespace MWGui void setGender(Gender gender) { mGenderIndex = gender == GM_Male ? 0 : 1; } void setNextButtonShow(bool shown); - virtual void open(); - virtual void close(); + virtual void onOpen(); + virtual void onClose(); // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 390a1f83c..00af45695 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -50,7 +50,7 @@ Recharge::Recharge() setVisible(false); } -void Recharge::open() +void Recharge::onOpen() { center(); diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp index cc3db14df..d963e9d66 100644 --- a/apps/openmw/mwgui/recharge.hpp +++ b/apps/openmw/mwgui/recharge.hpp @@ -22,7 +22,7 @@ class Recharge : public WindowBase public: Recharge(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 4d6441450..f917cef0f 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -46,7 +46,7 @@ Repair::Repair() mToolIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onSelectItem); } -void Repair::open() +void Repair::onOpen() { center(); diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index c50ba861a..44c380b51 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -19,7 +19,7 @@ class Repair : public WindowBase public: Repair(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index bf18e7355..61a7a2ac0 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -101,9 +101,9 @@ namespace MWGui okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked); } - void ReviewDialog::open() + void ReviewDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); mUpdateSkillArea = true; } diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index f21f2fa9d..34dd5a7d4 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -45,7 +45,7 @@ namespace MWGui void configureSkills(const SkillList& major, const SkillList& minor); void setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value); - virtual void open(); + virtual void onOpen(); void onFrame(float duration); diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 84d4ca959..7a4c3a22e 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -118,9 +118,9 @@ namespace MWGui accept(); } - void SaveGameDialog::open() + void SaveGameDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); mSaveNameEdit->setCaption (""); if (mSaving) diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index be0e47cab..2a49cf48a 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -17,7 +17,7 @@ namespace MWGui public: SaveGameDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index f46199c80..4e8547d33 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -553,7 +553,7 @@ namespace MWGui updateControlsBox (); } - void SettingsWindow::open() + void SettingsWindow::onOpen() { updateControlsBox (); resetScrollbars(); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 2ac06dcaa..447331574 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -15,7 +15,7 @@ namespace MWGui public: SettingsWindow(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 354253fa4..6a36554d8 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -96,9 +96,9 @@ namespace MWGui mConstantEffect = constant; } - void EditEffectDialog::open() + void EditEffectDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); center(); } @@ -415,7 +415,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_SpellCreation); } - void SpellCreationDialog::open() + void SpellCreationDialog::onOpen() { center(); } diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 6cdf74d10..d12115c88 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -23,7 +23,7 @@ namespace MWGui public: EditEffectDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); void setConstantEffect(bool constant); @@ -150,7 +150,7 @@ namespace MWGui public: SpellCreationDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); void startSpellMaking(MWWorld::Ptr actor); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 5ce3fd1fe..9261912b4 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -62,7 +62,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Magic); } - void SpellWindow::open() + void SpellWindow::onOpen() { updateSpells(); } diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index dcce10f9d..f8fead9ea 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -37,7 +37,7 @@ namespace MWGui virtual void onPinToggled(); virtual void onTitleDoubleClicked(); - virtual void open(); + virtual void onOpen(); SpellView* mSpellView; SpellIcons* mSpellIcons; diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp index 1fe3cb68d..487953e00 100644 --- a/apps/openmw/mwgui/statswindow.hpp +++ b/apps/openmw/mwgui/statswindow.hpp @@ -37,7 +37,7 @@ namespace MWGui void setBounty (int bounty) { if (bounty != mBounty) mChanged = true; this->mBounty = bounty; } void updateSkillArea(); - virtual void open() { onWindowResize(mMainWidget->castType()); } + virtual void onOpen() { onWindowResize(mMainWidget->castType()); } private: void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 958b52dc0..169c9e742 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -42,9 +42,9 @@ namespace MWGui setText("LabelT", label); } - void TextInputDialog::open() + void TextInputDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); // Make sure the edit box has focus MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); } diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp index 57dd34dd6..ccfa19c87 100644 --- a/apps/openmw/mwgui/textinput.hpp +++ b/apps/openmw/mwgui/textinput.hpp @@ -20,7 +20,7 @@ namespace MWGui void setNextButtonShow(bool shown); void setTextLabel(const std::string &label); - virtual void open(); + virtual void onOpen(); /** Event : Dialog finished, OK button clicked.\n signature : void method()\n diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 82218fef1..d2e771918 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -55,7 +55,7 @@ namespace MWGui mProgressBar.setVisible(false); } - void TrainingWindow::open() + void TrainingWindow::onOpen() { center(); } diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index 7c4582062..95a35be7f 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -14,7 +14,7 @@ namespace MWGui public: TrainingWindow(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index ba58a9c69..476d19bd6 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -35,7 +35,7 @@ namespace MWGui getWidget(mProgressText, "ProgressText"); } - void WaitDialogProgressBar::open() + void WaitDialogProgressBar::onOpen() { center(); } @@ -85,7 +85,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->popGuiMode(); } - void WaitDialog::open() + void WaitDialog::onOpen() { if (!MWBase::Environment::get().getWindowManager ()->getRestEnabled ()) { diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 13df1f8ae..829659d16 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -13,7 +13,7 @@ namespace MWGui public: WaitDialogProgressBar(); - virtual void open(); + virtual void onOpen(); void setProgress(int cur, int total); @@ -27,7 +27,7 @@ namespace MWGui public: WaitDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 99b74529e..1ba4c7ed6 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -23,9 +23,9 @@ void WindowBase::setVisible(bool visible) mMainWidget->setVisible(visible); if (visible) - open(); + onOpen(); else if (wasVisible && !visible) - close(); + onClose(); // This is needed as invisible widgets can retain key focus. // Remove for MyGUI 3.2.2 @@ -64,13 +64,13 @@ WindowModal::WindowModal(const std::string& parLayout) { } -void WindowModal::open() +void WindowModal::onOpen() { MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); MWBase::Environment::get().getWindowManager()->addCurrentModal(this); //Set so we can escape it if needed } -void WindowModal::close() +void WindowModal::onClose() { MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); MWBase::Environment::get().getWindowManager()->removeCurrentModal(this); diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 43fb8901e..400dc0ce4 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -22,9 +22,9 @@ namespace MWGui typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; /// Notify that window has been made visible - virtual void open() {} + virtual void onOpen() {} /// Notify that window has been hidden - virtual void close () {} + virtual void onClose () {} /// Gracefully exits the window virtual void exit() {} /// Sets the visibility of the window @@ -42,8 +42,8 @@ namespace MWGui { public: WindowModal(const std::string& parLayout); - virtual void open(); - virtual void close(); + virtual void onOpen(); + virtual void onClose(); virtual void exit() {} }; From 622e3ebd60f2de42e7a6e15a947c7bab1a6db606 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 20:43:53 +0200 Subject: [PATCH 141/505] Remove excessive padding in some GUI layouts --- ...openmw_chargen_generate_class_result.layout | 2 +- files/mygui/openmw_recharge_dialog.layout | 2 +- files/mygui/openmw_repair.layout | 2 +- files/mygui/openmw_savegame_dialog.layout | 2 +- files/mygui/openmw_tooltips.layout | 18 +++++++++--------- files/mygui/openmw_wait_dialog.layout | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/files/mygui/openmw_chargen_generate_class_result.layout b/files/mygui/openmw_chargen_generate_class_result.layout index 83595fafd..d49f57dde 100644 --- a/files/mygui/openmw_chargen_generate_class_result.layout +++ b/files/mygui/openmw_chargen_generate_class_result.layout @@ -3,7 +3,7 @@ - + diff --git a/files/mygui/openmw_recharge_dialog.layout b/files/mygui/openmw_recharge_dialog.layout index d620aadab..200d345e3 100644 --- a/files/mygui/openmw_recharge_dialog.layout +++ b/files/mygui/openmw_recharge_dialog.layout @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_repair.layout b/files/mygui/openmw_repair.layout index 340711bb1..abc429594 100644 --- a/files/mygui/openmw_repair.layout +++ b/files/mygui/openmw_repair.layout @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_savegame_dialog.layout b/files/mygui/openmw_savegame_dialog.layout index a7b7703de..236eaaa61 100644 --- a/files/mygui/openmw_savegame_dialog.layout +++ b/files/mygui/openmw_savegame_dialog.layout @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_tooltips.layout b/files/mygui/openmw_tooltips.layout index a7eeabfa5..c038066f1 100644 --- a/files/mygui/openmw_tooltips.layout +++ b/files/mygui/openmw_tooltips.layout @@ -32,7 +32,7 @@ - + @@ -44,7 +44,7 @@ - + @@ -61,7 +61,7 @@ - + @@ -77,7 +77,7 @@ - + @@ -137,7 +137,7 @@ - + @@ -159,7 +159,7 @@ - + @@ -211,7 +211,7 @@ - + @@ -245,7 +245,7 @@ - + @@ -277,7 +277,7 @@ - + diff --git a/files/mygui/openmw_wait_dialog.layout b/files/mygui/openmw_wait_dialog.layout index 112fa6001..4bc60ceb4 100644 --- a/files/mygui/openmw_wait_dialog.layout +++ b/files/mygui/openmw_wait_dialog.layout @@ -2,7 +2,7 @@ - + From 3820416277802709b03d29749535443b1c3913d7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 20:46:08 +0200 Subject: [PATCH 142/505] Refactor the unholy mess that is WindowManager::updateVisible GUI modes are now defined in a general and extensible way. The next commits are going to take advantage of this. --- apps/openmw/mwgui/journalwindow.cpp | 10 +- apps/openmw/mwgui/journalwindow.hpp | 6 +- apps/openmw/mwgui/mainmenu.cpp | 2 +- apps/openmw/mwgui/mainmenu.hpp | 4 +- apps/openmw/mwgui/messagebox.cpp | 3 +- apps/openmw/mwgui/windowbase.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 314 +++++++++++-------------- apps/openmw/mwgui/windowmanagerimp.hpp | 19 ++ 8 files changed, 177 insertions(+), 182 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 73b196cf8..a0e424021 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -44,7 +44,7 @@ namespace static char const LeftTopicIndex [] = "LeftTopicIndex"; static char const RightTopicIndex [] = "RightTopicIndex"; - struct JournalWindowImpl : MWGui::WindowBase, MWGui::JournalBooks, MWGui::JournalWindow + struct JournalWindowImpl : MWGui::JournalBooks, MWGui::JournalWindow { struct DisplayState { @@ -94,7 +94,7 @@ namespace } JournalWindowImpl (MWGui::JournalViewModel::Ptr Model, bool questList) - : WindowBase("openmw_journal.layout"), JournalBooks (Model) + : JournalBooks (Model), JournalWindow() { mMainWidget->setVisible(false); center(); @@ -603,3 +603,9 @@ MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model { return new JournalWindowImpl (Model, questList); } + +MWGui::JournalWindow::JournalWindow() + :WindowBase("openmw_journal.layout") +{ + +} diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index cc645ca44..c9bf0ef0a 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -1,6 +1,8 @@ #ifndef MWGUI_JOURNAL_H #define MWGUI_JOURNAL_H +#include "windowbase.hpp" + #include namespace MWBase { class WindowManager; } @@ -9,8 +11,10 @@ namespace MWGui { struct JournalViewModel; - struct JournalWindow + struct JournalWindow : public WindowBase { + JournalWindow(); + /// construct a new instance of the one JournalWindow implementation static JournalWindow * create (std::shared_ptr Model, bool questList); diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 265b08fd6..657f0e4ec 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -22,7 +22,7 @@ namespace MWGui { MainMenu::MainMenu(int w, int h, const VFS::Manager* vfs, const std::string& versionDescription) - : Layout("openmw_mainmenu.layout") + : WindowBase("openmw_mainmenu.layout") , mWidth (w), mHeight (h) , mVFS(vfs), mButtonBox(0) , mBackground(NULL) diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index fe256dc8e..612f7d1bd 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_GAME_MWGUI_MAINMENU_H #define OPENMW_GAME_MWGUI_MAINMENU_H -#include "layout.hpp" +#include "windowbase.hpp" namespace Gui { @@ -20,7 +20,7 @@ namespace MWGui class SaveGameDialog; class VideoWidget; - class MainMenu : public Layout + class MainMenu : public WindowBase { int mWidth; int mHeight; diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 6b5ba506b..dd0495051 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -77,6 +77,7 @@ namespace MWGui if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { mLastButtonPressed = mInterMessageBoxe->readPressedButton(); + mInterMessageBoxe->setVisible(false); delete mInterMessageBoxe; mInterMessageBoxe = NULL; MWBase::Environment::get().getInputManager()->changeInputMode( @@ -200,7 +201,7 @@ namespace MWGui , mMessageBoxManager(parMessageBoxManager) , mButtonPressed(-1) { - WindowModal::onOpen(); + setVisible(true); int textPadding = 10; // padding between text-widget and main-widget int textButtonPadding = 10; // padding between the text-widget und the button-widget diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 1ba4c7ed6..5ed564737 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -15,6 +15,7 @@ using namespace MWGui; WindowBase::WindowBase(const std::string& parLayout) : Layout(parLayout) { + mMainWidget->setVisible(false); } void WindowBase::setVisible(bool visible) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5d7a54735..81edc4a00 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -320,51 +320,103 @@ namespace MWGui mDragAndDrop = new DragAndDrop(); mRecharge = new Recharge(); + mGuiModeStates[GM_Recharge] = GuiModeState(mRecharge); + mMenu = new MainMenu(w, h, mResourceSystem->getVFS(), mVersionDescription); + mGuiModeStates[GM_MainMenu] = GuiModeState(mMenu); + mLocalMapRender = new MWRender::LocalMap(mViewer->getSceneData()->asGroup()); mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender, mWorkQueue); mMap->renderGlobalMap(); trackWindow(mMap, "map"); mStatsWindow = new StatsWindow(mDragAndDrop); trackWindow(mStatsWindow, "stats"); + mInventoryWindow = new InventoryWindow(mDragAndDrop, mViewer->getSceneData()->asGroup(), mResourceSystem); + mSpellWindow = new SpellWindow(mDragAndDrop); + trackWindow(mSpellWindow, "spells"); + + mGuiModeStates[GM_Inventory] = GuiModeState({mMap, mInventoryWindow, mSpellWindow, mStatsWindow}); + mGuiModeStates[GM_None] = GuiModeState({mMap, mInventoryWindow, mSpellWindow, mStatsWindow}); + + mTradeWindow = new TradeWindow(); + trackWindow(mTradeWindow, "barter"); + + mGuiModeStates[GM_Barter] = GuiModeState({mInventoryWindow, mTradeWindow}); + mConsole = new Console(w,h, mConsoleOnlyScripts); trackWindow(mConsole, "console"); + mGuiModeStates[GM_Console] = GuiModeState(mConsole); bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds"); mJournal = JournalWindow::create(JournalViewModel::create (), questList); + mGuiModeStates[GM_Journal] = GuiModeState(mJournal); + mMessageBoxManager = new MessageBoxManager(mStore->get().find("fMessageTimePerChar")->getFloat()); - mInventoryWindow = new InventoryWindow(mDragAndDrop, mViewer->getSceneData()->asGroup(), mResourceSystem); - mTradeWindow = new TradeWindow(); - trackWindow(mTradeWindow, "barter"); mSpellBuyingWindow = new SpellBuyingWindow(); + mGuiModeStates[GM_SpellBuying] = GuiModeState(mSpellBuyingWindow); + mTravelWindow = new TravelWindow(); + mGuiModeStates[GM_Travel] = GuiModeState(mTravelWindow); + mDialogueWindow = new DialogueWindow(); trackWindow(mDialogueWindow, "dialogue"); + mGuiModeStates[GM_Dialogue] = GuiModeState(mDialogueWindow); + mContainerWindow = new ContainerWindow(mDragAndDrop); trackWindow(mContainerWindow, "container"); + mGuiModeStates[GM_Container] = GuiModeState({mContainerWindow, mInventoryWindow}); + mHud = new HUD(mCustomMarkers, mDragAndDrop, mLocalMapRender); mToolTips = new ToolTips(); mScrollWindow = new ScrollWindow(); + mGuiModeStates[GM_Scroll] = GuiModeState(mScrollWindow); + mBookWindow = new BookWindow(); + mGuiModeStates[GM_Book] = GuiModeState(mBookWindow); + mCountDialog = new CountDialog(); mSettingsWindow = new SettingsWindow(); + mGuiModeStates[GM_Settings] = GuiModeState(mSettingsWindow); + mConfirmationDialog = new ConfirmationDialog(); + mAlchemyWindow = new AlchemyWindow(); trackWindow(mAlchemyWindow, "alchemy"); - mSpellWindow = new SpellWindow(mDragAndDrop); - trackWindow(mSpellWindow, "spells"); + mGuiModeStates[GM_Alchemy] = GuiModeState(mAlchemyWindow); + mQuickKeysMenu = new QuickKeysMenu(); + mGuiModeStates[GM_QuickKeysMenu] = GuiModeState(mQuickKeysMenu); + mLevelupDialog = new LevelupDialog(); + mGuiModeStates[GM_Levelup] = GuiModeState(mLevelupDialog); + mWaitDialog = new WaitDialog(); + mGuiModeStates[GM_Rest] = GuiModeState(mWaitDialog); + mGuiModeStates[GM_RestBed] = GuiModeState(mWaitDialog); + mSpellCreationDialog = new SpellCreationDialog(); + mGuiModeStates[GM_SpellCreation] = GuiModeState(mSpellCreationDialog); + mEnchantingDialog = new EnchantingDialog(); + mGuiModeStates[GM_Enchanting] = GuiModeState(mEnchantingDialog); + mTrainingWindow = new TrainingWindow(); + mGuiModeStates[GM_Training] = GuiModeState(mTrainingWindow); + mMerchantRepair = new MerchantRepair(); + mGuiModeStates[GM_MerchantRepair] = GuiModeState(mMerchantRepair); + mRepair = new Repair(); + mGuiModeStates[GM_Repair] = GuiModeState(mRepair); + mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); + mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); trackWindow(mCompanionWindow, "companion"); + mGuiModeStates[GM_Companion] = GuiModeState({mInventoryWindow, mCompanionWindow}); + mJailScreen = new JailScreen(); + mGuiModeStates[GM_Jail] = GuiModeState(mJailScreen); std::string werewolfFaderTex = "textures\\werewolfoverlay.dds"; if (mResourceSystem->getVFS()->exists(werewolfFaderTex)) @@ -531,196 +583,77 @@ namespace MWGui { if (!mMap) return; // UI not created yet - // Start out by hiding everything except the HUD - mMap->setVisible(false); - mMenu->setVisible(false); - mStatsWindow->setVisible(false); - mConsole->setVisible(false); - mJournal->setVisible(false); - mDialogueWindow->setVisible(false); - mContainerWindow->setVisible(false); - mInventoryWindow->setVisible(false); - mScrollWindow->setVisible(false); - mBookWindow->setVisible(false); - mTradeWindow->setVisible(false); - mSpellBuyingWindow->setVisible(false); - mTravelWindow->setVisible(false); - mSettingsWindow->setVisible(false); - mAlchemyWindow->setVisible(false); - mSpellWindow->setVisible(false); - mQuickKeysMenu->setVisible(false); - mLevelupDialog->setVisible(false); - mWaitDialog->setVisible(false); - mSpellCreationDialog->setVisible(false); - mEnchantingDialog->setVisible(false); - mTrainingWindow->setVisible(false); - mMerchantRepair->setVisible(false); - mRepair->setVisible(false); - mCompanionWindow->setVisible(false); - mInventoryWindow->setTrading(false); - mRecharge->setVisible(false); - mVideoBackground->setVisible(false); - mJailScreen->setVisible(false); - mHud->setVisible(mHudEnabled && mGuiEnabled); - mToolTips->setVisible(mGuiEnabled); + bool loading = (getMode() == GM_Loading || getMode() == GM_LoadingWallpaper); + + mHud->setVisible(mHudEnabled && mGuiEnabled && !loading); + mToolTips->setVisible(mGuiEnabled && !loading); bool gameMode = !isGuiMode(); mInputBlocker->setVisible (gameMode); - setCursorVisible(!gameMode); + + if (loading) + setCursorVisible(mMessageBoxManager && mMessageBoxManager->isInteractiveMessageBox()); + else + setCursorVisible(!gameMode); if (gameMode) setKeyFocusWidget (NULL); - if (!mGuiEnabled) - { - if (containsMode(GM_Console)) - mConsole->setVisible(true); - return; - } - // Icons of forced hidden windows are displayed setMinimapVisibility((mAllowed & GW_Map) && (!mMap->pinned() || (mForceHidden & GW_Map))); setWeaponVisibility((mAllowed & GW_Inventory) && (!mInventoryWindow->pinned() || (mForceHidden & GW_Inventory))); setSpellVisibility((mAllowed & GW_Magic) && (!mSpellWindow->pinned() || (mForceHidden & GW_Magic))); setHMSVisibility((mAllowed & GW_Stats) && (!mStatsWindow->pinned() || (mForceHidden & GW_Stats))); - // If in game mode (or interactive messagebox), show only the pinned windows + // If in game mode (or interactive messagebox), show the pinned windows if (mGuiModes.empty()) { - mInventoryWindow->setGuiMode(GM_None); mMap->setVisible(mMap->pinned() && !(mForceHidden & GW_Map) && (mAllowed & GW_Map)); mStatsWindow->setVisible(mStatsWindow->pinned() && !(mForceHidden & GW_Stats) && (mAllowed & GW_Stats)); mInventoryWindow->setVisible(mInventoryWindow->pinned() && !(mForceHidden & GW_Inventory) && (mAllowed & GW_Inventory)); mSpellWindow->setVisible(mSpellWindow->pinned() && !(mForceHidden & GW_Magic) && (mAllowed & GW_Magic)); - return; } - if(mGuiModes.size() != 0) + GuiMode mode = mGuiModes.back(); + + mInventoryWindow->setTrading(mode == GM_Barter); + mInventoryWindow->setGuiMode(mode); + + // For the inventory mode, compute the effective set of windows to show. + // This is controlled both by what windows the + // user has opened/closed (the 'shown' variable) and by what + // windows we are allowed to show (the 'allowed' var.) + int eff = mShown & mAllowed & ~mForceHidden; + mGuiModeStates[GM_Inventory].mVisibilityMask.resize(4); + mGuiModeStates[GM_Inventory].mVisibilityMask[0] = eff & GW_Map; + mGuiModeStates[GM_Inventory].mVisibilityMask[1] = eff & GW_Inventory; + mGuiModeStates[GM_Inventory].mVisibilityMask[2] = eff & GW_Magic; + mGuiModeStates[GM_Inventory].mVisibilityMask[3] = eff & GW_Stats; + if (getMode() == GM_Inventory) + mGuiModeStates[GM_Inventory].update(true); + + switch (mode) { - GuiMode mode = mGuiModes.back(); - - switch(mode) { - case GM_QuickKeysMenu: - mQuickKeysMenu->setVisible (true); - break; - case GM_MainMenu: - mMenu->setVisible(true); - break; - case GM_Settings: - mSettingsWindow->setVisible(true); - break; - case GM_Console: - mConsole->setVisible(true); - break; - case GM_Scroll: - mScrollWindow->setVisible(true); - break; - case GM_Book: - mBookWindow->setVisible(true); - break; - case GM_Alchemy: - mAlchemyWindow->setVisible(true); - break; - case GM_Rest: - mWaitDialog->setVisible(true); - break; - case GM_RestBed: - mWaitDialog->setVisible(true); - mWaitDialog->bedActivated(); - break; - case GM_Levelup: - mLevelupDialog->setVisible(true); - break; - case GM_Name: - case GM_Race: - case GM_Class: - case GM_ClassPick: - case GM_ClassCreate: - case GM_Birth: - case GM_ClassGenerate: - case GM_Review: - mCharGen->spawnDialog(mode); - break; - case GM_Inventory: - { - // First, compute the effective set of windows to show. - // This is controlled both by what windows the - // user has opened/closed (the 'shown' variable) and by what - // windows we are allowed to show (the 'allowed' var.) - int eff = mShown & mAllowed & ~mForceHidden; - - // Show the windows we want - mMap ->setVisible((eff & GW_Map) != 0); - mStatsWindow ->setVisible((eff & GW_Stats) != 0); - mInventoryWindow->setVisible((eff & GW_Inventory) != 0); - mInventoryWindow->setGuiMode(mode); - mSpellWindow ->setVisible((eff & GW_Magic) != 0); - break; - } - case GM_Container: - mContainerWindow->setVisible(true); - mInventoryWindow->setVisible(true); - mInventoryWindow->setGuiMode(mode); - break; - case GM_Companion: - mCompanionWindow->setVisible(true); - mInventoryWindow->setVisible(true); - mInventoryWindow->setGuiMode(mode); - break; - case GM_Dialogue: - mDialogueWindow->setVisible(true); - break; - case GM_Barter: - mInventoryWindow->setVisible(true); - mInventoryWindow->setTrading(true); - mInventoryWindow->setGuiMode(mode); - mTradeWindow->setVisible(true); - break; - case GM_SpellBuying: - mSpellBuyingWindow->setVisible(true); - break; - case GM_Travel: - mTravelWindow->setVisible(true); - break; - case GM_SpellCreation: - mSpellCreationDialog->setVisible(true); - break; - case GM_Recharge: - mRecharge->setVisible(true); - break; - case GM_Enchanting: - mEnchantingDialog->setVisible(true); - break; - case GM_Training: - mTrainingWindow->setVisible(true); - break; - case GM_MerchantRepair: - mMerchantRepair->setVisible(true); - break; - case GM_Repair: - mRepair->setVisible(true); - break; - 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, - // GM_Loading uses a texture of the last rendered frame so everything previously visible will be rendered. - mHud->setVisible(false); - mToolTips->setVisible(false); - setCursorVisible(mMessageBoxManager && mMessageBoxManager->isInteractiveMessageBox()); - break; - default: - // Unsupported mode, switch back to game - break; - } + // FIXME: refactor chargen windows to use modes properly (or not use them at all) + case GM_Name: + case GM_Race: + case GM_Class: + case GM_ClassPick: + case GM_ClassCreate: + case GM_Birth: + case GM_ClassGenerate: + case GM_Review: + mCharGen->spawnDialog(mode); + break; + case GM_RestBed: + // FIXME: use GM_Rest and push the 'bed' argument in some other way + mWaitDialog->bedActivated(); + break; + default: + break; } } @@ -1267,11 +1200,18 @@ namespace MWGui mSpellBuyingWindow->center(); } + void WindowManager::onCursorChange(const std::string &name) + { + mCursorManager->cursorChanged(name); + } + void WindowManager::pushGuiMode(GuiMode mode) { if (mode==GM_Inventory && mAllowed==GW_None) return; + if (!mGuiModes.empty() && mGuiModes.back() == mode) + return; // If this mode already exists somewhere in the stack, just bring it to the front. if (std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end()) @@ -1279,23 +1219,29 @@ namespace MWGui mGuiModes.erase(std::find(mGuiModes.begin(), mGuiModes.end(), mode)); } + if (!mGuiModes.empty()) + mGuiModeStates[mGuiModes.back()].update(false); + mGuiModes.push_back(mode); + mGuiModeStates[mode].update(true); + bool gameMode = !isGuiMode(); MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); updateVisible(); } - void WindowManager::onCursorChange(const std::string &name) - { - mCursorManager->cursorChanged(name); - } - void WindowManager::popGuiMode() { if (!mGuiModes.empty()) + { + mGuiModeStates[mGuiModes.back()].update(false); mGuiModes.pop_back(); + } + + if (!mGuiModes.empty()) + mGuiModeStates[mGuiModes.back()].update(true); bool gameMode = !isGuiMode(); MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); @@ -1305,6 +1251,12 @@ namespace MWGui void WindowManager::removeGuiMode(GuiMode mode) { + if (!mGuiModes.empty() && mGuiModes.back() == mode) + { + popGuiMode(); + return; + } + std::vector::iterator it = mGuiModes.begin(); while (it != mGuiModes.end()) { @@ -2214,4 +2166,16 @@ namespace MWGui else return true; } + + void WindowManager::GuiModeState::update(bool visible) + { + for (unsigned int i=0; isetVisible(visible && visibilityMask); + } + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3e17046df..524575c6a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -494,6 +494,25 @@ namespace MWGui std::map mPlayerSkillValues; MyGUI::Gui *mGui; // Gui + + struct GuiModeState + { + GuiModeState(WindowBase* window) + { + mWindows.push_back(window); + } + GuiModeState(const std::vector& windows) + : mWindows(windows) {} + GuiModeState() {} + + void update(bool visible); + + std::vector mWindows; + std::vector mVisibilityMask; // optional, may be used to temporarily exclude windows from this mode. + }; + // Defines the windows that should be shown in a particular GUI mode. + std::map mGuiModeStates; + // The currently active stack of GUI modes (top mode is the one we are in). std::vector mGuiModes; SDLUtil::SDLCursorManager* mCursorManager; From 84657271c7603aeead51ccee523f12b9608bb165 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 21:26:41 +0200 Subject: [PATCH 143/505] Improve WindowManager API with a generic way of passing a Ptr to the opened GUI window --- apps/openmw/mwbase/windowmanager.hpp | 18 +-- apps/openmw/mwclass/creature.cpp | 4 +- apps/openmw/mwclass/npc.cpp | 4 +- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 2 +- apps/openmw/mwgui/bookwindow.cpp | 6 +- apps/openmw/mwgui/bookwindow.hpp | 2 +- apps/openmw/mwgui/companionwindow.cpp | 2 +- apps/openmw/mwgui/companionwindow.hpp | 2 +- apps/openmw/mwgui/console.cpp | 6 +- apps/openmw/mwgui/console.hpp | 2 +- apps/openmw/mwgui/container.cpp | 4 +- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 16 +-- apps/openmw/mwgui/enchantingdialog.cpp | 63 ++++------ apps/openmw/mwgui/enchantingdialog.hpp | 5 +- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/merchantrepair.cpp | 4 +- apps/openmw/mwgui/merchantrepair.hpp | 2 +- apps/openmw/mwgui/recharge.cpp | 2 +- apps/openmw/mwgui/recharge.hpp | 2 +- apps/openmw/mwgui/repair.cpp | 2 +- apps/openmw/mwgui/repair.hpp | 2 +- apps/openmw/mwgui/scrollwindow.cpp | 6 +- apps/openmw/mwgui/scrollwindow.hpp | 2 +- apps/openmw/mwgui/soulgemdialog.cpp | 6 +- apps/openmw/mwgui/spellbuyingwindow.cpp | 9 +- apps/openmw/mwgui/spellbuyingwindow.hpp | 3 +- apps/openmw/mwgui/spellcreationdialog.cpp | 2 +- apps/openmw/mwgui/spellcreationdialog.hpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.hpp | 2 +- apps/openmw/mwgui/trainingwindow.cpp | 2 +- apps/openmw/mwgui/trainingwindow.hpp | 2 +- apps/openmw/mwgui/travelwindow.cpp | 2 +- apps/openmw/mwgui/travelwindow.hpp | 2 +- apps/openmw/mwgui/windowbase.hpp | 8 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 116 +++--------------- apps/openmw/mwgui/windowmanagerimp.hpp | 20 +-- apps/openmw/mwworld/actionopen.cpp | 5 +- apps/openmw/mwworld/actionopen.hpp | 5 +- apps/openmw/mwworld/actionread.cpp | 6 +- apps/openmw/mwworld/actionread.hpp | 2 +- apps/openmw/mwworld/actionrepair.cpp | 2 +- 43 files changed, 125 insertions(+), 235 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 37c3ce0d3..242f358a9 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -115,6 +115,7 @@ namespace MWBase virtual void setNewGame(bool newgame) = 0; + virtual void pushGuiMode (MWGui::GuiMode mode, const MWWorld::Ptr& arg) = 0; virtual void pushGuiMode (MWGui::GuiMode mode) = 0; virtual void popGuiMode() = 0; @@ -157,8 +158,6 @@ namespace MWBase virtual void updateSpellWindow() = 0; - virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; - /// Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0; virtual void setValue (int parSkill, const MWMechanics::SkillValue& value) = 0; @@ -284,21 +283,6 @@ namespace MWBase virtual bool getPlayerSleeping() = 0; virtual void wakeUpPlayer() = 0; - virtual void showCompanionWindow(MWWorld::Ptr actor) = 0; - virtual void startSpellMaking(MWWorld::Ptr actor) = 0; - virtual void startEnchanting(MWWorld::Ptr actor) = 0; - virtual void startRecharge(MWWorld::Ptr soulgem) = 0; - virtual void startSelfEnchanting(MWWorld::Ptr soulgem) = 0; - virtual void startTraining(MWWorld::Ptr actor) = 0; - virtual void startRepair(MWWorld::Ptr actor) = 0; - virtual void startRepairItem(MWWorld::Ptr item) = 0; - virtual void startTravel(const MWWorld::Ptr& actor) = 0; - virtual void startSpellBuying(const MWWorld::Ptr& actor) = 0; - virtual void startTrade(const MWWorld::Ptr& actor) = 0; - virtual void openContainer(const MWWorld::Ptr& container, bool loot) = 0; - virtual void showBook(const MWWorld::Ptr& item, bool showTakeButton) = 0; - virtual void showScroll(const MWWorld::Ptr& item, bool showTakeButton) = 0; - virtual void showSoulgemDialog (MWWorld::Ptr item) = 0; virtual void changePointer (const std::string& name) = 0; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 65f8c80d8..d6926f11d 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -457,11 +457,11 @@ namespace MWClass // by default user can loot friendly actors during death animation if (canLoot && !stats.getAiSequence().isInCombat()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // otherwise wait until death animation if(stats.isDeathAnimationFinished()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // death animation is not finished, do nothing return std::shared_ptr (new MWWorld::FailedAction("")); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index ca6c85aba..e7085bfbc 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -872,11 +872,11 @@ namespace MWClass // by default user can loot friendly actors during death animation if (canLoot && !stats.getAiSequence().isInCombat()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // otherwise wait until death animation if(stats.isDeathAnimationFinished()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // death animation is not finished, do nothing return std::shared_ptr (new MWWorld::FailedAction("")); diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 6da1f7806..fb4ba1016 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -186,7 +186,7 @@ namespace MWDialogue bool isCompanion = !mActor.getClass().getScript(mActor).empty() && mActor.getRefData().getLocals().getIntVar(mActor.getClass().getScript(mActor), "companion"); if (isCompanion) - MWBase::Environment::get().getWindowManager()->showCompanionWindow(mActor); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, mActor); } bool DialogueManager::compile (const std::string& cmd, std::vector& code, const MWWorld::Ptr& actor) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index b3296e7a7..ca697d0b6 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -11,6 +11,7 @@ #include "../mwmechanics/actorutil.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/class.hpp" #include "formatting.hpp" @@ -74,10 +75,13 @@ namespace MWGui mPages.clear(); } - void BookWindow::openBook (MWWorld::Ptr book, bool showTakeButton) + void BookWindow::setPtr (const MWWorld::Ptr& book) { mBook = book; + MWWorld::Ptr player = MWMechanics::getPlayer(); + bool showTakeButton = book.getContainerStore() != &player.getClass().getContainerStore(player); + clearPages(); mCurrentPage = 0; diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index 881b9997c..e8a1a42ff 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -16,7 +16,7 @@ namespace MWGui virtual void exit(); - void openBook(MWWorld::Ptr book, bool showTakeButton); + void setPtr(const MWWorld::Ptr& book); void setInventoryAllowed(bool allowed); protected: diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index fc4a98489..07753ab11 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -103,7 +103,7 @@ void CompanionWindow::onBackgroundSelected() } } -void CompanionWindow::openCompanion(const MWWorld::Ptr& npc) +void CompanionWindow::setPtr(const MWWorld::Ptr& npc) { mPtr = npc; updateEncumbranceBar(); diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index d37f0c4e4..ec70146f2 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -22,7 +22,7 @@ namespace MWGui virtual void resetReference(); - void openCompanion(const MWWorld::Ptr& npc); + void setPtr(const MWWorld::Ptr& npc); void onFrame (); private: diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 62690a0f1..55a03bafd 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -422,7 +422,7 @@ namespace MWGui setCoord(10,10, width-10, height/2); } - void Console::setSelectedObject(const MWWorld::Ptr& object) + void Console::setPtr(const MWWorld::Ptr& object) { if (!object.isEmpty()) { @@ -448,12 +448,12 @@ namespace MWGui void Console::onReferenceUnavailable() { - setSelectedObject(MWWorld::Ptr()); + setPtr(MWWorld::Ptr()); } void Console::resetReference() { ReferenceInterface::resetReference(); - setSelectedObject(MWWorld::Ptr()); + setPtr(MWWorld::Ptr()); } } diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 1232036ca..927fdd5fe 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -25,7 +25,7 @@ namespace MWGui { public: /// Set the implicit object for script execution - void setSelectedObject(const MWWorld::Ptr& object); + void setPtr(const MWWorld::Ptr& object); MyGUI::EditBox* mCommandLine; MyGUI::EditBox* mHistory; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 4f9201f06..6ea2e3e9a 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -129,11 +129,13 @@ namespace MWGui dropItem(); } - void ContainerWindow::openContainer(const MWWorld::Ptr& container, bool loot) + void ContainerWindow::setPtr(const MWWorld::Ptr& container) { mPickpocketDetected = false; mPtr = container; + bool loot = mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead(); + if (mPtr.getTypeName() == typeid(ESM::NPC).name() && !loot) { // we are stealing stuff diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 65cfa35c7..2758f57c9 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -33,7 +33,7 @@ namespace MWGui public: ContainerWindow(DragAndDrop* dragAndDrop); - void openContainer(const MWWorld::Ptr& container, bool loot=false); + void setPtr(const MWWorld::Ptr& container); virtual void onClose(); virtual void resetReference(); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index d9954a792..d2d97a437 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -336,23 +336,23 @@ namespace MWGui if (topic == gmst.find("sPersuasion")->getString()) mPersuasionDialog.setVisible(true); else if (topic == gmst.find("sCompanionShare")->getString()) - MWBase::Environment::get().getWindowManager()->showCompanionWindow(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion, mPtr); else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) { if (topic == gmst.find("sBarter")->getString()) - MWBase::Environment::get().getWindowManager()->startTrade(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter, mPtr); else if (topic == gmst.find("sSpells")->getString()) - MWBase::Environment::get().getWindowManager()->startSpellBuying(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying, mPtr); else if (topic == gmst.find("sTravel")->getString()) - MWBase::Environment::get().getWindowManager()->startTravel(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel, mPtr); else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) - MWBase::Environment::get().getWindowManager()->startSpellMaking (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation, mPtr); else if (topic == gmst.find("sEnchanting")->getString()) - MWBase::Environment::get().getWindowManager()->startEnchanting (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting, mPtr); else if (topic == gmst.find("sServiceTrainingTitle")->getString()) - MWBase::Environment::get().getWindowManager()->startTraining (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training, mPtr); else if (topic == gmst.find("sRepair")->getString()) - MWBase::Environment::get().getWindowManager()->startRepair (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair, mPtr); } } } diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 25568da07..94e8b329d 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -143,51 +143,36 @@ namespace MWGui } } - void EnchantingDialog::startEnchanting (MWWorld::Ptr actor) + void EnchantingDialog::setPtr (const MWWorld::Ptr& ptr) { mName->setCaption(""); - mEnchanting.setSelfEnchanting(false); - mEnchanting.setEnchanter(actor); - - mBuyButton->setCaptionWithReplacing("#{sBuy}"); - - mChanceLayout->setVisible(false); - - mPtr = actor; + if (ptr.getClass().isActor()) + { + mEnchanting.setSelfEnchanting(false); + mEnchanting.setEnchanter(ptr); + mBuyButton->setCaptionWithReplacing("#{sBuy}"); + mChanceLayout->setVisible(false); + mPtr = ptr; + setSoulGem(MWWorld::Ptr()); + mPrice->setVisible(true); + mPriceText->setVisible(true); + } + else + { + mEnchanting.setSelfEnchanting(true); + mEnchanting.setEnchanter(MWMechanics::getPlayer()); + mBuyButton->setCaptionWithReplacing("#{sCreate}"); + bool enabled = Settings::Manager::getBool("show enchant chance","Game"); + mChanceLayout->setVisible(enabled); + mPtr = MWMechanics::getPlayer(); + setSoulGem(ptr); + mPrice->setVisible(false); + mPriceText->setVisible(false); + } - setSoulGem(MWWorld::Ptr()); setItem(MWWorld::Ptr()); - startEditing (); - mPrice->setVisible(true); - mPriceText->setVisible(true); - updateLabels(); - } - - void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) - { - mName->setCaption(""); - - MWWorld::Ptr player = MWMechanics::getPlayer(); - - mEnchanting.setSelfEnchanting(true); - mEnchanting.setEnchanter(player); - - mBuyButton->setCaptionWithReplacing("#{sCreate}"); - - bool enabled = Settings::Manager::getBool("show enchant chance","Game"); - - mChanceLayout->setVisible(enabled); - - mPtr = player; - startEditing(); - - setSoulGem(soulgem); - setItem(MWWorld::Ptr()); - - mPrice->setVisible(false); - mPriceText->setVisible(false); updateLabels(); } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 7c49ae54a..41d6382cc 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -26,8 +26,9 @@ namespace MWGui void setSoulGem (const MWWorld::Ptr& gem); void setItem (const MWWorld::Ptr& item); - void startEnchanting(MWWorld::Ptr actor); - void startSelfEnchanting(MWWorld::Ptr soulgem); + /// Actor Ptr: buy enchantment from this actor + /// Soulgem Ptr: player self-enchant + void setPtr(const MWWorld::Ptr& ptr); virtual void resetReference(); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 0e1b2cc89..ba4d05d75 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -260,7 +260,7 @@ namespace MWGui MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); if (mode == GM_Console) - MWBase::Environment::get().getWindowManager()->setConsoleSelectedObject(object); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Console, object); else if ((mode == GM_Container) || (mode == GM_Inventory)) { // pick up object diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 9c706851f..785b5ee48 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -32,7 +32,7 @@ MerchantRepair::MerchantRepair() mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onOkButtonClick); } -void MerchantRepair::startRepair(const MWWorld::Ptr &actor) +void MerchantRepair::setPtr(const MWWorld::Ptr &actor) { mActor = actor; @@ -145,7 +145,7 @@ void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) MWMechanics::CreatureStats& actorStats = mActor.getClass().getCreatureStats(mActor); actorStats.setGoldPool(actorStats.getGoldPool() + price); - startRepair(mActor); + setPtr(mActor); } void MerchantRepair::onOkButtonClick(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 5006b08a4..76ccd28cc 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -16,7 +16,7 @@ public: virtual void exit(); - void startRepair(const MWWorld::Ptr& actor); + void setPtr(const MWWorld::Ptr& actor); private: MyGUI::ScrollView* mList; diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 00af45695..54473746a 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -67,7 +67,7 @@ void Recharge::exit() MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Recharge); } -void Recharge::start (const MWWorld::Ptr &item) +void Recharge::setPtr (const MWWorld::Ptr &item) { mGemIcon->setItem(item); mGemIcon->setUserString("ToolTipType", "ItemPtr"); diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp index d963e9d66..93f86ab65 100644 --- a/apps/openmw/mwgui/recharge.hpp +++ b/apps/openmw/mwgui/recharge.hpp @@ -26,7 +26,7 @@ public: virtual void exit(); - void start (const MWWorld::Ptr& gem); + void setPtr (const MWWorld::Ptr& gem); protected: ItemChargeView* mBox; diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index f917cef0f..295b8254b 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -63,7 +63,7 @@ void Repair::exit() MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Repair); } -void Repair::startRepairItem(const MWWorld::Ptr &item) +void Repair::setPtr(const MWWorld::Ptr &item) { MWBase::Environment::get().getWindowManager()->playSound("Item Repair Up"); diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index 44c380b51..a2573d780 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -23,7 +23,7 @@ public: virtual void exit(); - void startRepairItem (const MWWorld::Ptr& item); + void setPtr (const MWWorld::Ptr& item); protected: ItemChargeView* mRepairBox; diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index a5d4c3324..3649afe23 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -12,6 +12,7 @@ #include "../mwmechanics/actorutil.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/class.hpp" #include "formatting.hpp" @@ -49,13 +50,16 @@ namespace MWGui center(); } - void ScrollWindow::openScroll (MWWorld::Ptr scroll, bool showTakeButton) + void ScrollWindow::setPtr (const MWWorld::Ptr& scroll) { // no 3d sounds because the object could be in a container. MWBase::Environment::get().getWindowManager()->playSound("scroll"); mScroll = scroll; + MWWorld::Ptr player = MWMechanics::getPlayer(); + bool showTakeButton = scroll.getContainerStore() != &player.getClass().getContainerStore(player); + MWWorld::LiveCellRef *ref = mScroll.get(); Formatting::BookFormatter formatter; diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 961f1b675..5ae8e972a 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -17,7 +17,7 @@ namespace MWGui public: ScrollWindow (); - void openScroll (MWWorld::Ptr scroll, bool showTakeButton); + void setPtr (const MWWorld::Ptr& scroll); virtual void exit(); void setInventoryAllowed(bool allowed); diff --git a/apps/openmw/mwgui/soulgemdialog.cpp b/apps/openmw/mwgui/soulgemdialog.cpp index 0232eb7b3..104c81eab 100644 --- a/apps/openmw/mwgui/soulgemdialog.cpp +++ b/apps/openmw/mwgui/soulgemdialog.cpp @@ -22,13 +22,11 @@ namespace MWGui { if (button == 0) { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Recharge); - MWBase::Environment::get().getWindowManager()->startRecharge(mSoulgem); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Recharge, mSoulgem); } else { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting); - MWBase::Environment::get().getWindowManager()->startSelfEnchanting(mSoulgem); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting, mSoulgem); } } diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 6a7376aa0..592316274 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -88,7 +88,12 @@ namespace MWGui mSpellsWidgetMap.clear(); } - void SpellBuyingWindow::startSpellBuying(const MWWorld::Ptr& actor, int startOffset) + void SpellBuyingWindow::setPtr(const MWWorld::Ptr &actor) + { + setPtr(actor, 0); + } + + void SpellBuyingWindow::setPtr(const MWWorld::Ptr& actor, int startOffset) { center(); mPtr = actor; @@ -161,7 +166,7 @@ namespace MWGui MWMechanics::CreatureStats& npcStats = mPtr.getClass().getCreatureStats(mPtr); npcStats.setGoldPool(npcStats.getGoldPool() + price); - startSpellBuying(mPtr, mSpellsView->getViewOffset().top); + setPtr(mPtr, mSpellsView->getViewOffset().top); MWBase::Environment::get().getWindowManager()->playSound("Item Gold Up"); } diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 37210819f..b96896e4c 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -25,7 +25,8 @@ namespace MWGui public: SpellBuyingWindow(); - void startSpellBuying(const MWWorld::Ptr& actor, int startOffset); + void setPtr(const MWWorld::Ptr& actor); + void setPtr(const MWWorld::Ptr& actor, int startOffset); virtual void exit(); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 6a36554d8..d5982a174 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -352,7 +352,7 @@ namespace MWGui setWidgets(mAvailableEffectsList, mUsedEffectsView); } - void SpellCreationDialog::startSpellMaking (MWWorld::Ptr actor) + void SpellCreationDialog::setPtr (const MWWorld::Ptr& actor) { mPtr = actor; mNameEdit->setCaption(""); diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index d12115c88..76038abb4 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -153,7 +153,7 @@ namespace MWGui virtual void onOpen(); virtual void exit(); - void startSpellMaking(MWWorld::Ptr actor); + void setPtr(const MWWorld::Ptr& actor); protected: virtual void onReferenceUnavailable (); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index ca0bb48e8..60abf4ac7 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -115,7 +115,7 @@ namespace MWGui } } - void TradeWindow::startTrade(const MWWorld::Ptr& actor) + void TradeWindow::setPtr(const MWWorld::Ptr& actor) { mPtr = actor; diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 4b03c8d90..984f5a394 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -27,7 +27,7 @@ namespace MWGui public: TradeWindow(); - void startTrade(const MWWorld::Ptr& actor); + void setPtr(const MWWorld::Ptr& actor); void borrowItem (int index, size_t count); void returnItem (int index, size_t count); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index d2e771918..3079adb6d 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -65,7 +65,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); } - void TrainingWindow::startTraining (MWWorld::Ptr actor) + void TrainingWindow::setPtr (const MWWorld::Ptr& actor) { mPtr = actor; diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index 95a35be7f..e52a889ef 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -18,7 +18,7 @@ namespace MWGui virtual void exit(); - void startTraining(MWWorld::Ptr actor); + void setPtr(const MWWorld::Ptr& actor); void onFrame(float dt); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 3a7afe497..4c4dc436c 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -108,7 +108,7 @@ namespace MWGui MyGUI::Gui::getInstance().destroyWidget(mDestinationsView->getChildAt(0)); } - void TravelWindow::startTravel(const MWWorld::Ptr& actor) + void TravelWindow::setPtr(const MWWorld::Ptr& actor) { center(); mPtr = actor; diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index 3230f897f..529d5ebe1 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -26,7 +26,7 @@ namespace MWGui virtual void exit(); - void startTravel(const MWWorld::Ptr& actor); + void setPtr (const MWWorld::Ptr& actor); protected: MyGUI::Button* mCancelButton; diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 400dc0ce4..73574ce7c 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -8,6 +8,11 @@ namespace MWBase class WindowManager; } +namespace MWWorld +{ + class Ptr; +} + namespace MWGui { class WindowManager; @@ -21,6 +26,9 @@ namespace MWGui // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; + /// Open this object in the GUI, for windows that support it + virtual void setPtr(const MWWorld::Ptr& ptr) {} + /// Notify that window has been made visible virtual void onOpen() {} /// Notify that window has been hidden diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 81edc4a00..54ff8c30f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1207,24 +1207,31 @@ namespace MWGui void WindowManager::pushGuiMode(GuiMode mode) { - if (mode==GM_Inventory && mAllowed==GW_None) - return; + pushGuiMode(mode, MWWorld::Ptr()); + } - if (!mGuiModes.empty() && mGuiModes.back() == mode) + void WindowManager::pushGuiMode(GuiMode mode, const MWWorld::Ptr& arg) + { + if (mode==GM_Inventory && mAllowed==GW_None) return; - // If this mode already exists somewhere in the stack, just bring it to the front. - if (std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end()) + if (mGuiModes.empty() || mGuiModes.back() != mode) { - mGuiModes.erase(std::find(mGuiModes.begin(), mGuiModes.end(), mode)); - } + // If this mode already exists somewhere in the stack, just bring it to the front. + if (std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end()) + { + mGuiModes.erase(std::find(mGuiModes.begin(), mGuiModes.end(), mode)); + } - if (!mGuiModes.empty()) - mGuiModeStates[mGuiModes.back()].update(false); + if (!mGuiModes.empty()) + mGuiModeStates[mGuiModes.back()].update(false); - mGuiModes.push_back(mode); + mGuiModes.push_back(mode); - mGuiModeStates[mode].update(true); + mGuiModeStates[mode].update(true); + } + for (WindowBase* window : mGuiModeStates[mode].mWindows) + window->setPtr(arg); bool gameMode = !isGuiMode(); MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); @@ -1543,52 +1550,11 @@ namespace MWGui mMap->addVisitedLocation (name, x, y); } - void WindowManager::startSpellMaking(MWWorld::Ptr actor) - { - pushGuiMode(GM_SpellCreation); - mSpellCreationDialog->startSpellMaking (actor); - } - - void WindowManager::startEnchanting (MWWorld::Ptr actor) - { - pushGuiMode(GM_Enchanting); - mEnchantingDialog->startEnchanting (actor); - } - - void WindowManager::startSelfEnchanting(MWWorld::Ptr soulgem) - { - mEnchantingDialog->startSelfEnchanting(soulgem); - } - - void WindowManager::startTraining(MWWorld::Ptr actor) - { - pushGuiMode(GM_Training); - mTrainingWindow->startTraining(actor); - } - - void WindowManager::startRepair(MWWorld::Ptr actor) - { - pushGuiMode(GM_MerchantRepair); - mMerchantRepair->startRepair(actor); - } - - void WindowManager::startRepairItem(MWWorld::Ptr item) - { - pushGuiMode(MWGui::GM_Repair); - mRepair->startRepairItem(item); - } - const Translation::Storage& WindowManager::getTranslationDataStorage() const { return mTranslationDataStorage; } - void WindowManager::showCompanionWindow(MWWorld::Ptr actor) - { - pushGuiMode(MWGui::GM_Companion); - mCompanionWindow->openCompanion(actor); - } - void WindowManager::changePointer(const std::string &name) { MyGUI::PointerManager::getInstance().setPointer(name); @@ -1642,11 +1608,6 @@ namespace MWGui return mLoadingScreen; } - void WindowManager::startRecharge(MWWorld::Ptr soulgem) - { - mRecharge->start(soulgem); - } - bool WindowManager::getCursorVisible() { return mCursorVisible; @@ -1996,53 +1957,12 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->playSound(soundId, volume, pitch, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); } - void WindowManager::setConsoleSelectedObject(const MWWorld::Ptr &object) - { - mConsole->setSelectedObject(object); - } - void WindowManager::updateSpellWindow() { if (mSpellWindow) mSpellWindow->updateSpells(); } - void WindowManager::startTravel(const MWWorld::Ptr &actor) - { - pushGuiMode(GM_Travel); - mTravelWindow->startTravel(actor); - } - - void WindowManager::startSpellBuying(const MWWorld::Ptr &actor) - { - pushGuiMode(GM_SpellBuying); - mSpellBuyingWindow->startSpellBuying(actor, 0); - } - - void WindowManager::startTrade(const MWWorld::Ptr &actor) - { - pushGuiMode(GM_Barter); - mTradeWindow->startTrade(actor); - } - - void WindowManager::openContainer(const MWWorld::Ptr &container, bool loot) - { - pushGuiMode(GM_Container); - mContainerWindow->openContainer(container, loot); - } - - void WindowManager::showBook(const MWWorld::Ptr &item, bool showTakeButton) - { - pushGuiMode(GM_Book); - mBookWindow->openBook(item, showTakeButton); - } - - void WindowManager::showScroll(const MWWorld::Ptr &item, bool showTakeButton) - { - pushGuiMode(GM_Scroll); - mScrollWindow->openScroll(item, showTakeButton); - } - std::string WindowManager::correctIconPath(const std::string& path) { return Misc::ResourceHelpers::correctIconPath(path, mResourceSystem->getVFS()); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 524575c6a..c267f505a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -158,7 +158,8 @@ namespace MWGui virtual void setNewGame(bool newgame); - virtual void pushGuiMode(GuiMode mode); + virtual void pushGuiMode(GuiMode mode, const MWWorld::Ptr& arg); + virtual void pushGuiMode (GuiMode mode); virtual void popGuiMode(); virtual void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack @@ -196,8 +197,6 @@ namespace MWGui virtual void updateSpellWindow(); - virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); - ///< Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value); virtual void setValue (int parSkill, const MWMechanics::SkillValue& value); @@ -315,21 +314,6 @@ namespace MWGui virtual void updatePlayer(); - virtual void showCompanionWindow(MWWorld::Ptr actor); - virtual void startSpellMaking(MWWorld::Ptr actor); - virtual void startEnchanting(MWWorld::Ptr actor); - virtual void startSelfEnchanting(MWWorld::Ptr soulgem); - virtual void startTraining(MWWorld::Ptr actor); - virtual void startRepair(MWWorld::Ptr actor); - virtual void startRepairItem(MWWorld::Ptr item); - virtual void startRecharge(MWWorld::Ptr soulgem); - virtual void startTravel(const MWWorld::Ptr& actor); - virtual void startSpellBuying(const MWWorld::Ptr &actor); - virtual void startTrade(const MWWorld::Ptr &actor); - virtual void openContainer(const MWWorld::Ptr &container, bool loot); - virtual void showBook(const MWWorld::Ptr& item, bool showTakeButton); - virtual void showScroll(const MWWorld::Ptr& item, bool showTakeButton); - virtual void showSoulgemDialog (MWWorld::Ptr item); virtual void changePointer (const std::string& name); diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index 0df451b18..7ff6dd068 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -10,9 +10,8 @@ namespace MWWorld { - ActionOpen::ActionOpen (const MWWorld::Ptr& container, bool loot) + ActionOpen::ActionOpen (const MWWorld::Ptr& container) : Action (false, container) - , mLoot(loot) { } @@ -23,6 +22,6 @@ namespace MWWorld MWMechanics::diseaseContact(actor, getTarget()); - MWBase::Environment::get().getWindowManager()->openContainer(getTarget(), mLoot); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container, getTarget()); } } diff --git a/apps/openmw/mwworld/actionopen.hpp b/apps/openmw/mwworld/actionopen.hpp index 454cc09f1..3bce25c6b 100644 --- a/apps/openmw/mwworld/actionopen.hpp +++ b/apps/openmw/mwworld/actionopen.hpp @@ -12,12 +12,9 @@ namespace MWWorld virtual void executeImp (const MWWorld::Ptr& actor); public: - ActionOpen (const Ptr& container, bool loot=false); + ActionOpen (const Ptr& container); ///< \param container The Container the Player has activated. - /// \param loot If true, display the "dispose of corpse" button - private: - bool mLoot; }; } diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index b3ac772ae..d2dc972fc 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -32,14 +32,12 @@ namespace MWWorld return; } - bool showTakeButton = (getTarget().getContainerStore() != &actor.getClass().getContainerStore(actor)); - LiveCellRef *ref = getTarget().get(); if (ref->mBase->mData.mIsScroll) - MWBase::Environment::get().getWindowManager()->showScroll(getTarget(), showTakeButton); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Scroll, getTarget()); else - MWBase::Environment::get().getWindowManager()->showBook(getTarget(), showTakeButton); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Book, getTarget()); MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats (actor); diff --git a/apps/openmw/mwworld/actionread.hpp b/apps/openmw/mwworld/actionread.hpp index 00a4756dd..c23bf2900 100644 --- a/apps/openmw/mwworld/actionread.hpp +++ b/apps/openmw/mwworld/actionread.hpp @@ -16,4 +16,4 @@ namespace MWWorld }; } -#endif // ACTIONOPEN_H +#endif // ACTIONREAD_H diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp index 8e19927b8..191cf2063 100644 --- a/apps/openmw/mwworld/actionrepair.cpp +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -23,6 +23,6 @@ namespace MWWorld return; } - MWBase::Environment::get().getWindowManager()->startRepairItem(getTarget()); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Repair, getTarget()); } } From bbafe1e4561fc54da1f240d9083b6592eb6f758d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 21:31:10 +0200 Subject: [PATCH 144/505] Remove redundant player cell variable --- apps/openmw/mwgui/referenceinterface.cpp | 10 ---------- apps/openmw/mwgui/referenceinterface.hpp | 5 +---- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index 9aaa98f19..6213d9e25 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -1,14 +1,8 @@ #include "referenceinterface.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/environment.hpp" - -#include "../mwmechanics/actorutil.hpp" - namespace MWGui { ReferenceInterface::ReferenceInterface() - : mCurrentPlayerCell(NULL) { } @@ -18,8 +12,6 @@ namespace MWGui void ReferenceInterface::checkReferenceAvailable() { - MWWorld::CellStore* playerCell = MWMechanics::getPlayer().getCell(); - // check if count of the reference has become 0 if (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0) { @@ -29,7 +21,5 @@ namespace MWGui onReferenceUnavailable(); } } - - mCurrentPlayerCell = playerCell; } } diff --git a/apps/openmw/mwgui/referenceinterface.hpp b/apps/openmw/mwgui/referenceinterface.hpp index 0ba180de8..6428a5b54 100644 --- a/apps/openmw/mwgui/referenceinterface.hpp +++ b/apps/openmw/mwgui/referenceinterface.hpp @@ -17,15 +17,12 @@ namespace MWGui void checkReferenceAvailable(); ///< closes the window, if the MW-reference has become unavailable - virtual void resetReference() { mPtr = MWWorld::Ptr(); mCurrentPlayerCell = NULL; } + virtual void resetReference() { mPtr = MWWorld::Ptr(); } protected: virtual void onReferenceUnavailable() = 0; ///< called when reference has become unavailable MWWorld::Ptr mPtr; - - private: - MWWorld::CellStore* mCurrentPlayerCell; }; } From 269094ba8d84945de1b86b40c4c9db81fe46efbf Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 23:01:34 +0200 Subject: [PATCH 145/505] Restore the previous key focus widget when exiting modal dialog --- apps/openmw/mwgui/windowbase.cpp | 5 +++-- apps/openmw/mwgui/windowmanagerimp.cpp | 26 ++++++++++++++++++++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 8 ++++++-- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 5ed564737..e563d9aa9 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -67,14 +67,15 @@ WindowModal::WindowModal(const std::string& parLayout) void WindowModal::onOpen() { - MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); + // Order important. We need to save the key focus widget before its unset MWBase::Environment::get().getWindowManager()->addCurrentModal(this); //Set so we can escape it if needed + MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); } void WindowModal::onClose() { - MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); MWBase::Environment::get().getWindowManager()->removeCurrentModal(this); + MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); } NoDrop::NoDrop(DragAndDrop *drag, MyGUI::Widget *widget) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 54ff8c30f..2d17db643 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -136,6 +137,7 @@ namespace MWGui , mWorkQueue(workQueue) , mViewer(viewer) , mConsoleOnlyScripts(consoleOnlyScripts) + , mSaveKeyFocus(NULL) , mCurrentModals() , mHud(NULL) , mMap(NULL) @@ -260,6 +262,8 @@ namespace MWGui MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); + MyGUI::WidgetManager::getInstance().registerUnlinker(this); + // Create all cursors in advance createCursors(); onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); @@ -496,6 +500,8 @@ namespace MWGui MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear(); MyGUI::ClipboardManager::getInstance().eventClipboardRequested.clear(); + MyGUI::WidgetManager::getInstance().unregisterUnlinker(this); + delete mConsole; delete mMessageBoxManager; delete mHud; @@ -1608,6 +1614,12 @@ namespace MWGui return mLoadingScreen; } + void WindowManager::_unlinkWidget(MyGUI::Widget *widget) + { + if (widget == mSaveKeyFocus) + mSaveKeyFocus = NULL; + } + bool WindowManager::getCursorVisible() { return mCursorVisible; @@ -1818,6 +1830,17 @@ namespace MWGui { if (!mCurrentModals.empty()) mCurrentModals.top()->exit(); + + if (mCurrentModals.empty()) + MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveKeyFocus); + } + + void WindowManager::addCurrentModal(WindowModal *input) + { + if (mCurrentModals.empty()) + mSaveKeyFocus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + + mCurrentModals.push(input); } void WindowManager::removeCurrentModal(WindowModal* input) @@ -1827,6 +1850,9 @@ namespace MWGui if(!mCurrentModals.empty()) if(input == mCurrentModals.top()) mCurrentModals.pop(); + + if (mCurrentModals.empty()) + MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveKeyFocus); } void WindowManager::onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index c267f505a..18ece21f9 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -124,7 +124,7 @@ namespace MWGui class JailScreen; class KeyboardNavigation; - class WindowManager : public MWBase::WindowManager + class WindowManager : public MWBase::WindowManager, MyGUI::IUnlinkWidget { public: typedef std::pair Faction; @@ -142,6 +142,8 @@ namespace MWGui virtual Loading::Listener* getLoadingScreen(); + void _unlinkWidget(MyGUI::Widget* widget); + /// @note This method will block until the video finishes playing /// (and will continually update the window while doing so) virtual void playVideo(const std::string& name, bool allowSkipping); @@ -341,7 +343,7 @@ namespace MWGui /// Sets the current Modal /** Used to send exit command to active Modal when Esc is pressed **/ - virtual void addCurrentModal(WindowModal* input) {mCurrentModals.push(input);} + virtual void addCurrentModal(WindowModal* input); /// Removes the top Modal /** Used when one Modal adds another Modal @@ -404,6 +406,8 @@ namespace MWGui MWWorld::Ptr mSelectedEnchantItem; MWWorld::Ptr mSelectedWeapon; + MyGUI::Widget* mSaveKeyFocus; + std::stack mCurrentModals; // Markers placed manually by the player. Must be shared between both map views (the HUD map and the map window). From 531e7ac58677dc44fe94c433d2d979caed8710dc Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 23:25:20 +0200 Subject: [PATCH 146/505] Allow drag-and-drop to be cancelled (Esc or Inventory key) --- apps/openmw/mwgui/draganddrop.cpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 14 +++++++++++++- apps/openmw/mwinput/inputmanagerimp.cpp | 6 +++--- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index fa17d974d..fe0ad3374 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -125,6 +125,8 @@ void DragAndDrop::finish() { mIsOnDragAndDrop = false; mSourceSortModel->clearDragItems(); + // since mSourceView doesn't get updated in drag() + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); MyGUI::Gui::getInstance().destroyWidget(mDraggedWidget); mDraggedWidget = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2d17db643..4964af7d8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -755,7 +755,14 @@ namespace MWGui mGarbageDialogs.push_back(dialog); } - void WindowManager::exitCurrentGuiMode() { + void WindowManager::exitCurrentGuiMode() + { + if (mDragAndDrop && mDragAndDrop->mIsOnDragAndDrop) + { + mDragAndDrop->finish(); + return; + } + switch(mGuiModes.back()) { case GM_QuickKeysMenu: mQuickKeysMenu->exit(); @@ -1247,6 +1254,11 @@ namespace MWGui void WindowManager::popGuiMode() { + if (mDragAndDrop && mDragAndDrop->mIsOnDragAndDrop) + { + mDragAndDrop->finish(); + } + if (!mGuiModes.empty()) { mGuiModeStates[mGuiModes.back()].update(false); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 33f1edb6c..3ed259c58 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -177,13 +177,13 @@ namespace MWInput void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) { - if (mDragDrop) - return; - resetIdleTime (); int action = channel->getNumber(); + if (mDragDrop && action != A_GameMenu && action != A_Inventory) + return; + if((previousValue == 1 || previousValue == 0) && (currentValue==1 || currentValue==0)) { //Is a normal button press, so don't change it at all From 20766fb508f6f4a286a786f1b2d63225de11fd8a Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 00:00:40 +0200 Subject: [PATCH 147/505] Associate open/close sounds with the GUI mode --- apps/openmw/mwbase/windowmanager.hpp | 4 ++-- apps/openmw/mwgui/bookwindow.cpp | 5 ----- apps/openmw/mwgui/scrollwindow.cpp | 7 +------ apps/openmw/mwgui/windowmanagerimp.cpp | 18 ++++++++++++++---- apps/openmw/mwgui/windowmanagerimp.hpp | 7 +++++-- apps/openmw/mwinput/inputmanagerimp.cpp | 2 -- 6 files changed, 22 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 242f358a9..243ec3ccf 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -117,9 +117,9 @@ namespace MWBase virtual void pushGuiMode (MWGui::GuiMode mode, const MWWorld::Ptr& arg) = 0; virtual void pushGuiMode (MWGui::GuiMode mode) = 0; - virtual void popGuiMode() = 0; + virtual void popGuiMode(bool noSound=false) = 0; - virtual void removeGuiMode (MWGui::GuiMode mode) = 0; + virtual void removeGuiMode (MWGui::GuiMode mode, bool noSound=false) = 0; ///< can be anywhere in the stack virtual void goToJail(int days) = 0; diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index ca697d0b6..7cabf68b1 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -85,8 +85,6 @@ namespace MWGui clearPages(); mCurrentPage = 0; - MWBase::Environment::get().getWindowManager()->playSound("book open"); - MWWorld::LiveCellRef *ref = mBook.get(); Formatting::BookFormatter formatter; @@ -100,9 +98,6 @@ namespace MWGui void BookWindow::exit() { - // no 3d sounds because the object could be in a container. - MWBase::Environment::get().getWindowManager()->playSound("book close"); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); } diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 3649afe23..ccbd1d7c0 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -52,9 +52,6 @@ namespace MWGui void ScrollWindow::setPtr (const MWWorld::Ptr& scroll) { - // no 3d sounds because the object could be in a container. - MWBase::Environment::get().getWindowManager()->playSound("scroll"); - mScroll = scroll; MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -81,8 +78,6 @@ namespace MWGui void ScrollWindow::exit() { - MWBase::Environment::get().getWindowManager()->playSound("scroll"); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); } @@ -110,6 +105,6 @@ namespace MWGui MWWorld::ActionTake take(mScroll); take.execute (MWMechanics::getPlayer()); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll, true); } } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 4964af7d8..70b95351b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -354,6 +354,8 @@ namespace MWGui bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds"); mJournal = JournalWindow::create(JournalViewModel::create (), questList); mGuiModeStates[GM_Journal] = GuiModeState(mJournal); + mGuiModeStates[GM_Journal].mCloseSound = "book close"; + mGuiModeStates[GM_Journal].mOpenSound = "book open"; mMessageBoxManager = new MessageBoxManager(mStore->get().find("fMessageTimePerChar")->getFloat()); mSpellBuyingWindow = new SpellBuyingWindow(); @@ -374,9 +376,13 @@ namespace MWGui mToolTips = new ToolTips(); mScrollWindow = new ScrollWindow(); mGuiModeStates[GM_Scroll] = GuiModeState(mScrollWindow); + mGuiModeStates[GM_Scroll].mOpenSound = "scroll"; + mGuiModeStates[GM_Scroll].mCloseSound = "scroll"; mBookWindow = new BookWindow(); mGuiModeStates[GM_Book] = GuiModeState(mBookWindow); + mGuiModeStates[GM_Book].mOpenSound = "book open"; + mGuiModeStates[GM_Book].mCloseSound = "book close"; mCountDialog = new CountDialog(); mSettingsWindow = new SettingsWindow(); @@ -840,7 +846,6 @@ namespace MWGui mRepair->exit(); break; case GM_Journal: - playSound("book close"); removeGuiMode(GM_Journal); //Simple way to remove it break; default: @@ -1242,6 +1247,7 @@ namespace MWGui mGuiModes.push_back(mode); mGuiModeStates[mode].update(true); + playSound(mGuiModeStates[mode].mOpenSound); } for (WindowBase* window : mGuiModeStates[mode].mWindows) window->setPtr(arg); @@ -1252,7 +1258,7 @@ namespace MWGui updateVisible(); } - void WindowManager::popGuiMode() + void WindowManager::popGuiMode(bool noSound) { if (mDragAndDrop && mDragAndDrop->mIsOnDragAndDrop) { @@ -1262,6 +1268,8 @@ namespace MWGui if (!mGuiModes.empty()) { mGuiModeStates[mGuiModes.back()].update(false); + if (!noSound) + playSound(mGuiModeStates[mGuiModes.back()].mCloseSound); mGuiModes.pop_back(); } @@ -1274,11 +1282,11 @@ namespace MWGui updateVisible(); } - void WindowManager::removeGuiMode(GuiMode mode) + void WindowManager::removeGuiMode(GuiMode mode, bool noSound) { if (!mGuiModes.empty() && mGuiModes.back() == mode) { - popGuiMode(); + popGuiMode(noSound); return; } @@ -1992,6 +2000,8 @@ namespace MWGui void WindowManager::playSound(const std::string& soundId, float volume, float pitch) { + if (soundId.empty()) + return; MWBase::Environment::get().getSoundManager()->playSound(soundId, volume, pitch, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 18ece21f9..9fa921a4c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -162,8 +162,8 @@ namespace MWGui virtual void pushGuiMode(GuiMode mode, const MWWorld::Ptr& arg); virtual void pushGuiMode (GuiMode mode); - virtual void popGuiMode(); - virtual void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack + virtual void popGuiMode(bool noSound=false); + virtual void removeGuiMode(GuiMode mode, bool noSound=false); ///< can be anywhere in the stack virtual void goToJail(int days); @@ -497,6 +497,9 @@ namespace MWGui std::vector mWindows; std::vector mVisibilityMask; // optional, may be used to temporarily exclude windows from this mode. + + std::string mCloseSound; + std::string mOpenSound; }; // Defines the windows that should be shown in a particular GUI mode. std::map mGuiModeStates; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 3ed259c58..cf42db04b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1039,12 +1039,10 @@ namespace MWInput && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_MainMenu && MWBase::Environment::get().getWindowManager ()->getJournalAllowed()) { - MWBase::Environment::get().getWindowManager()->playSound ("book open"); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Journal); } else if(MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Journal)) { - MWBase::Environment::get().getWindowManager()->playSound ("book close"); MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Journal); } } From 4fff2e2e34eeac62f7c510e63085bf8c676785d9 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 12:18:39 +0200 Subject: [PATCH 148/505] Refactor exitCurrentGuiMode --- apps/openmw/mwgui/alchemywindow.cpp | 9 +- apps/openmw/mwgui/alchemywindow.hpp | 1 - apps/openmw/mwgui/birth.hpp | 2 + apps/openmw/mwgui/bookwindow.cpp | 7 +- apps/openmw/mwgui/bookwindow.hpp | 2 - apps/openmw/mwgui/class.cpp | 9 +- apps/openmw/mwgui/class.hpp | 14 ++- apps/openmw/mwgui/companionwindow.cpp | 9 +- apps/openmw/mwgui/companionwindow.hpp | 2 +- apps/openmw/mwgui/confirmationdialog.cpp | 7 +- apps/openmw/mwgui/confirmationdialog.hpp | 2 +- apps/openmw/mwgui/console.cpp | 5 - apps/openmw/mwgui/console.hpp | 2 - apps/openmw/mwgui/container.cpp | 10 +- apps/openmw/mwgui/container.hpp | 2 - apps/openmw/mwgui/countdialog.cpp | 12 +-- apps/openmw/mwgui/countdialog.hpp | 2 - apps/openmw/mwgui/dialogue.cpp | 16 ++-- apps/openmw/mwgui/dialogue.hpp | 3 +- apps/openmw/mwgui/enchantingdialog.cpp | 7 +- apps/openmw/mwgui/enchantingdialog.hpp | 2 - apps/openmw/mwgui/itemselection.cpp | 3 +- apps/openmw/mwgui/itemselection.hpp | 2 +- apps/openmw/mwgui/jailscreen.hpp | 2 + apps/openmw/mwgui/mapwindow.cpp | 5 - apps/openmw/mwgui/mapwindow.hpp | 1 - apps/openmw/mwgui/merchantrepair.cpp | 7 +- apps/openmw/mwgui/merchantrepair.hpp | 2 - apps/openmw/mwgui/quickkeysmenu.cpp | 13 +-- apps/openmw/mwgui/quickkeysmenu.hpp | 5 +- apps/openmw/mwgui/race.hpp | 2 + apps/openmw/mwgui/recharge.cpp | 7 +- apps/openmw/mwgui/recharge.hpp | 2 - apps/openmw/mwgui/repair.cpp | 7 +- apps/openmw/mwgui/repair.hpp | 2 - apps/openmw/mwgui/review.hpp | 2 + apps/openmw/mwgui/savegamedialog.cpp | 7 +- apps/openmw/mwgui/savegamedialog.hpp | 2 - apps/openmw/mwgui/scrollwindow.cpp | 7 +- apps/openmw/mwgui/scrollwindow.hpp | 1 - apps/openmw/mwgui/settingswindow.cpp | 7 +- apps/openmw/mwgui/settingswindow.hpp | 2 - apps/openmw/mwgui/spellbuyingwindow.cpp | 7 +- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 - apps/openmw/mwgui/spellcreationdialog.cpp | 12 +-- apps/openmw/mwgui/spellcreationdialog.hpp | 3 +- apps/openmw/mwgui/textinput.hpp | 2 + apps/openmw/mwgui/tradewindow.cpp | 5 +- apps/openmw/mwgui/tradewindow.hpp | 2 +- apps/openmw/mwgui/trainingwindow.cpp | 7 +- apps/openmw/mwgui/trainingwindow.hpp | 2 - apps/openmw/mwgui/travelwindow.cpp | 7 +- apps/openmw/mwgui/travelwindow.hpp | 2 - apps/openmw/mwgui/waitdialog.cpp | 5 +- apps/openmw/mwgui/waitdialog.hpp | 2 +- apps/openmw/mwgui/windowbase.hpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 110 +++++----------------- 57 files changed, 101 insertions(+), 284 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index c68bad02a..5b1489821 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -59,7 +59,7 @@ namespace MWGui void AlchemyWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Alchemy); } void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) @@ -103,6 +103,7 @@ namespace MWGui void AlchemyWindow::onOpen() { + mAlchemy->clear(); mAlchemy->setAlchemist (MWMechanics::getPlayer()); InventoryItemModel* model = new InventoryItemModel(MWMechanics::getPlayer()); @@ -129,12 +130,6 @@ namespace MWGui update(); } - void AlchemyWindow::exit() { - mAlchemy->clear(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Alchemy); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Inventory); - } - void AlchemyWindow::onIngredientSelected(MyGUI::Widget* _sender) { removeIngredient(_sender); diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 8b7bcaaca..8dffaaad1 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -25,7 +25,6 @@ namespace MWGui AlchemyWindow(); virtual void onOpen(); - virtual void exit(); private: std::string mSuggestedPotionName; diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index c13d49838..86af14286 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -22,6 +22,8 @@ namespace MWGui void setNextButtonShow(bool shown); virtual void onOpen(); + bool exit() { return false; } + // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 7cabf68b1..5abc63c55 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -96,11 +96,6 @@ namespace MWGui setTakeButtonShow(showTakeButton); } - void BookWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); - } - void BookWindow::setTakeButtonShow(bool show) { mTakeButtonShow = show; @@ -115,7 +110,7 @@ namespace MWGui void BookWindow::onCloseButtonClicked (MyGUI::Widget* sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); } void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender) diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index e8a1a42ff..4f7224ea8 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -14,8 +14,6 @@ namespace MWGui public: BookWindow(); - virtual void exit(); - void setPtr(const MWWorld::Ptr& book); void setInventoryAllowed(bool allowed); diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 2278b5141..c63d470d7 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -730,9 +730,10 @@ namespace MWGui exit(); } - void SelectSpecializationDialog::exit() + bool SelectSpecializationDialog::exit() { eventCancel(); + return true; } /* SelectAttributeDialog */ @@ -778,9 +779,10 @@ namespace MWGui exit(); } - void SelectAttributeDialog::exit() + bool SelectAttributeDialog::exit() { eventCancel(); + return true; } @@ -869,9 +871,10 @@ namespace MWGui exit(); } - void SelectSkillDialog::exit() + bool SelectSkillDialog::exit() { eventCancel(); + return true; } /* DescriptionDialog */ diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 2b205d12f..3a2573fd4 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -23,6 +23,8 @@ namespace MWGui virtual void onOpen(); + bool exit() { return false; } + // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Int; @@ -67,6 +69,8 @@ namespace MWGui std::string getClassId() const; void setClassId(const std::string &classId); + bool exit() { return false; } + // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; @@ -102,6 +106,8 @@ namespace MWGui void setNextButtonShow(bool shown); virtual void onOpen(); + bool exit() { return false; } + // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; @@ -142,7 +148,7 @@ namespace MWGui SelectSpecializationDialog(); ~SelectSpecializationDialog(); - virtual void exit(); + virtual bool exit(); ESM::Class::Specialization getSpecializationId() const { return mSpecializationId; } @@ -175,7 +181,7 @@ namespace MWGui SelectAttributeDialog(); ~SelectAttributeDialog(); - virtual void exit(); + virtual bool exit(); ESM::Attribute::AttributeID getAttributeId() const { return mAttributeId; } @@ -206,7 +212,7 @@ namespace MWGui SelectSkillDialog(); ~SelectSkillDialog(); - virtual void exit(); + virtual bool exit(); ESM::Skill::SkillEnum getSkillId() const { return mSkillId; } @@ -262,6 +268,8 @@ namespace MWGui CreateClassDialog(); virtual ~CreateClassDialog(); + bool exit() { return false; } + std::string getName() const; std::string getDescription() const; ESM::Class::Specialization getSpecializationId() const; diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 07753ab11..c4e50c8c2 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -139,10 +139,11 @@ void CompanionWindow::updateEncumbranceBar() void CompanionWindow::onCloseButtonClicked(MyGUI::Widget* _sender) { - exit(); + if (exit()) + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion); } -void CompanionWindow::exit() +bool CompanionWindow::exit() { if (mModel && mModel->hasProfit(mPtr) && getProfit(mPtr) < 0) { @@ -151,9 +152,9 @@ void CompanionWindow::exit() buttons.push_back("#{sCompanionWarningButtonTwo}"); mMessageBoxManager->createInteractiveMessageBox("#{sCompanionWarningMessage}", buttons); mMessageBoxManager->eventButtonPressed += MyGUI::newDelegate(this, &CompanionWindow::onMessageBoxButtonClicked); + return false; } - else - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion); + return true; } void CompanionWindow::onMessageBoxButtonClicked(int button) diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index ec70146f2..fd66cfa80 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -18,7 +18,7 @@ namespace MWGui public: CompanionWindow(DragAndDrop* dragAndDrop, MessageBoxManager* manager); - virtual void exit(); + virtual bool exit(); virtual void resetReference(); diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index f3a06f245..697d90862 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -46,15 +46,16 @@ namespace MWGui center(); } - void ConfirmationDialog::exit() + bool ConfirmationDialog::exit() { - setVisible(false); - eventCancelClicked(); + return true; } void ConfirmationDialog::onCancelButtonClicked(MyGUI::Widget* _sender) { + setVisible(false); + exit(); } diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 745c7a1a5..259579376 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -11,7 +11,7 @@ namespace MWGui ConfirmationDialog(); void askForConfirmation(const std::string& message); void askForConfirmation(const std::string& message, const std::string& confirmMessage, const std::string& cancelMessage); - virtual void exit(); + virtual bool exit(); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 55a03bafd..182b6ef97 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -159,11 +159,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL); } - void Console::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Console); - } - void Console::setFont(const std::string &fntName) { mHistory->setFontName(fntName); diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 927fdd5fe..6257b5617 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -42,8 +42,6 @@ namespace MWGui virtual void onOpen(); virtual void onClose(); - virtual void exit(); - void setFont(const std::string &fntName); void onResChange(int width, int height); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6ea2e3e9a..85afc1aa3 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -198,17 +198,9 @@ namespace MWGui } } - void ContainerWindow::exit() - { - if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); - } - } - void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 2758f57c9..3ae73a01f 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -38,8 +38,6 @@ namespace MWGui virtual void resetReference(); - virtual void exit(); - private: DragAndDrop* mDragAndDrop; diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index 03cf1cab6..cf058caac 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -56,19 +56,9 @@ namespace MWGui mItemEdit->setValue(maxCount); } - void CountDialog::cancel() //Keeping this here as I don't know if anything else relies on it. - { - exit(); - } - - void CountDialog::exit() - { - setVisible(false); - } - void CountDialog::onCancelButtonClicked(MyGUI::Widget* _sender) { - cancel(); + setVisible(false); } void CountDialog::onOkButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index 7014b5fad..766612f68 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -15,8 +15,6 @@ namespace MWGui public: CountDialog(); void openCountDialog(const std::string& item, const std::string& message, const int maxCount); - void cancel(); - virtual void exit(); typedef MyGUI::delegates::CMultiDelegate2 EventHandle_WidgetInt; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index d2d97a437..48d291325 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -52,7 +52,7 @@ namespace MWGui void PersuasionDialog::onCancel(MyGUI::Widget *sender) { - exit(); + setVisible(false); } void PersuasionDialog::onPersuade(MyGUI::Widget *sender) @@ -88,11 +88,6 @@ namespace MWGui mGoldLabel->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); } - void PersuasionDialog::exit() - { - setVisible(false); - } - // -------------------------------------------------------------------------------------------------- Response::Response(const std::string &text, const std::string &title, bool needMargin) @@ -275,18 +270,18 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); } - void DialogueWindow::exit() + bool DialogueWindow::exit() { if ((!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) && !mGoodbye) { - // in choice, not allowed to escape, but give access to main menu to allow loading other saves - MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + return false; } else { MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); mTopicsList->scrollToTop(); + return true; } } @@ -311,7 +306,8 @@ namespace MWGui void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) { - exit(); + if (exit()) + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } void DialogueWindow::onSelectTopic(const std::string& topic, int id) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 682baef3c..12e2328f4 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -29,7 +29,6 @@ namespace MWGui PersuasionDialog(); virtual void onOpen(); - virtual void exit(); private: MyGUI::Button* mCancelButton; @@ -100,7 +99,7 @@ namespace MWGui public: DialogueWindow(); - virtual void exit(); + virtual bool exit(); // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 94e8b329d..88973bd46 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -100,11 +100,6 @@ namespace MWGui } } - void EnchantingDialog::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); - } - void EnchantingDialog::updateLabels() { std::stringstream enchantCost; @@ -194,7 +189,7 @@ namespace MWGui void EnchantingDialog::onCancelButtonClicked(MyGUI::Widget* sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Enchanting); } void EnchantingDialog::onSelectItem(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 41d6382cc..ace63ae5c 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -21,8 +21,6 @@ namespace MWGui virtual void onOpen(); - virtual void exit(); - void setSoulGem (const MWWorld::Ptr& gem); void setItem (const MWWorld::Ptr& item); diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index 095f392b7..effd11d55 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -29,9 +29,10 @@ namespace MWGui center(); } - void ItemSelectionDialog::exit() + bool ItemSelectionDialog::exit() { eventDialogCanceled(); + return true; } void ItemSelectionDialog::openContainer(const MWWorld::Ptr& container) diff --git a/apps/openmw/mwgui/itemselection.hpp b/apps/openmw/mwgui/itemselection.hpp index 50e15a3fe..07b6452a5 100644 --- a/apps/openmw/mwgui/itemselection.hpp +++ b/apps/openmw/mwgui/itemselection.hpp @@ -21,7 +21,7 @@ namespace MWGui public: ItemSelectionDialog(const std::string& label); - virtual void exit(); + virtual bool exit(); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Item; diff --git a/apps/openmw/mwgui/jailscreen.hpp b/apps/openmw/mwgui/jailscreen.hpp index 7a544126d..36d19b5a9 100644 --- a/apps/openmw/mwgui/jailscreen.hpp +++ b/apps/openmw/mwgui/jailscreen.hpp @@ -14,6 +14,8 @@ namespace MWGui void onFrame(float dt); + bool exit() { return false; } + private: int mDays; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 7bc66fab4..8c7ec6bfe 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1114,11 +1114,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); } - void EditNoteDialog::exit() - { - setVisible(false); - } - void EditNoteDialog::onCancelButtonClicked(MyGUI::Widget *sender) { setVisible(false); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index eae1cec7e..ed6e4874f 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -170,7 +170,6 @@ namespace MWGui EditNoteDialog(); virtual void onOpen(); - virtual void exit(); void showDeleteButton(bool show); bool getDeleteButtonShown(); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 785b5ee48..d3504ebc3 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -118,11 +118,6 @@ void MerchantRepair::onOpen() mList->setViewOffset(MyGUI::IntPoint(0, 0)); } -void MerchantRepair::exit() -{ - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_MerchantRepair); -} - void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) { MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -150,7 +145,7 @@ void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) void MerchantRepair::onOkButtonClick(MyGUI::Widget *sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_MerchantRepair); } } diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 76ccd28cc..4e4e7164f 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -14,8 +14,6 @@ public: virtual void onOpen(); - virtual void exit(); - void setPtr(const MWWorld::Ptr& actor); private: diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 19dd6fa03..6da7b0905 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -64,11 +64,6 @@ namespace MWGui } } - void QuickKeysMenu::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_QuickKeysMenu); - } - void QuickKeysMenu::clear() { mActivatedIndex = -1; @@ -449,11 +444,6 @@ namespace MWGui center(); } - void QuickKeysMenuAssign::exit() - { - setVisible(false); - } - void QuickKeysMenu::write(ESM::ESMWriter &writer) { writer.startRecord(ESM::REC_KEYS); @@ -585,9 +575,10 @@ namespace MWGui exit(); } - void MagicSelectionDialog::exit() + bool MagicSelectionDialog::exit() { mParent->onAssignMagicCancel(); + return true; } void MagicSelectionDialog::onOpen () diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index d07cdef3d..c99d482ee 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -22,8 +22,6 @@ namespace MWGui QuickKeysMenu(); ~QuickKeysMenu(); - virtual void exit(); - void onItemButtonClicked(MyGUI::Widget* sender); void onMagicButtonClicked(MyGUI::Widget* sender); void onUnassignButtonClicked(MyGUI::Widget* sender); @@ -77,7 +75,6 @@ namespace MWGui { public: QuickKeysMenuAssign(QuickKeysMenu* parent); - virtual void exit(); private: MyGUI::TextBox* mLabel; @@ -95,7 +92,7 @@ namespace MWGui MagicSelectionDialog(QuickKeysMenu* parent); virtual void onOpen(); - virtual void exit(); + virtual bool exit(); private: MyGUI::Button* mCancelButton; diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 911bce577..c9e31d42d 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -54,6 +54,8 @@ namespace MWGui virtual void onOpen(); virtual void onClose(); + bool exit() { return false; } + // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 54473746a..0398112ba 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -62,11 +62,6 @@ void Recharge::onOpen() mBox->resetScrollbars(); } -void Recharge::exit() -{ - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Recharge); -} - void Recharge::setPtr (const MWWorld::Ptr &item) { mGemIcon->setItem(item); @@ -107,7 +102,7 @@ void Recharge::updateView() void Recharge::onCancel(MyGUI::Widget *sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Recharge); } void Recharge::onSelectItem(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp index 93f86ab65..f4602ce30 100644 --- a/apps/openmw/mwgui/recharge.hpp +++ b/apps/openmw/mwgui/recharge.hpp @@ -24,8 +24,6 @@ public: virtual void onOpen(); - virtual void exit(); - void setPtr (const MWWorld::Ptr& gem); protected: diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 295b8254b..a461f7b3d 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -58,11 +58,6 @@ void Repair::onOpen() mRepairBox->resetScrollbars(); } -void Repair::exit() -{ - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Repair); -} - void Repair::setPtr(const MWWorld::Ptr &item) { MWBase::Environment::get().getWindowManager()->playSound("Item Repair Up"); @@ -145,7 +140,7 @@ void Repair::onItemCancel() void Repair::onCancel(MyGUI::Widget* /*sender*/) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Repair); } void Repair::onRepairItem(MyGUI::Widget* /*sender*/, const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index a2573d780..f31625095 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -21,8 +21,6 @@ public: virtual void onOpen(); - virtual void exit(); - void setPtr (const MWWorld::Ptr& item); protected: diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 34dd5a7d4..8e9ec0ec7 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -31,6 +31,8 @@ namespace MWGui ReviewDialog(); + bool exit() { return false; } + void setPlayerName(const std::string &name); void setRace(const std::string &raceId); void setClass(const ESM::Class& class_); diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 7a4c3a22e..e7c27b268 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -191,11 +191,6 @@ namespace MWGui } - void SaveGameDialog::exit() - { - setVisible(false); - } - void SaveGameDialog::setLoadOrSave(bool load) { mSaving = !load; @@ -217,7 +212,7 @@ namespace MWGui void SaveGameDialog::onCancelButtonClicked(MyGUI::Widget *sender) { - exit(); + setVisible(false); } void SaveGameDialog::onDeleteButtonClicked(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 2a49cf48a..39e3d310a 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -19,8 +19,6 @@ namespace MWGui virtual void onOpen(); - virtual void exit(); - void setLoadOrSave(bool load); private: diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index ccbd1d7c0..a92ef92ab 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -76,11 +76,6 @@ namespace MWGui setTakeButtonShow(showTakeButton); } - void ScrollWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); - } - void ScrollWindow::setTakeButtonShow(bool show) { mTakeButtonShow = show; @@ -95,7 +90,7 @@ namespace MWGui void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); } void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 5ae8e972a..596db06ad 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -18,7 +18,6 @@ namespace MWGui ScrollWindow (); void setPtr (const MWWorld::Ptr& scroll); - virtual void exit(); void setInventoryAllowed(bool allowed); protected: diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 4e8547d33..c239fc12f 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -258,7 +258,7 @@ namespace MWGui void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Settings); } void SettingsWindow::onResolutionSelected(MyGUI::ListBox* _sender, size_t index) @@ -559,11 +559,6 @@ namespace MWGui resetScrollbars(); } - void SettingsWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Settings); - } - void SettingsWindow::onWindowResize(MyGUI::Window *_sender) { layoutControlsBox(); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 447331574..4f8607fda 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -17,8 +17,6 @@ namespace MWGui virtual void onOpen(); - virtual void exit(); - void updateControlsBox(); protected: diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 592316274..aeb5cfbe5 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -31,11 +31,6 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onCancelButtonClicked); } - void SpellBuyingWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellBuying); - } - bool SpellBuyingWindow::sortSpells (const ESM::Spell* left, const ESM::Spell* right) { std::string leftName = Misc::StringUtils::lowerCase(left->mName); @@ -173,7 +168,7 @@ namespace MWGui void SpellBuyingWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_SpellBuying); } void SpellBuyingWindow::updateLabels() diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index b96896e4c..01cc6c2f9 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -28,8 +28,6 @@ namespace MWGui void setPtr(const MWWorld::Ptr& actor); void setPtr(const MWWorld::Ptr& actor, int startOffset); - virtual void exit(); - protected: MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index d5982a174..8d0639d25 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -102,13 +102,13 @@ namespace MWGui center(); } - void EditEffectDialog::exit() + bool EditEffectDialog::exit() { - setVisible(false); if(mEditing) eventEffectModified(mOldEffect); else eventEffectRemoved(mEffect); + return true; } void EditEffectDialog::newEffect (const ESM::MagicEffect *effect) @@ -275,6 +275,7 @@ namespace MWGui void EditEffectDialog::onCancelButtonClicked (MyGUI::Widget* sender) { + setVisible(false); exit(); } @@ -362,7 +363,7 @@ namespace MWGui void SpellCreationDialog::onCancelButtonClicked (MyGUI::Widget* sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_SpellCreation); } void SpellCreationDialog::onBuyButtonClicked (MyGUI::Widget* sender) @@ -420,11 +421,6 @@ namespace MWGui center(); } - void SpellCreationDialog::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_SpellCreation); - } - void SpellCreationDialog::onReferenceUnavailable () { MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue); diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 76038abb4..f7bb8a101 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -24,7 +24,7 @@ namespace MWGui EditEffectDialog(); virtual void onOpen(); - virtual void exit(); + virtual bool exit(); void setConstantEffect(bool constant); @@ -151,7 +151,6 @@ namespace MWGui SpellCreationDialog(); virtual void onOpen(); - virtual void exit(); void setPtr(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp index ccfa19c87..56c6632e1 100644 --- a/apps/openmw/mwgui/textinput.hpp +++ b/apps/openmw/mwgui/textinput.hpp @@ -22,6 +22,8 @@ namespace MWGui void setTextLabel(const std::string &label); virtual void onOpen(); + bool exit() { return false; } + /** Event : Dialog finished, OK button clicked.\n signature : void method()\n */ diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 60abf4ac7..2a6c61a16 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -171,11 +171,11 @@ namespace MWGui return mPtr.getClass().getServices(mPtr); } - void TradeWindow::exit() + bool TradeWindow::exit() { mTradeModel->abort(); MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel()->abort(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); + return true; } void TradeWindow::onItemSelected (int index) @@ -362,6 +362,7 @@ namespace MWGui void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); } void TradeWindow::onMaxSaleButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 984f5a394..55164b934 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -34,7 +34,7 @@ namespace MWGui int getMerchantServices(); - virtual void exit(); + virtual bool exit(); virtual void resetReference(); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 3079adb6d..ca6f2246e 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -60,11 +60,6 @@ namespace MWGui center(); } - void TrainingWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); - } - void TrainingWindow::setPtr (const MWWorld::Ptr& actor) { mPtr = actor; @@ -124,7 +119,7 @@ namespace MWGui void TrainingWindow::onCancelButtonClicked (MyGUI::Widget *sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Training); } void TrainingWindow::onTrainingSelected (MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index e52a889ef..d4785194a 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -16,8 +16,6 @@ namespace MWGui virtual void onOpen(); - virtual void exit(); - void setPtr(const MWWorld::Ptr& actor); void onFrame(float dt); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 4c4dc436c..02df6bd8e 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -45,11 +45,6 @@ namespace MWGui mSelect->getHeight()); } - void TravelWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); - } - void TravelWindow::addDestination(const std::string& name,ESM::Position pos,bool interior) { int price; @@ -194,7 +189,7 @@ namespace MWGui void TravelWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); } void TravelWindow::updateLabels() diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index 529d5ebe1..5ae466047 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -24,8 +24,6 @@ namespace MWGui public: TravelWindow(); - virtual void exit(); - void setPtr (const MWWorld::Ptr& actor); protected: diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 476d19bd6..b39b1a8ab 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -79,10 +79,9 @@ namespace MWGui mProgressBar.setVisible (false); } - void WaitDialog::exit() + bool WaitDialog::exit() { - if(!mProgressBar.isVisible()) //Only exit if not currently waiting - MWBase::Environment::get().getWindowManager()->popGuiMode(); + return (!mProgressBar.isVisible()); //Only exit if not currently waiting } void WaitDialog::onOpen() diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 829659d16..9bf8279be 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -29,7 +29,7 @@ namespace MWGui virtual void onOpen(); - virtual void exit(); + virtual bool exit(); void onFrame(float dt); diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 73574ce7c..e6817358f 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -34,7 +34,7 @@ namespace MWGui /// Notify that window has been hidden virtual void onClose () {} /// Gracefully exits the window - virtual void exit() {} + virtual bool exit() {return true;} /// Sets the visibility of the window virtual void setVisible(bool visible); /// Returns the visibility state of the window @@ -52,7 +52,7 @@ namespace MWGui WindowModal(const std::string& parLayout); virtual void onOpen(); virtual void onClose(); - virtual void exit() {} + virtual bool exit() {return true;} }; /// A window that cannot be the target of a drag&drop action. diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 70b95351b..31a072fd1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -769,89 +769,19 @@ namespace MWGui return; } - switch(mGuiModes.back()) { - case GM_QuickKeysMenu: - mQuickKeysMenu->exit(); - break; - case GM_MainMenu: - removeGuiMode(GM_MainMenu); //Simple way to remove it - break; - case GM_Settings: - mSettingsWindow->exit(); - break; - case GM_Console: - mConsole->exit(); - break; - case GM_Scroll: - mScrollWindow->exit(); - break; - case GM_Book: - mBookWindow->exit(); - break; - case GM_Alchemy: - mAlchemyWindow->exit(); - break; - case GM_Rest: - mWaitDialog->exit(); - break; - case GM_RestBed: - mWaitDialog->exit(); - break; - case GM_Name: - case GM_Race: - case GM_Class: - case GM_ClassPick: - case GM_ClassCreate: - case GM_Birth: - case GM_ClassGenerate: - case GM_Review: - break; - case GM_Inventory: - removeGuiMode(GM_Inventory); //Simple way to remove it - break; - case GM_Container: - mContainerWindow->exit(); - break; - case GM_Companion: - mCompanionWindow->exit(); - break; - case GM_Dialogue: - mDialogueWindow->exit(); - break; - case GM_Barter: - mTradeWindow->exit(); - break; - case GM_SpellBuying: - mSpellBuyingWindow->exit(); - break; - case GM_Travel: - mTravelWindow->exit(); - break; - case GM_SpellCreation: - mSpellCreationDialog->exit(); - break; - case GM_Recharge: - mRecharge->exit(); - break; - case GM_Enchanting: - mEnchantingDialog->exit(); - break; - case GM_Training: - mTrainingWindow->exit(); - break; - case GM_MerchantRepair: - mMerchantRepair->exit(); - break; - case GM_Repair: - mRepair->exit(); - break; - case GM_Journal: - removeGuiMode(GM_Journal); //Simple way to remove it - break; - default: - // Unsupported mode, switch back to game - break; + GuiModeState& state = mGuiModeStates[mGuiModes.back()]; + for (WindowBase* window : state.mWindows) + { + if (!window->exit()) + { + // unable to exit window, but give access to main menu + if (!MyGUI::InputManager::getInstance().isModalAny()) + pushGuiMode (MWGui::GM_MainMenu); + return; + } } + + popGuiMode(); } void WindowManager::interactiveMessageBox(const std::string &message, const std::vector &buttons, bool block) @@ -1267,10 +1197,11 @@ namespace MWGui if (!mGuiModes.empty()) { - mGuiModeStates[mGuiModes.back()].update(false); - if (!noSound) - playSound(mGuiModeStates[mGuiModes.back()].mCloseSound); + const GuiMode mode = mGuiModes.back(); mGuiModes.pop_back(); + mGuiModeStates[mode].update(false); + if (!noSound) + playSound(mGuiModeStates[mode].mCloseSound); } if (!mGuiModes.empty()) @@ -1849,10 +1780,11 @@ namespace MWGui void WindowManager::exitCurrentModal() { if (!mCurrentModals.empty()) - mCurrentModals.top()->exit(); - - if (mCurrentModals.empty()) - MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveKeyFocus); + { + if (!mCurrentModals.top()->exit()) + return; + mCurrentModals.top()->setVisible(false); + } } void WindowManager::addCurrentModal(WindowModal *input) From be19f51013ece60db26a860388778c1b5b6f103c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 12:55:28 +0200 Subject: [PATCH 149/505] Adjust some more windows to be keyboard friendlier --- apps/openmw/mwgui/birth.cpp | 1 + apps/openmw/mwgui/class.cpp | 1 + apps/openmw/mwgui/dialogue.cpp | 3 +++ apps/openmw/mwgui/race.cpp | 2 ++ apps/openmw/mwgui/spellcreationdialog.cpp | 1 + apps/openmw/mwgui/spellview.cpp | 1 + files/mygui/openmw_inventory_window.layout | 5 +++++ files/mygui/openmw_trade_window.layout | 5 +++++ 8 files changed, 19 insertions(+) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index b4a6b7d2f..92f29e3ef 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -69,6 +69,7 @@ namespace MWGui WindowModal::onOpen(); updateBirths(); updateSpells(); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mBirthList); } diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index c63d470d7..33daa0ad1 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -130,6 +130,7 @@ namespace MWGui WindowModal::onOpen (); updateClasses(); updateStats(); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mClassList); } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 48d291325..2effcc700 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -526,7 +526,10 @@ namespace MWGui } bool goodbyeEnabled = !MWBase::Environment::get().getDialogueManager()->isInChoice() || mGoodbye; + bool goodbyeWasEnabled = mGoodbyeButton->getEnabled(); mGoodbyeButton->setEnabled(goodbyeEnabled); + if (goodbyeEnabled && !goodbyeWasEnabled) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); bool topicsEnabled = !MWBase::Environment::get().getDialogueManager()->isInChoice() && !mGoodbye; mTopicsList->setEnabled(topicsEnabled); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 374a5d3d8..2b407ac93 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -163,6 +163,8 @@ namespace MWGui size_t initialPos = mHeadRotate->getScrollRange()/2+mHeadRotate->getScrollRange()/10; mHeadRotate->setScrollPosition(initialPos); onHeadRotate(mHeadRotate, initialPos); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mRaceList); } void RaceDialog::setRaceId(const std::string &raceId) diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 8d0639d25..d5dee1139 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -419,6 +419,7 @@ namespace MWGui void SpellCreationDialog::onOpen() { center(); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit); } void SpellCreationDialog::onReferenceUnavailable () diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index ebda8873c..4268b33a0 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -106,6 +106,7 @@ namespace MWGui Gui::SharedStateButton* t = mScrollView->createWidget(skin, MyGUI::IntCoord(0, 0, 0, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); + t->setNeedKeyFocus(true); t->setCaption(spell.mName); t->setTextAlign(MyGUI::Align::Left); adjustSpellWidget(spell, i, t); diff --git a/files/mygui/openmw_inventory_window.layout b/files/mygui/openmw_inventory_window.layout index bb707fa0d..6221799b5 100644 --- a/files/mygui/openmw_inventory_window.layout +++ b/files/mygui/openmw_inventory_window.layout @@ -32,18 +32,23 @@ + + + + + diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index f9f24581f..d1f31c475 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -9,18 +9,23 @@ + + + + + From ad4b91131f998253bf3fedca03f405c79dcc3d11 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 12:58:28 +0200 Subject: [PATCH 150/505] toggleGui renamed to toggleHud, remove unused variable --- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 13 ++++++------- apps/openmw/mwgui/windowmanagerimp.hpp | 5 ++--- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- apps/openmw/mwscript/guiextensions.cpp | 2 +- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 243ec3ccf..190768f26 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -229,7 +229,7 @@ namespace MWBase virtual void showCrosshair(bool show) = 0; virtual bool getSubtitlesEnabled() = 0; - virtual bool toggleGui() = 0; + virtual bool toggleHud() = 0; virtual void disallowMouse() = 0; virtual void allowMouse() = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 31a072fd1..2c58336da 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -190,7 +190,6 @@ namespace MWGui , mHitFaderEnabled(Settings::Manager::getBool ("hit fader", "GUI")) , mWerewolfOverlayEnabled(Settings::Manager::getBool ("werewolf overlay", "GUI")) , mHudEnabled(true) - , mGuiEnabled(true) , mCursorVisible(true) , mPlayerName() , mPlayerRaceId() @@ -450,7 +449,7 @@ namespace MWGui mInputBlocker = MyGUI::Gui::getInstance().createWidget("",0,0,w,h,MyGUI::Align::Stretch,"InputBlocker"); - mHud->setVisible(mHudEnabled); + mHud->setVisible(true); mCharGen = new CharacterCreation(mViewer->getSceneData()->asGroup(), mResourceSystem); @@ -598,8 +597,8 @@ namespace MWGui bool loading = (getMode() == GM_Loading || getMode() == GM_LoadingWallpaper); - mHud->setVisible(mHudEnabled && mGuiEnabled && !loading); - mToolTips->setVisible(mGuiEnabled && !loading); + mHud->setVisible(mHudEnabled && !loading); + mToolTips->setVisible(mHudEnabled && !loading); bool gameMode = !isGuiMode(); @@ -1477,11 +1476,11 @@ namespace MWGui return mSubtitlesEnabled; } - bool WindowManager::toggleGui() + bool WindowManager::toggleHud() { - mGuiEnabled = !mGuiEnabled; + mHudEnabled = !mHudEnabled; updateVisible(); - return mGuiEnabled; + return mHudEnabled; } bool WindowManager::getRestEnabled() diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 9fa921a4c..17707d2c3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -260,8 +260,8 @@ namespace MWGui virtual void showCrosshair(bool show); virtual bool getSubtitlesEnabled(); - /// Turn visibility of *all* GUI elements on or off (HUD and all windows, except the console) - virtual bool toggleGui(); + /// Turn visibility of HUD on or off + virtual bool toggleHud(); virtual void disallowMouse(); virtual void allowMouse(); @@ -468,7 +468,6 @@ namespace MWGui bool mHitFaderEnabled; bool mWerewolfOverlayEnabled; bool mHudEnabled; - bool mGuiEnabled; bool mCursorVisible; void setCursorVisible(bool visible); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index cf42db04b..cd17c5175 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -289,7 +289,7 @@ namespace MWInput showQuickKeysMenu(); break; case A_ToggleHUD: - MWBase::Environment::get().getWindowManager()->toggleGui(); + MWBase::Environment::get().getWindowManager()->toggleHud(); break; case A_ToggleDebug: MWBase::Environment::get().getWindowManager()->toggleDebugWindow(); diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 254da56d6..6f2c146b1 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -209,7 +209,7 @@ namespace MWScript public: virtual void execute(Interpreter::Runtime &runtime) { - bool state = MWBase::Environment::get().getWindowManager()->toggleGui(); + bool state = MWBase::Environment::get().getWindowManager()->toggleHud(); runtime.getContext().report(state ? "GUI -> On" : "GUI -> Off"); if (!state) From 35110fb2f8e1b43b6200a307c33d3bc50066a941 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 13:31:22 +0200 Subject: [PATCH 151/505] Remove unused and slightly broken custom button titles in ConfirmationDialog --- apps/openmw/mwgui/confirmationdialog.cpp | 8 -------- apps/openmw/mwgui/confirmationdialog.hpp | 1 - apps/openmw/mwgui/mapwindow.cpp | 2 +- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 697d90862..65b079d85 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -19,14 +19,6 @@ namespace MWGui mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ConfirmationDialog::onOkButtonClicked); } - void ConfirmationDialog::askForConfirmation(const std::string& message, const std::string& confirmMessage, const std::string& cancelMessage) - { - mCancelButton->setCaptionWithReplacing(cancelMessage); - mOkButton->setCaptionWithReplacing(confirmMessage); - - askForConfirmation(message); - } - void ConfirmationDialog::askForConfirmation(const std::string& message) { setVisible(true); diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 259579376..ab52549ec 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -10,7 +10,6 @@ namespace MWGui public: ConfirmationDialog(); void askForConfirmation(const std::string& message); - void askForConfirmation(const std::string& message, const std::string& confirmMessage, const std::string& cancelMessage); virtual bool exit(); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 8c7ec6bfe..d3c1ec292 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -701,7 +701,7 @@ namespace MWGui void MapWindow::onNoteEditDelete() { ConfirmationDialog* confirmation = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - confirmation->askForConfirmation("#{sDeleteNote}", "#{sYes}", "#{sNo}"); + confirmation->askForConfirmation("#{sDeleteNote}"); confirmation->eventCancelClicked.clear(); confirmation->eventOkClicked.clear(); confirmation->eventOkClicked += MyGUI::newDelegate(this, &MapWindow::onNoteEditDeleteConfirm); From 5f440a29bda58ce9f5afa80e02148155b4d1cc37 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 13:49:09 +0200 Subject: [PATCH 152/505] Remember key focus per GUI mode Among other things, this will remember the focused button in the container window, allowing quick looting of multiple containers. --- apps/openmw/mwgui/keyboardnavigation.cpp | 25 +++++++++++++++++++++ apps/openmw/mwgui/keyboardnavigation.hpp | 10 ++++++++- apps/openmw/mwgui/windowmanagerimp.cpp | 28 +++++++++++------------- apps/openmw/mwgui/windowmanagerimp.hpp | 6 +---- 4 files changed, 48 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index ba09ce369..c97532df5 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -28,10 +28,35 @@ void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& resu KeyboardNavigation::KeyboardNavigation() { + MyGUI::WidgetManager::getInstance().registerUnlinker(this); } KeyboardNavigation::~KeyboardNavigation() { + MyGUI::WidgetManager::getInstance().unregisterUnlinker(this); +} + +void KeyboardNavigation::saveFocus(int mode) +{ + mKeyFocus[mode] = MyGUI::InputManager::getInstance().getKeyFocusWidget(); +} + +void KeyboardNavigation::restoreFocus(int mode) +{ + std::map::const_iterator found = mKeyFocus.find(mode); + if (found != mKeyFocus.end()) + { + MyGUI::Widget* w = found->second; + if (w && w->getVisible() && w->getEnabled()) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(found->second); + } +} + +void KeyboardNavigation::_unlinkWidget(MyGUI::Widget *widget) +{ + for (std::pair& w : mKeyFocus) + if (w.second == widget) + w.second = nullptr; } bool isButtonFocus() diff --git a/apps/openmw/mwgui/keyboardnavigation.hpp b/apps/openmw/mwgui/keyboardnavigation.hpp index 86cc67962..fff36d862 100644 --- a/apps/openmw/mwgui/keyboardnavigation.hpp +++ b/apps/openmw/mwgui/keyboardnavigation.hpp @@ -2,11 +2,12 @@ #define OPENMW_MWGUI_KEYBOARDNAVIGATION_H #include +#include namespace MWGui { - class KeyboardNavigation + class KeyboardNavigation : public MyGUI::IUnlinkWidget { public: KeyboardNavigation(); @@ -15,11 +16,18 @@ namespace MWGui /// @return Was the key handled by this class? bool injectKeyPress(MyGUI::KeyCode key, unsigned int text); + void saveFocus(int mode); + void restoreFocus(int mode); + + void _unlinkWidget(MyGUI::Widget* widget); + private: bool switchFocus(int direction, bool wrap); /// Send button press event to focused button bool accept(); + + std::map mKeyFocus; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2c58336da..6306ef81a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -137,7 +137,6 @@ namespace MWGui , mWorkQueue(workQueue) , mViewer(viewer) , mConsoleOnlyScripts(consoleOnlyScripts) - , mSaveKeyFocus(NULL) , mCurrentModals() , mHud(NULL) , mMap(NULL) @@ -261,8 +260,6 @@ namespace MWGui MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); - MyGUI::WidgetManager::getInstance().registerUnlinker(this); - // Create all cursors in advance createCursors(); onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); @@ -505,8 +502,6 @@ namespace MWGui MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear(); MyGUI::ClipboardManager::getInstance().eventClipboardRequested.clear(); - MyGUI::WidgetManager::getInstance().unregisterUnlinker(this); - delete mConsole; delete mMessageBoxManager; delete mHud; @@ -1171,8 +1166,10 @@ namespace MWGui } if (!mGuiModes.empty()) + { + mKeyboardNavigation->saveFocus(mGuiModes.back()); mGuiModeStates[mGuiModes.back()].update(false); - + } mGuiModes.push_back(mode); mGuiModeStates[mode].update(true); @@ -1181,6 +1178,8 @@ namespace MWGui for (WindowBase* window : mGuiModeStates[mode].mWindows) window->setPtr(arg); + mKeyboardNavigation->restoreFocus(mode); + bool gameMode = !isGuiMode(); MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); @@ -1197,6 +1196,7 @@ namespace MWGui if (!mGuiModes.empty()) { const GuiMode mode = mGuiModes.back(); + mKeyboardNavigation->saveFocus(mode); mGuiModes.pop_back(); mGuiModeStates[mode].update(false); if (!noSound) @@ -1204,7 +1204,11 @@ namespace MWGui } if (!mGuiModes.empty()) - mGuiModeStates[mGuiModes.back()].update(true); + { + const GuiMode mode = mGuiModes.back(); + mGuiModeStates[mode].update(true); + mKeyboardNavigation->restoreFocus(mode); + } bool gameMode = !isGuiMode(); MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); @@ -1564,12 +1568,6 @@ namespace MWGui return mLoadingScreen; } - void WindowManager::_unlinkWidget(MyGUI::Widget *widget) - { - if (widget == mSaveKeyFocus) - mSaveKeyFocus = NULL; - } - bool WindowManager::getCursorVisible() { return mCursorVisible; @@ -1789,7 +1787,7 @@ namespace MWGui void WindowManager::addCurrentModal(WindowModal *input) { if (mCurrentModals.empty()) - mSaveKeyFocus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + mKeyboardNavigation->saveFocus(getMode()); mCurrentModals.push(input); } @@ -1803,7 +1801,7 @@ namespace MWGui mCurrentModals.pop(); if (mCurrentModals.empty()) - MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveKeyFocus); + mKeyboardNavigation->restoreFocus(getMode()); } void WindowManager::onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 17707d2c3..30d19e9f1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -124,7 +124,7 @@ namespace MWGui class JailScreen; class KeyboardNavigation; - class WindowManager : public MWBase::WindowManager, MyGUI::IUnlinkWidget + class WindowManager : public MWBase::WindowManager { public: typedef std::pair Faction; @@ -142,8 +142,6 @@ namespace MWGui virtual Loading::Listener* getLoadingScreen(); - void _unlinkWidget(MyGUI::Widget* widget); - /// @note This method will block until the video finishes playing /// (and will continually update the window while doing so) virtual void playVideo(const std::string& name, bool allowSkipping); @@ -406,8 +404,6 @@ namespace MWGui MWWorld::Ptr mSelectedEnchantItem; MWWorld::Ptr mSelectedWeapon; - MyGUI::Widget* mSaveKeyFocus; - std::stack mCurrentModals; // Markers placed manually by the player. Must be shared between both map views (the HUD map and the map window). From 65a707348caf471eed2d7f5211aff7de6f1575a3 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 14:27:10 +0200 Subject: [PATCH 153/505] Make Tab select the first widget if none is selected --- apps/openmw/mwgui/keyboardnavigation.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index c97532df5..8ce26e1d0 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" @@ -13,6 +14,9 @@ namespace MWGui /// Recursively get all child widgets that accept keyboard input void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& results) { + if (!parent->getVisible() || !parent->getEnabled()) + return; + MyGUI::EnumeratorWidgetPtr enumerator = parent->getEnumerator(); while (enumerator.next()) { @@ -101,6 +105,22 @@ bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text) bool KeyboardNavigation::switchFocus(int direction, bool wrap) { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + + if (!focus && (direction == D_Next || direction == D_Prev)) + { + // if nothing is selected, select the first widget + MyGUI::VectorWidgetPtr keyFocusList; + MyGUI::EnumeratorWidgetPtr enumerator = MyGUI::Gui::getInstance().getEnumerator(); + while (enumerator.next()) + getKeyFocusWidgets(enumerator.current(), keyFocusList); + + if (!keyFocusList.empty()) + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]); + return true; + } + } + if (!focus) return false; From 9ead331741fb4ccd1a2615047739e5c03b9030d6 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 14:42:25 +0200 Subject: [PATCH 154/505] Fix pinned windows showing in other GUI modes --- apps/openmw/mwgui/windowmanagerimp.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6306ef81a..8266e3e8d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -613,6 +613,8 @@ namespace MWGui setSpellVisibility((mAllowed & GW_Magic) && (!mSpellWindow->pinned() || (mForceHidden & GW_Magic))); setHMSVisibility((mAllowed & GW_Stats) && (!mStatsWindow->pinned() || (mForceHidden & GW_Stats))); + mInventoryWindow->setGuiMode(getMode()); + // If in game mode (or interactive messagebox), show the pinned windows if (mGuiModes.empty()) { @@ -622,11 +624,17 @@ namespace MWGui mSpellWindow->setVisible(mSpellWindow->pinned() && !(mForceHidden & GW_Magic) && (mAllowed & GW_Magic)); return; } + else if (getMode() != GM_Inventory) + { + mMap->setVisible(false); + mStatsWindow->setVisible(false); + mSpellWindow->setVisible(false); + mInventoryWindow->setVisible(getMode() == GM_Container || getMode() == GM_Barter); + } GuiMode mode = mGuiModes.back(); mInventoryWindow->setTrading(mode == GM_Barter); - mInventoryWindow->setGuiMode(mode); // For the inventory mode, compute the effective set of windows to show. // This is controlled both by what windows the From 32f9c8058a5e919ed60306e4ce986d839d8bd8bb Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 15:06:11 +0200 Subject: [PATCH 155/505] Remove redundant RestBed gui mode --- apps/openmw/mwgui/mode.hpp | 1 - apps/openmw/mwgui/waitdialog.cpp | 10 ++++++---- apps/openmw/mwgui/waitdialog.hpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 7 +------ apps/openmw/mwscript/guiextensions.cpp | 2 +- 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index db851e067..c452a1f5f 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -23,7 +23,6 @@ namespace MWGui GM_Dialogue, // NPC interaction GM_Barter, GM_Rest, - GM_RestBed, GM_SpellBuying, GM_Travel, GM_SpellCreation, diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index b39b1a8ab..afcf23be3 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -79,6 +79,11 @@ namespace MWGui mProgressBar.setVisible (false); } + void WaitDialog::setPtr(const MWWorld::Ptr &ptr) + { + setCanRest(!ptr.isEmpty() || MWBase::Environment::get().getWorld ()->canRest () == 0); + } + bool WaitDialog::exit() { return (!mProgressBar.isVisible()); //Only exit if not currently waiting @@ -100,8 +105,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->popGuiMode (); } - setCanRest(canRest == 0); - onHourSliderChangedPosition(mHourSlider, 0); mHourSlider->setScrollPosition (0); @@ -176,7 +179,7 @@ namespace MWGui void WaitDialog::onCancelButtonClicked(MyGUI::Widget* sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Rest); } void WaitDialog::onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position) @@ -264,7 +267,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2f); mProgressBar.setVisible (false); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Rest); - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_RestBed); mTimeAdvancer.stop(); } diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 9bf8279be..19c265204 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -27,14 +27,14 @@ namespace MWGui public: WaitDialog(); + void setPtr(const MWWorld::Ptr &ptr); + virtual void onOpen(); virtual bool exit(); void onFrame(float dt); - void bedActivated() { setCanRest(true); } - bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } void wakeUp(); void autosave(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8266e3e8d..bfd6fd20d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -398,7 +398,6 @@ namespace MWGui mWaitDialog = new WaitDialog(); mGuiModeStates[GM_Rest] = GuiModeState(mWaitDialog); - mGuiModeStates[GM_RestBed] = GuiModeState(mWaitDialog); mSpellCreationDialog = new SpellCreationDialog(); mGuiModeStates[GM_SpellCreation] = GuiModeState(mSpellCreationDialog); @@ -662,10 +661,6 @@ namespace MWGui case GM_Review: mCharGen->spawnDialog(mode); break; - case GM_RestBed: - // FIXME: use GM_Rest and push the 'bed' argument in some other way - mWaitDialog->bedActivated(); - break; default: break; } @@ -1700,7 +1695,7 @@ namespace MWGui { return !MyGUI::InputManager::getInstance().isModalAny() // TODO: remove this, once we have properly serialized the state of open windows - && (!isGuiMode() || (mGuiModes.size() == 1 && (getMode() == GM_MainMenu || getMode() == GM_Rest || getMode() == GM_RestBed))); + && (!isGuiMode() || (mGuiModes.size() == 1 && (getMode() == GM_MainMenu || getMode() == GM_Rest))); } void WindowManager::playVideo(const std::string &name, bool allowSkipping) diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 6f2c146b1..cea176ff6 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -57,7 +57,7 @@ namespace MWScript if (bed.isEmpty() || !MWBase::Environment::get().getMechanicsManager()->sleepInBed(MWMechanics::getPlayer(), bed)) - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_RestBed); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Rest, bed); } }; From ba7ae2663f26b7376ab79a878719a6e617021e00 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 21:45:52 +0200 Subject: [PATCH 156/505] Use a generic container to delete windows --- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/hud.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 92 ++++++++++++++------------ apps/openmw/mwgui/windowmanagerimp.hpp | 3 +- 4 files changed, 55 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index ba4d05d75..ed7273384 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -68,7 +68,7 @@ namespace MWGui HUD::HUD(CustomMarkerCollection &customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender) - : Layout("openmw_hud.layout") + : WindowBase("openmw_hud.layout") , LocalMapBase(customMarkers, localMapRender, Settings::Manager::getBool("local map hud fog of war", "Map")) , mHealth(NULL) , mMagicka(NULL) diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index e2ef52be0..4ea9d7ac3 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -16,7 +16,7 @@ namespace MWGui class SpellIcons; class ItemWidget; - class HUD : public Layout, public LocalMapBase + class HUD : public WindowBase, public LocalMapBase { public: HUD(CustomMarkerCollection& customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index bfd6fd20d..47557f369 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -146,7 +146,6 @@ namespace MWGui , mStatsWindow(NULL) , mMessageBoxManager(NULL) , mConsole(NULL) - , mJournal(NULL) , mDialogueWindow(NULL) , mContainerWindow(NULL) , mDragAndDrop(NULL) @@ -252,6 +251,7 @@ namespace MWGui mKeyboardNavigation.reset(new KeyboardNavigation()); mLoadingScreen = new LoadingScreen(mResourceSystem->getVFS(), mViewer); + mWindows.push_back(mLoadingScreen); //set up the hardware cursor manager mCursorManager = new SDLUtil::SDLCursorManager(); @@ -321,112 +321,153 @@ namespace MWGui mRecharge = new Recharge(); mGuiModeStates[GM_Recharge] = GuiModeState(mRecharge); + mWindows.push_back(mRecharge); mMenu = new MainMenu(w, h, mResourceSystem->getVFS(), mVersionDescription); mGuiModeStates[GM_MainMenu] = GuiModeState(mMenu); + mWindows.push_back(mMenu); mLocalMapRender = new MWRender::LocalMap(mViewer->getSceneData()->asGroup()); mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender, mWorkQueue); + mWindows.push_back(mMap); mMap->renderGlobalMap(); trackWindow(mMap, "map"); + mStatsWindow = new StatsWindow(mDragAndDrop); + mWindows.push_back(mStatsWindow); trackWindow(mStatsWindow, "stats"); + mInventoryWindow = new InventoryWindow(mDragAndDrop, mViewer->getSceneData()->asGroup(), mResourceSystem); + mWindows.push_back(mInventoryWindow); + mSpellWindow = new SpellWindow(mDragAndDrop); + mWindows.push_back(mSpellWindow); trackWindow(mSpellWindow, "spells"); mGuiModeStates[GM_Inventory] = GuiModeState({mMap, mInventoryWindow, mSpellWindow, mStatsWindow}); mGuiModeStates[GM_None] = GuiModeState({mMap, mInventoryWindow, mSpellWindow, mStatsWindow}); mTradeWindow = new TradeWindow(); + mWindows.push_back(mTradeWindow); trackWindow(mTradeWindow, "barter"); mGuiModeStates[GM_Barter] = GuiModeState({mInventoryWindow, mTradeWindow}); mConsole = new Console(w,h, mConsoleOnlyScripts); + mWindows.push_back(mConsole); trackWindow(mConsole, "console"); mGuiModeStates[GM_Console] = GuiModeState(mConsole); bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds"); - mJournal = JournalWindow::create(JournalViewModel::create (), questList); - mGuiModeStates[GM_Journal] = GuiModeState(mJournal); + JournalWindow* journal = JournalWindow::create(JournalViewModel::create (), questList); + mWindows.push_back(journal); + mGuiModeStates[GM_Journal] = GuiModeState(journal); mGuiModeStates[GM_Journal].mCloseSound = "book close"; mGuiModeStates[GM_Journal].mOpenSound = "book open"; mMessageBoxManager = new MessageBoxManager(mStore->get().find("fMessageTimePerChar")->getFloat()); + mSpellBuyingWindow = new SpellBuyingWindow(); + mWindows.push_back(mSpellBuyingWindow); mGuiModeStates[GM_SpellBuying] = GuiModeState(mSpellBuyingWindow); mTravelWindow = new TravelWindow(); + mWindows.push_back(mTravelWindow); mGuiModeStates[GM_Travel] = GuiModeState(mTravelWindow); mDialogueWindow = new DialogueWindow(); + mWindows.push_back(mDialogueWindow); trackWindow(mDialogueWindow, "dialogue"); mGuiModeStates[GM_Dialogue] = GuiModeState(mDialogueWindow); mContainerWindow = new ContainerWindow(mDragAndDrop); + mWindows.push_back(mContainerWindow); trackWindow(mContainerWindow, "container"); mGuiModeStates[GM_Container] = GuiModeState({mContainerWindow, mInventoryWindow}); mHud = new HUD(mCustomMarkers, mDragAndDrop, mLocalMapRender); + mWindows.push_back(mHud); + mToolTips = new ToolTips(); + mScrollWindow = new ScrollWindow(); + mWindows.push_back(mScrollWindow); mGuiModeStates[GM_Scroll] = GuiModeState(mScrollWindow); mGuiModeStates[GM_Scroll].mOpenSound = "scroll"; mGuiModeStates[GM_Scroll].mCloseSound = "scroll"; mBookWindow = new BookWindow(); + mWindows.push_back(mBookWindow); mGuiModeStates[GM_Book] = GuiModeState(mBookWindow); mGuiModeStates[GM_Book].mOpenSound = "book open"; mGuiModeStates[GM_Book].mCloseSound = "book close"; mCountDialog = new CountDialog(); + mWindows.push_back(mCountDialog); + mSettingsWindow = new SettingsWindow(); + mWindows.push_back(mSettingsWindow); mGuiModeStates[GM_Settings] = GuiModeState(mSettingsWindow); mConfirmationDialog = new ConfirmationDialog(); + mWindows.push_back(mConfirmationDialog); mAlchemyWindow = new AlchemyWindow(); + mWindows.push_back(mAlchemyWindow); trackWindow(mAlchemyWindow, "alchemy"); mGuiModeStates[GM_Alchemy] = GuiModeState(mAlchemyWindow); mQuickKeysMenu = new QuickKeysMenu(); + mWindows.push_back(mQuickKeysMenu); mGuiModeStates[GM_QuickKeysMenu] = GuiModeState(mQuickKeysMenu); mLevelupDialog = new LevelupDialog(); + mWindows.push_back(mLevelupDialog); mGuiModeStates[GM_Levelup] = GuiModeState(mLevelupDialog); mWaitDialog = new WaitDialog(); + mWindows.push_back(mWaitDialog); mGuiModeStates[GM_Rest] = GuiModeState(mWaitDialog); mSpellCreationDialog = new SpellCreationDialog(); + mWindows.push_back(mSpellCreationDialog); mGuiModeStates[GM_SpellCreation] = GuiModeState(mSpellCreationDialog); mEnchantingDialog = new EnchantingDialog(); + mWindows.push_back(mEnchantingDialog); mGuiModeStates[GM_Enchanting] = GuiModeState(mEnchantingDialog); mTrainingWindow = new TrainingWindow(); + mWindows.push_back(mTrainingWindow); mGuiModeStates[GM_Training] = GuiModeState(mTrainingWindow); mMerchantRepair = new MerchantRepair(); + mWindows.push_back(mMerchantRepair); mGuiModeStates[GM_MerchantRepair] = GuiModeState(mMerchantRepair); mRepair = new Repair(); + mWindows.push_back(mRepair); mGuiModeStates[GM_Repair] = GuiModeState(mRepair); mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); + mWindows.push_back(mCompanionWindow); trackWindow(mCompanionWindow, "companion"); mGuiModeStates[GM_Companion] = GuiModeState({mInventoryWindow, mCompanionWindow}); mJailScreen = new JailScreen(); + mWindows.push_back(mJailScreen); mGuiModeStates[GM_Jail] = GuiModeState(mJailScreen); std::string werewolfFaderTex = "textures\\werewolfoverlay.dds"; if (mResourceSystem->getVFS()->exists(werewolfFaderTex)) + { mWerewolfFader = new ScreenFader(werewolfFaderTex); + mWindows.push_back(mWerewolfFader); + } mBlindnessFader = new ScreenFader("black"); + mWindows.push_back(mBlindnessFader); // fall back to player_hit_01.dds if bm_player_hit_01.dds is not available std::string hitFaderTexture = "textures\\bm_player_hit_01.dds"; @@ -438,10 +479,13 @@ namespace MWGui hitFaderCoord = MyGUI::FloatCoord(0.2, 0.25, 0.6, 0.5); } mHitFader = new ScreenFader(hitFaderTexture, hitFaderLayout, hitFaderCoord); + mWindows.push_back(mHitFader); mScreenFader = new ScreenFader("black"); + mWindows.push_back(mScreenFader); mDebugWindow = new DebugWindow(); + mWindows.push_back(mDebugWindow); mInputBlocker = MyGUI::Gui::getInstance().createWidget("",0,0,w,h,MyGUI::Align::Stretch,"InputBlocker"); @@ -501,49 +545,15 @@ namespace MWGui MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear(); MyGUI::ClipboardManager::getInstance().eventClipboardRequested.clear(); - delete mConsole; + for (WindowBase* window : mWindows) + delete window; + mWindows.clear(); + delete mMessageBoxManager; - delete mHud; - delete mMap; delete mLocalMapRender; - delete mMenu; - delete mStatsWindow; - delete mJournal; - delete mDialogueWindow; - delete mContainerWindow; - delete mInventoryWindow; - delete mToolTips; delete mCharGen; delete mDragAndDrop; - delete mBookWindow; - delete mScrollWindow; - delete mTradeWindow; - delete mSpellBuyingWindow; - delete mTravelWindow; - delete mSettingsWindow; - delete mConfirmationDialog; - delete mAlchemyWindow; - delete mSpellWindow; - delete mLoadingScreen; - delete mLevelupDialog; - delete mWaitDialog; - delete mSpellCreationDialog; - delete mEnchantingDialog; - delete mTrainingWindow; - delete mCountDialog; - delete mQuickKeysMenu; - delete mMerchantRepair; - delete mRepair; delete mSoulgemDialog; - delete mRecharge; - delete mCompanionWindow; - delete mHitFader; - delete mWerewolfFader; - delete mScreenFader; - delete mBlindnessFader; - delete mDebugWindow; - delete mJailScreen; - delete mCursorManager; cleanupGarbage(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 30d19e9f1..90fcf8979 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -417,7 +417,6 @@ namespace MWGui StatsWindow *mStatsWindow; MessageBoxManager *mMessageBoxManager; Console *mConsole; - JournalWindow* mJournal; DialogueWindow *mDialogueWindow; ContainerWindow *mContainerWindow; DragAndDrop* mDragAndDrop; @@ -453,6 +452,8 @@ namespace MWGui DebugWindow* mDebugWindow; JailScreen* mJailScreen; + std::vector mWindows; + Translation::Storage& mTranslationDataStorage; CharacterCreation* mCharGen; From 2b03bc0c5695623ffc5693fae30b875b34ee8f07 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 22:00:15 +0200 Subject: [PATCH 157/505] Call WindowBase::onFrame() for every active window --- apps/openmw/mwgui/companionwindow.cpp | 3 +- apps/openmw/mwgui/companionwindow.hpp | 2 +- apps/openmw/mwgui/console.hpp | 2 ++ apps/openmw/mwgui/container.hpp | 2 ++ apps/openmw/mwgui/dialogue.cpp | 5 ++-- apps/openmw/mwgui/dialogue.hpp | 2 +- apps/openmw/mwgui/enchantingdialog.hpp | 2 ++ apps/openmw/mwgui/inventorywindow.cpp | 5 +--- apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/mainmenu.cpp | 2 +- apps/openmw/mwgui/mainmenu.hpp | 2 +- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 ++ apps/openmw/mwgui/spellcreationdialog.hpp | 2 ++ apps/openmw/mwgui/spellwindow.cpp | 15 ++++------ apps/openmw/mwgui/statswindow.cpp | 3 -- apps/openmw/mwgui/tradewindow.cpp | 5 ++++ apps/openmw/mwgui/tradewindow.hpp | 2 ++ apps/openmw/mwgui/trainingwindow.cpp | 1 + apps/openmw/mwgui/windowbase.hpp | 3 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 35 ++++++----------------- 20 files changed, 47 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index c4e50c8c2..90ef32ced 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -116,8 +116,9 @@ void CompanionWindow::setPtr(const MWWorld::Ptr& npc) setTitle(npc.getClass().getName(npc)); } -void CompanionWindow::onFrame() +void CompanionWindow::onFrame(float dt) { + checkReferenceAvailable(); updateEncumbranceBar(); } diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index fd66cfa80..23af6bc96 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -23,7 +23,7 @@ namespace MWGui virtual void resetReference(); void setPtr(const MWWorld::Ptr& npc); - void onFrame (); + void onFrame (float dt); private: ItemView* mItemView; diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 6257b5617..a68f1cb43 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -42,6 +42,8 @@ namespace MWGui virtual void onOpen(); virtual void onClose(); + void onFrame(float dt) { checkReferenceAvailable(); } + void setFont(const std::string &fntName); void onResChange(int width, int height); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 3ae73a01f..27b0e408b 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -36,6 +36,8 @@ namespace MWGui void setPtr(const MWWorld::Ptr& container); virtual void onClose(); + void onFrame(float dt) { checkReferenceAvailable(); } + virtual void resetReference(); private: diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 2effcc700..ec6dcb2cb 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -630,9 +630,10 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } - void DialogueWindow::onFrame() + void DialogueWindow::onFrame(float dt) { - if(mMainWidget->getVisible() && mPtr.getTypeName() == typeid(ESM::NPC).name()) + checkReferenceAvailable(); + if(mPtr.getTypeName() == typeid(ESM::NPC).name()) { int disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr); mDispositionBar->setProgressRange(100); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 12e2328f4..4ac5bd9d0 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -117,7 +117,7 @@ namespace MWGui void clearChoices(); void goodbye(); - void onFrame(); + void onFrame(float dt); // make sure to call these before setKeywords() void setServices(int services) { mServices = services; } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index ace63ae5c..335e5fda9 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -21,6 +21,8 @@ namespace MWGui virtual void onOpen(); + void onFrame(float dt) { checkReferenceAvailable(); } + void setSoulGem (const MWWorld::Ptr& gem); void setItem (const MWWorld::Ptr& item); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index dcfb075db..735bf3682 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -589,11 +589,8 @@ namespace MWGui mEncumbranceBar->setValue(static_cast(encumbrance), static_cast(capacity)); } - void InventoryWindow::onFrame() + void InventoryWindow::onFrame(float dt) { - if (!mMainWidget->getVisible()) - return; - updateEncumbranceBar(); } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index fb5be3493..5576b52ed 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -40,7 +40,7 @@ namespace MWGui /// start trading, disables item drag&drop void setTrading(bool trading); - void onFrame(); + void onFrame(float dt); void pickUpObject (MWWorld::Ptr object); diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 657f0e4ec..4e629403a 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -197,7 +197,7 @@ namespace MWGui } } - void MainMenu::update(float dt) + void MainMenu::onFrame(float dt) { if (mVideo) { diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index 612f7d1bd..1beb9ee16 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -36,7 +36,7 @@ namespace MWGui virtual void setVisible (bool visible); - void update(float dt); + void onFrame(float dt); private: const VFS::Manager* mVFS; diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 01cc6c2f9..6eb52366b 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -28,6 +28,8 @@ namespace MWGui void setPtr(const MWWorld::Ptr& actor); void setPtr(const MWWorld::Ptr& actor, int startOffset); + void onFrame(float dt) { checkReferenceAvailable(); } + protected: MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index f7bb8a101..7bacda385 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -152,6 +152,8 @@ namespace MWGui virtual void onOpen(); + void onFrame(float dt) { checkReferenceAvailable(); } + void setPtr(const MWWorld::Ptr& actor); protected: diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 9261912b4..601204aa1 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -68,16 +68,13 @@ namespace MWGui } void SpellWindow::onFrame(float dt) - { - if (mMainWidget->getVisible()) + { + NoDrop::onFrame(dt); + mUpdateTimer += dt; + if (0.5f < mUpdateTimer) { - NoDrop::onFrame(dt); - mUpdateTimer += dt; - if (0.5f < mUpdateTimer) - { - mUpdateTimer = 0; - mSpellView->incrementalUpdate(); - } + mUpdateTimer = 0; + mSpellView->incrementalUpdate(); } } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 17e51e338..bf505b00f 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -297,9 +297,6 @@ namespace MWGui void StatsWindow::onFrame (float dt) { - if (!mMainWidget->getVisible()) - return; - NoDrop::onFrame(dt); MWWorld::Ptr player = MWMechanics::getPlayer(); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 2a6c61a16..feccfd942 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -142,6 +142,11 @@ namespace MWGui onFilterChanged(mFilterAll); } + void TradeWindow::onFrame(float dt) + { + checkReferenceAvailable(); + } + void TradeWindow::onFilterChanged(MyGUI::Widget* _sender) { if (_sender == mFilterAll) diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 55164b934..69fdc135b 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -29,6 +29,8 @@ namespace MWGui void setPtr(const MWWorld::Ptr& actor); + void onFrame(float dt); + void borrowItem (int index, size_t count); void returnItem (int index, size_t count); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index ca6f2246e..c1f7f8ac1 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -195,6 +195,7 @@ namespace MWGui void TrainingWindow::onFrame(float dt) { + checkReferenceAvailable(); mTimeAdvancer.onFrame(dt); if (mFadeTimeRemaining <= 0) diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index e6817358f..6889ad9ec 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -29,6 +29,9 @@ namespace MWGui /// Open this object in the GUI, for windows that support it virtual void setPtr(const MWWorld::Ptr& ptr) {} + /// Called every frame if the window is in an active GUI mode + virtual void onFrame(float duration) {} + /// Notify that window has been made visible virtual void onOpen() {} /// Notify that window has been hidden diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 47557f369..9635f804e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -890,12 +890,19 @@ namespace MWGui void WindowManager::onFrame (float frameDuration) { + if (!mGuiModes.empty()) + { + GuiModeState& state = mGuiModeStates[mGuiModes.back()]; + for (WindowBase* window : state.mWindows) + window->onFrame(frameDuration); + } + if (!mCurrentModals.empty()) + mCurrentModals.top()->onFrame(frameDuration); + mMessageBoxManager->onFrame(frameDuration); mToolTips->onFrame(frameDuration); - mMenu->update(frameDuration); - if (mLocalMapRender) mLocalMapRender->cleanupCameras(); @@ -909,34 +916,10 @@ namespace MWGui mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); } - mDialogueWindow->onFrame(); - - mInventoryWindow->onFrame(); - updateMap(); - mStatsWindow->onFrame(frameDuration); - mMap->onFrame(frameDuration); - mSpellWindow->onFrame(frameDuration); - - mWaitDialog->onFrame(frameDuration); - mHud->onFrame(frameDuration); - mTrainingWindow->onFrame (frameDuration); - - mTrainingWindow->checkReferenceAvailable(); - mDialogueWindow->checkReferenceAvailable(); - mTradeWindow->checkReferenceAvailable(); - mSpellBuyingWindow->checkReferenceAvailable(); - mSpellCreationDialog->checkReferenceAvailable(); - mEnchantingDialog->checkReferenceAvailable(); - mContainerWindow->checkReferenceAvailable(); - mCompanionWindow->checkReferenceAvailable(); - mConsole->checkReferenceAvailable(); - mCompanionWindow->onFrame(); - mJailScreen->onFrame(frameDuration); - if (mWerewolfFader) mWerewolfFader->update(frameDuration); mBlindnessFader->update(frameDuration); From c6c01870ec299c0f99065d474107bf253a39ec78 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 22:07:30 +0200 Subject: [PATCH 158/505] Call onResChange for every window --- apps/openmw/mwgui/alchemywindow.hpp | 2 ++ apps/openmw/mwgui/bookwindow.hpp | 2 ++ apps/openmw/mwgui/quickkeysmenu.hpp | 2 ++ apps/openmw/mwgui/scrollwindow.hpp | 2 ++ apps/openmw/mwgui/settingswindow.hpp | 2 ++ apps/openmw/mwgui/spellbuyingwindow.hpp | 2 ++ apps/openmw/mwgui/windowbase.hpp | 4 ++++ apps/openmw/mwgui/windowmanagerimp.cpp | 12 ++++-------- 8 files changed, 20 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 8dffaaad1..a27d9c749 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -26,6 +26,8 @@ namespace MWGui virtual void onOpen(); + void onResChange(int, int) { center(); } + private: std::string mSuggestedPotionName; diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index 4f7224ea8..b20498feb 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -17,6 +17,8 @@ namespace MWGui void setPtr(const MWWorld::Ptr& book); void setInventoryAllowed(bool allowed); + void onResChange(int, int) { center(); } + protected: void onNextPageButtonClicked (MyGUI::Widget* sender); void onPrevPageButtonClicked (MyGUI::Widget* sender); diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index c99d482ee..0070aa55b 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -22,6 +22,8 @@ namespace MWGui QuickKeysMenu(); ~QuickKeysMenu(); + void onResChange(int, int) { center(); } + void onItemButtonClicked(MyGUI::Widget* sender); void onMagicButtonClicked(MyGUI::Widget* sender); void onUnassignButtonClicked(MyGUI::Widget* sender); diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 596db06ad..35016e5dc 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -20,6 +20,8 @@ namespace MWGui void setPtr (const MWWorld::Ptr& scroll); void setInventoryAllowed(bool allowed); + void onResChange(int, int) { center(); } + protected: void onCloseButtonClicked (MyGUI::Widget* _sender); void onTakeButtonClicked (MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 4f8607fda..c6e48819c 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -19,6 +19,8 @@ namespace MWGui void updateControlsBox(); + void onResChange(int, int) { center(); } + protected: MyGUI::TabControl* mSettingsTab; MyGUI::Button* mOkButton; diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 6eb52366b..36f7499a0 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -30,6 +30,8 @@ namespace MWGui void onFrame(float dt) { checkReferenceAvailable(); } + void onResChange(int, int) { center(); } + protected: MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 6889ad9ec..c9f9555b0 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -42,7 +42,11 @@ namespace MWGui virtual void setVisible(bool visible); /// Returns the visibility state of the window bool isVisible(); + void center(); + + /// Called when GUI viewport changes size + virtual void onResChange(int width, int height) {} }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9635f804e..3e55060f8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1128,14 +1128,10 @@ namespace MWGui it->first->setSize(size); } - mConsole->onResChange(x, y); - mMenu->onResChange(x, y); - mSettingsWindow->center(); - mAlchemyWindow->center(); - mScrollWindow->center(); - mBookWindow->center(); - mQuickKeysMenu->center(); - mSpellBuyingWindow->center(); + for (WindowBase* window : mWindows) + window->onResChange(x, y); + + // TODO: check if any windows are now off-screen and move them back if so } void WindowManager::onCursorChange(const std::string &name) From e7d2a8a4dc6d205a08ed2c7f372f49d56be6bf15 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 22:16:56 +0200 Subject: [PATCH 159/505] Call clear() for every window --- apps/openmw/mwgui/companionwindow.hpp | 1 + apps/openmw/mwgui/console.hpp | 1 + apps/openmw/mwgui/container.hpp | 1 + apps/openmw/mwgui/dialogue.hpp | 1 + apps/openmw/mwgui/enchantingdialog.hpp | 1 + apps/openmw/mwgui/hud.hpp | 2 ++ apps/openmw/mwgui/spellbuyingwindow.hpp | 1 + apps/openmw/mwgui/spellcreationdialog.hpp | 1 + apps/openmw/mwgui/tradewindow.hpp | 1 + apps/openmw/mwgui/trainingwindow.hpp | 2 ++ apps/openmw/mwgui/waitdialog.cpp | 5 +++++ apps/openmw/mwgui/waitdialog.hpp | 1 + apps/openmw/mwgui/windowbase.hpp | 3 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 26 ++++++----------------- 14 files changed, 27 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 23af6bc96..891106853 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -24,6 +24,7 @@ namespace MWGui void setPtr(const MWWorld::Ptr& npc); void onFrame (float dt); + void clear() { resetReference(); } private: ItemView* mItemView; diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index a68f1cb43..f243b8387 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -47,6 +47,7 @@ namespace MWGui void setFont(const std::string &fntName); void onResChange(int width, int height); + void clear() { resetReference(); } // Print a message to the console, in specified color. void print(const std::string &msg, const std::string& color = "#FFFFFF"); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 27b0e408b..a53d4f782 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -35,6 +35,7 @@ namespace MWGui void setPtr(const MWWorld::Ptr& container); virtual void onClose(); + void clear() { resetReference(); } void onFrame(float dt) { checkReferenceAvailable(); } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 4ac5bd9d0..224ecba66 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -118,6 +118,7 @@ namespace MWGui void goodbye(); void onFrame(float dt); + void clear() { resetReference(); } // make sure to call these before setKeywords() void setServices(int services) { mServices = services; } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 335e5fda9..39614ebd1 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -22,6 +22,7 @@ namespace MWGui virtual void onOpen(); void onFrame(float dt) { checkReferenceAvailable(); } + void clear() { resetReference(); } void setSoulGem (const MWWorld::Ptr& gem); void setItem (const MWWorld::Ptr& item); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 4ea9d7ac3..3dae2157f 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -60,6 +60,8 @@ namespace MWGui void setEnemy(const MWWorld::Ptr& enemy); void resetEnemy(); + void clear() { resetEnemy(); } + private: MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth, *mDrowning; MyGUI::Widget* mHealthFrame; diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 36f7499a0..649aab3f2 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -29,6 +29,7 @@ namespace MWGui void setPtr(const MWWorld::Ptr& actor, int startOffset); void onFrame(float dt) { checkReferenceAvailable(); } + void clear() { resetReference(); } void onResChange(int, int) { center(); } diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 7bacda385..855016666 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -151,6 +151,7 @@ namespace MWGui SpellCreationDialog(); virtual void onOpen(); + void clear() { resetReference(); } void onFrame(float dt) { checkReferenceAvailable(); } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 69fdc135b..00f38024d 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -30,6 +30,7 @@ namespace MWGui void setPtr(const MWWorld::Ptr& actor); void onFrame(float dt); + void clear() { resetReference(); } void borrowItem (int index, size_t count); void returnItem (int index, size_t count); diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index d4785194a..127c85f6a 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -20,6 +20,8 @@ namespace MWGui void onFrame(float dt); + void clear() { resetReference(); } + protected: virtual void onReferenceUnavailable (); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index afcf23be3..cd1d29854 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -262,6 +262,11 @@ namespace MWGui } } + void WaitDialog::clear() + { + mProgressBar.setVisible(false); + } + void WaitDialog::stopWaiting () { MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2f); diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 19c265204..6bd90473f 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -34,6 +34,7 @@ namespace MWGui virtual bool exit(); void onFrame(float dt); + void clear(); bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } void wakeUp(); diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index c9f9555b0..f183c97fe 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -45,6 +45,9 @@ namespace MWGui void center(); + /// Clear any state specific to the running game + virtual void clear() {} + /// Called when GUI viewport changes size virtual void onResChange(int width, int height) {} }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 3e55060f8..b512d8fc8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -514,10 +514,6 @@ namespace MWGui void WindowManager::setNewGame(bool newgame) { - // This method will always be called after loading a savegame or starting a new game - // Reset enemy, it could be a dangling pointer from a previous game - mHud->resetEnemy(); - if (newgame) { disallowAll(); @@ -1596,36 +1592,26 @@ namespace MWGui void WindowManager::clear() { + for (WindowBase* window : mWindows) + window->clear(); + if (mLocalMapRender) mLocalMapRender->clear(); - mMap->clear(); - mQuickKeysMenu->clear(); mMessageBoxManager->clear(); - mTrainingWindow->resetReference(); - mDialogueWindow->resetReference(); - mTradeWindow->resetReference(); - mSpellBuyingWindow->resetReference(); - mSpellCreationDialog->resetReference(); - mEnchantingDialog->resetReference(); - mContainerWindow->resetReference(); - mCompanionWindow->resetReference(); - mConsole->resetReference(); - mToolTips->setFocusObject(MWWorld::ConstPtr()); - mInventoryWindow->clear(); - mSelectedSpell.clear(); - mCustomMarkers.clear(); mForceHidden = GW_None; setWerewolfOverlay(false); - mGuiModes.clear(); + while (!mGuiModes.empty()) + popGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(false); updateVisible(); } From f67dbc8aa034adb3ac9740803a943cf7bb732d60 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 22:24:22 +0200 Subject: [PATCH 160/505] Remove redundant update function --- apps/openmw/engine.cpp | 5 ----- apps/openmw/mwbase/windowmanager.hpp | 7 ------ apps/openmw/mwgui/hud.cpp | 31 ++++++++++++-------------- apps/openmw/mwgui/hud.hpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 13 ++++------- apps/openmw/mwgui/windowmanagerimp.hpp | 7 ------ 6 files changed, 18 insertions(+), 47 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index f5ec86cc3..3e5ab7ce6 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -161,11 +161,6 @@ void OMW::Engine::frame(float frametime) // update GUI mEnvironment.getWindowManager()->onFrame(frametime); - if (mEnvironment.getStateManager()->getState()!= - MWBase::StateManager::State_NoGame) - { - mEnvironment.getWindowManager()->update(); - } unsigned int frameNumber = mViewer->getFrameStamp()->getFrameNumber(); osg::Stats* stats = mViewer->getViewerStats(); diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 190768f26..43d99b6b3 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -102,13 +102,6 @@ namespace MWBase virtual ~WindowManager() {} - /** - * Should be called each frame to update windows/gui elements. - * This could mean updating sizes of gui elements or opening - * new dialogs. - */ - virtual void update() = 0; - /// @note This method will block until the video finishes playing /// (and will continually update the window while doing so) virtual void playVideo(const std::string& name, bool allowSkipping) = 0; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index ed7273384..87c1b2f3c 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -371,6 +371,20 @@ namespace MWGui if (mIsDrowning) mDrowningFlashTheta += dt * osg::PI*2; + + mSpellIcons->updateWidgets(mEffectBox, true); + + if (mEnemyActorId != -1 && mEnemyHealth->getVisible()) + { + updateEnemyHealthBar(); + } + + if (mIsDrowning) + { + float intensity = (cos(mDrowningFlashTheta) + 2.0f) / 3.0f; + + mDrowningFlash->setAlpha(intensity); + } } void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent) @@ -602,23 +616,6 @@ namespace MWGui } - void HUD::update() - { - mSpellIcons->updateWidgets(mEffectBox, true); - - if (mEnemyActorId != -1 && mEnemyHealth->getVisible()) - { - updateEnemyHealthBar(); - } - - if (mIsDrowning) - { - float intensity = (cos(mDrowningFlashTheta) + 2.0f) / 3.0f; - - mDrowningFlash->setAlpha(intensity); - } - } - void HUD::setEnemy(const MWWorld::Ptr &enemy) { mEnemyActorId = enemy.getClass().getCreatureStats(enemy).getActorId(); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 3dae2157f..fc335d1e7 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -55,8 +55,6 @@ namespace MWGui MyGUI::Widget* getEffectBox() { return mEffectBox; } - void update(); - void setEnemy(const MWWorld::Ptr& enemy); void resetEnemy(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index b512d8fc8..c9dec0287 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -581,15 +581,6 @@ namespace MWGui } } - void WindowManager::update() - { - cleanupGarbage(); - - mHud->update(); - - updateActivatedQuickKey (); - } - void WindowManager::updateVisible() { if (!mMap) @@ -926,6 +917,10 @@ namespace MWGui if (mCharGen) mCharGen->onFrame(frameDuration); + + updateActivatedQuickKey (); + + cleanupGarbage(); } void WindowManager::changeCell(const MWWorld::CellStore* cell) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 90fcf8979..773eed4fc 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -146,13 +146,6 @@ namespace MWGui /// (and will continually update the window while doing so) virtual void playVideo(const std::string& name, bool allowSkipping); - /** - * Should be called each frame to update windows/gui elements. - * This could mean updating sizes of gui elements or opening - * new dialogs. - */ - virtual void update(); - /// Warning: do not use MyGUI::InputManager::setKeyFocusWidget directly. Instead use this. virtual void setKeyFocusWidget (MyGUI::Widget* widget); From d10985e4814baea6a331a1d94698b949788e039e Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 22:42:55 +0200 Subject: [PATCH 161/505] Remove unneeded window pointers --- apps/openmw/mwgui/windowmanagerimp.cpp | 97 +++++++++++--------------- apps/openmw/mwgui/windowmanagerimp.hpp | 13 ---- 2 files changed, 42 insertions(+), 68 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c9dec0287..906151ab1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -141,37 +141,24 @@ namespace MWGui , mHud(NULL) , mMap(NULL) , mLocalMapRender(NULL) - , mMenu(NULL) , mToolTips(NULL) , mStatsWindow(NULL) , mMessageBoxManager(NULL) , mConsole(NULL) , mDialogueWindow(NULL) - , mContainerWindow(NULL) , mDragAndDrop(NULL) , mInventoryWindow(NULL) , mScrollWindow(NULL) , mBookWindow(NULL) , mCountDialog(NULL) , mTradeWindow(NULL) - , mSpellBuyingWindow(NULL) - , mTravelWindow(NULL) , mSettingsWindow(NULL) , mConfirmationDialog(NULL) - , mAlchemyWindow(NULL) , mSpellWindow(NULL) , mQuickKeysMenu(NULL) , mLoadingScreen(NULL) - , mLevelupDialog(NULL) , mWaitDialog(NULL) - , mSpellCreationDialog(NULL) - , mEnchantingDialog(NULL) - , mTrainingWindow(NULL) - , mMerchantRepair(NULL) , mSoulgemDialog(NULL) - , mRepair(NULL) - , mRecharge(NULL) - , mCompanionWindow(NULL) , mVideoBackground(NULL) , mVideoWidget(NULL) , mWerewolfFader(NULL) @@ -319,13 +306,13 @@ namespace MWGui mDragAndDrop = new DragAndDrop(); - mRecharge = new Recharge(); - mGuiModeStates[GM_Recharge] = GuiModeState(mRecharge); - mWindows.push_back(mRecharge); + Recharge* recharge = new Recharge(); + mGuiModeStates[GM_Recharge] = GuiModeState(recharge); + mWindows.push_back(recharge); - mMenu = new MainMenu(w, h, mResourceSystem->getVFS(), mVersionDescription); - mGuiModeStates[GM_MainMenu] = GuiModeState(mMenu); - mWindows.push_back(mMenu); + MainMenu* menu = new MainMenu(w, h, mResourceSystem->getVFS(), mVersionDescription); + mGuiModeStates[GM_MainMenu] = GuiModeState(menu); + mWindows.push_back(menu); mLocalMapRender = new MWRender::LocalMap(mViewer->getSceneData()->asGroup()); mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender, mWorkQueue); @@ -367,23 +354,23 @@ namespace MWGui mMessageBoxManager = new MessageBoxManager(mStore->get().find("fMessageTimePerChar")->getFloat()); - mSpellBuyingWindow = new SpellBuyingWindow(); - mWindows.push_back(mSpellBuyingWindow); - mGuiModeStates[GM_SpellBuying] = GuiModeState(mSpellBuyingWindow); + SpellBuyingWindow* spellBuyingWindow = new SpellBuyingWindow(); + mWindows.push_back(spellBuyingWindow); + mGuiModeStates[GM_SpellBuying] = GuiModeState(spellBuyingWindow); - mTravelWindow = new TravelWindow(); - mWindows.push_back(mTravelWindow); - mGuiModeStates[GM_Travel] = GuiModeState(mTravelWindow); + TravelWindow* travelWindow = new TravelWindow(); + mWindows.push_back(travelWindow); + mGuiModeStates[GM_Travel] = GuiModeState(travelWindow); mDialogueWindow = new DialogueWindow(); mWindows.push_back(mDialogueWindow); trackWindow(mDialogueWindow, "dialogue"); mGuiModeStates[GM_Dialogue] = GuiModeState(mDialogueWindow); - mContainerWindow = new ContainerWindow(mDragAndDrop); - mWindows.push_back(mContainerWindow); - trackWindow(mContainerWindow, "container"); - mGuiModeStates[GM_Container] = GuiModeState({mContainerWindow, mInventoryWindow}); + ContainerWindow* containerWindow = new ContainerWindow(mDragAndDrop); + mWindows.push_back(containerWindow); + trackWindow(containerWindow, "container"); + mGuiModeStates[GM_Container] = GuiModeState({containerWindow, mInventoryWindow}); mHud = new HUD(mCustomMarkers, mDragAndDrop, mLocalMapRender); mWindows.push_back(mHud); @@ -412,49 +399,49 @@ namespace MWGui mConfirmationDialog = new ConfirmationDialog(); mWindows.push_back(mConfirmationDialog); - mAlchemyWindow = new AlchemyWindow(); - mWindows.push_back(mAlchemyWindow); - trackWindow(mAlchemyWindow, "alchemy"); - mGuiModeStates[GM_Alchemy] = GuiModeState(mAlchemyWindow); + AlchemyWindow* alchemyWindow = new AlchemyWindow(); + mWindows.push_back(alchemyWindow); + trackWindow(alchemyWindow, "alchemy"); + mGuiModeStates[GM_Alchemy] = GuiModeState(alchemyWindow); mQuickKeysMenu = new QuickKeysMenu(); mWindows.push_back(mQuickKeysMenu); mGuiModeStates[GM_QuickKeysMenu] = GuiModeState(mQuickKeysMenu); - mLevelupDialog = new LevelupDialog(); - mWindows.push_back(mLevelupDialog); - mGuiModeStates[GM_Levelup] = GuiModeState(mLevelupDialog); + LevelupDialog* levelupDialog = new LevelupDialog(); + mWindows.push_back(levelupDialog); + mGuiModeStates[GM_Levelup] = GuiModeState(levelupDialog); mWaitDialog = new WaitDialog(); mWindows.push_back(mWaitDialog); mGuiModeStates[GM_Rest] = GuiModeState(mWaitDialog); - mSpellCreationDialog = new SpellCreationDialog(); - mWindows.push_back(mSpellCreationDialog); - mGuiModeStates[GM_SpellCreation] = GuiModeState(mSpellCreationDialog); + SpellCreationDialog* spellCreationDialog = new SpellCreationDialog(); + mWindows.push_back(spellCreationDialog); + mGuiModeStates[GM_SpellCreation] = GuiModeState(spellCreationDialog); - mEnchantingDialog = new EnchantingDialog(); - mWindows.push_back(mEnchantingDialog); - mGuiModeStates[GM_Enchanting] = GuiModeState(mEnchantingDialog); + EnchantingDialog* enchantingDialog = new EnchantingDialog(); + mWindows.push_back(enchantingDialog); + mGuiModeStates[GM_Enchanting] = GuiModeState(enchantingDialog); - mTrainingWindow = new TrainingWindow(); - mWindows.push_back(mTrainingWindow); - mGuiModeStates[GM_Training] = GuiModeState(mTrainingWindow); + TrainingWindow* trainingWindow = new TrainingWindow(); + mWindows.push_back(trainingWindow); + mGuiModeStates[GM_Training] = GuiModeState(trainingWindow); - mMerchantRepair = new MerchantRepair(); - mWindows.push_back(mMerchantRepair); - mGuiModeStates[GM_MerchantRepair] = GuiModeState(mMerchantRepair); + MerchantRepair* merchantRepair = new MerchantRepair(); + mWindows.push_back(merchantRepair); + mGuiModeStates[GM_MerchantRepair] = GuiModeState(merchantRepair); - mRepair = new Repair(); - mWindows.push_back(mRepair); - mGuiModeStates[GM_Repair] = GuiModeState(mRepair); + Repair* repair = new Repair(); + mWindows.push_back(repair); + mGuiModeStates[GM_Repair] = GuiModeState(repair); mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); - mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); - mWindows.push_back(mCompanionWindow); - trackWindow(mCompanionWindow, "companion"); - mGuiModeStates[GM_Companion] = GuiModeState({mInventoryWindow, mCompanionWindow}); + CompanionWindow* companionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); + mWindows.push_back(companionWindow); + trackWindow(companionWindow, "companion"); + mGuiModeStates[GM_Companion] = GuiModeState({mInventoryWindow, companionWindow}); mJailScreen = new JailScreen(); mWindows.push_back(mJailScreen); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 773eed4fc..f315bb906 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -405,37 +405,24 @@ namespace MWGui HUD *mHud; MapWindow *mMap; MWRender::LocalMap* mLocalMapRender; - MainMenu *mMenu; ToolTips *mToolTips; StatsWindow *mStatsWindow; MessageBoxManager *mMessageBoxManager; Console *mConsole; DialogueWindow *mDialogueWindow; - ContainerWindow *mContainerWindow; DragAndDrop* mDragAndDrop; InventoryWindow *mInventoryWindow; ScrollWindow* mScrollWindow; BookWindow* mBookWindow; CountDialog* mCountDialog; TradeWindow* mTradeWindow; - SpellBuyingWindow* mSpellBuyingWindow; - TravelWindow* mTravelWindow; SettingsWindow* mSettingsWindow; ConfirmationDialog* mConfirmationDialog; - AlchemyWindow* mAlchemyWindow; SpellWindow* mSpellWindow; QuickKeysMenu* mQuickKeysMenu; LoadingScreen* mLoadingScreen; - LevelupDialog* mLevelupDialog; WaitDialog* mWaitDialog; - SpellCreationDialog* mSpellCreationDialog; - EnchantingDialog* mEnchantingDialog; - TrainingWindow* mTrainingWindow; - MerchantRepair* mMerchantRepair; SoulgemDialog* mSoulgemDialog; - Repair* mRepair; - Recharge* mRecharge; - CompanionWindow* mCompanionWindow; MyGUI::ImageBox* mVideoBackground; VideoWidget* mVideoWidget; ScreenFader* mWerewolfFader; From f6c227b966e17325541ac7b9b010da8babb1aceb Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 23:02:17 +0200 Subject: [PATCH 162/505] Reset screen faders in clear() Fixes a black screen when loading a game while waiting/resting. --- apps/openmw/mwgui/screenfader.cpp | 6 ++++++ apps/openmw/mwgui/screenfader.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 2 -- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index be0346e88..1d04e871e 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -119,6 +119,12 @@ namespace MWGui queue(time, percent/100.f); } + void ScreenFader::clear() + { + clearQueue(); + notifyAlphaChanged(0.f); + } + void ScreenFader::setFactor(float factor) { mFactor = factor; diff --git a/apps/openmw/mwgui/screenfader.hpp b/apps/openmw/mwgui/screenfader.hpp index b510e133a..19468de3c 100644 --- a/apps/openmw/mwgui/screenfader.hpp +++ b/apps/openmw/mwgui/screenfader.hpp @@ -42,6 +42,8 @@ namespace MWGui void fadeOut(const float time); void fadeTo(const int percent, const float time); + void clear(); + void setFactor (float factor); void setRepeat(bool repeat); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 906151ab1..29425e7c3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1589,8 +1589,6 @@ namespace MWGui mForceHidden = GW_None; - setWerewolfOverlay(false); - while (!mGuiModes.empty()) popGuiMode(); From 222defc6d873f1cb9cc93abeff939ed77e442e6d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 23:09:41 +0200 Subject: [PATCH 163/505] Extend HUD::clear() --- apps/openmw/mwgui/hud.cpp | 7 +++++++ apps/openmw/mwgui/hud.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 9 ++------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 87c1b2f3c..779e358d3 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -632,6 +632,13 @@ namespace MWGui mEnemyHealthTimer = -1; } + void HUD::clear() + { + unsetSelectedSpell(); + unsetSelectedWeapon(); + resetEnemy(); + } + void HUD::customMarkerCreated(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 fc335d1e7..3542f3ebf 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -58,7 +58,7 @@ namespace MWGui void setEnemy(const MWWorld::Ptr& enemy); void resetEnemy(); - void clear() { resetEnemy(); } + void clear(); private: MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth, *mDrowning; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 29425e7c3..2cfafd0a2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -506,16 +506,9 @@ namespace MWGui disallowAll(); delete mCharGen; mCharGen = new CharacterCreation(mViewer->getSceneData()->asGroup(), mResourceSystem); - mGuiModes.clear(); - MWBase::Environment::get().getInputManager()->changeInputMode(false); - mHud->unsetSelectedWeapon(); - mHud->unsetSelectedSpell(); - unsetForceHide(GW_ALL); } else allow(GW_ALL); - - mRestAllowed = !newgame; } WindowManager::~WindowManager() @@ -1338,6 +1331,7 @@ namespace MWGui void WindowManager::disallowAll() { mAllowed = GW_None; + mRestAllowed = false; mBookWindow->setInventoryAllowed (false); mScrollWindow->setInventoryAllowed (false); @@ -1588,6 +1582,7 @@ namespace MWGui mCustomMarkers.clear(); mForceHidden = GW_None; + mRestAllowed = true; while (!mGuiModes.empty()) popGuiMode(); From c0d8bef82fb5964a278bf53005b9135c8954ca63 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 23:14:53 +0200 Subject: [PATCH 164/505] Call changeInputMode() from updateVisible() --- apps/openmw/mwgui/windowmanagerimp.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2cfafd0a2..8349ca0bc 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -495,8 +495,6 @@ namespace MWGui // Set up visibility updateVisible(); - - MWBase::Environment::get().getInputManager()->changeInputMode(false); } void WindowManager::setNewGame(bool newgame) @@ -573,6 +571,8 @@ namespace MWGui bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + mInputBlocker->setVisible (gameMode); if (loading) @@ -761,7 +761,6 @@ namespace MWGui void WindowManager::interactiveMessageBox(const std::string &message, const std::vector &buttons, bool block) { mMessageBoxManager->createInteractiveMessageBox(message, buttons); - MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); updateVisible(); if (block) @@ -1143,9 +1142,6 @@ namespace MWGui mKeyboardNavigation->restoreFocus(mode); - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - updateVisible(); } @@ -1173,9 +1169,6 @@ namespace MWGui mKeyboardNavigation->restoreFocus(mode); } - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - updateVisible(); } @@ -1196,9 +1189,6 @@ namespace MWGui ++it; } - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - updateVisible(); } @@ -1488,7 +1478,6 @@ namespace MWGui void WindowManager::showSoulgemDialog(MWWorld::Ptr item) { mSoulgemDialog->show(item); - MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); updateVisible(); } @@ -1587,7 +1576,6 @@ namespace MWGui while (!mGuiModes.empty()) popGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(false); updateVisible(); } From d58ff4a736d8f5003d5dff234524e6fb697fc69b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 23:47:47 +0200 Subject: [PATCH 165/505] Remove obsolete Container GUI keyboard handling --- apps/openmw/mwgui/container.cpp | 9 --------- apps/openmw/mwgui/container.hpp | 1 - 2 files changed, 10 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 85afc1aa3..90ed1a596 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -46,7 +46,6 @@ namespace MWGui mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); - mCloseButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ContainerWindow::onKeyPressed); mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); setCoord(200,0,600,300); @@ -158,14 +157,6 @@ namespace MWGui setTitle(container.getClass().getName(container)); } - void ContainerWindow::onKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) - { - if (_key == MyGUI::KeyCode::Space) - onCloseButtonClicked(mCloseButton); - if (_key == MyGUI::KeyCode::Return || _key == MyGUI::KeyCode::NumpadEnter) - onTakeAllButtonClicked(mTakeButton); - } - void ContainerWindow::resetReference() { ReferenceInterface::resetReference(); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index a53d4f782..50c69da3b 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -62,7 +62,6 @@ namespace MWGui void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender); void onDisposeCorpseButtonClicked(MyGUI::Widget* sender); - void onKeyPressed(MyGUI::Widget* _sender, MyGUI::KeyCode _key, MyGUI::Char _char); /// @return is taking the item allowed? bool onTakeItem(const ItemStack& item, int count); From 331192f2d688ebd7452726e3861434fe9d537619 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 00:23:08 +0200 Subject: [PATCH 166/505] Improve keyboard navigation of book/scroll windows --- apps/openmw/mwgui/bookwindow.cpp | 15 +++++++++++++++ apps/openmw/mwgui/bookwindow.hpp | 2 ++ apps/openmw/mwgui/formatting.cpp | 9 +++++---- apps/openmw/mwgui/keyboardnavigation.cpp | 9 +++++---- apps/openmw/mwgui/scrollwindow.cpp | 21 +++++++++++++++++++-- apps/openmw/mwgui/scrollwindow.hpp | 1 + 6 files changed, 47 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 5abc63c55..ae20b8e43 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -52,6 +52,11 @@ namespace MWGui mRightPage->setNeedMouseFocus(true); mRightPage->eventMouseWheel += MyGUI::newDelegate(this, &BookWindow::onMouseWheel); + mNextPageButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &BookWindow::onKeyButtonPressed); + mPrevPageButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &BookWindow::onKeyButtonPressed); + mTakeButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &BookWindow::onKeyButtonPressed); + mCloseButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &BookWindow::onKeyButtonPressed); + if (mNextPageButton->getSize().width == 64) { // english button has a 7 pixel wide strip of garbage on its right edge @@ -94,6 +99,8 @@ namespace MWGui updatePages(); setTakeButtonShow(showTakeButton); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); } void BookWindow::setTakeButtonShow(bool show) @@ -102,6 +109,14 @@ namespace MWGui mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); } + void BookWindow::onKeyButtonPressed(MyGUI::Widget *sender, MyGUI::KeyCode key, MyGUI::Char character) + { + if (key == MyGUI::KeyCode::ArrowUp) + prevPage(); + else if (key == MyGUI::KeyCode::ArrowDown) + nextPage(); + } + void BookWindow::setInventoryAllowed(bool allowed) { mTakeButtonAllowed = allowed; diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index b20498feb..2459c3464 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -27,6 +27,8 @@ namespace MWGui void onMouseWheel(MyGUI::Widget* _sender, int _rel); void setTakeButtonShow(bool show); + void onKeyButtonPressed(MyGUI::Widget* sender, MyGUI::KeyCode key, MyGUI::Char character); + void nextPage(); void prevPage(); diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index cf4a5b589..a9319048e 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -406,10 +406,11 @@ namespace MWGui MyGUI::EditBox* box = parent->createWidget("NormalText", MyGUI::IntCoord(0, pag.getCurrentTop(), pag.getPageWidth(), 0), MyGUI::Align::Left | MyGUI::Align::Top, parent->getName() + MyGUI::utility::toString(parent->getChildCount())); - box->setProperty("Static", "true"); - box->setProperty("MultiLine", "true"); - box->setProperty("WordWrap", "true"); - box->setProperty("NeedMouse", "false"); + box->setEditStatic(true); + box->setEditMultiLine(true); + box->setEditWordWrap(true); + box->setNeedMouseFocus(false); + box->setNeedKeyFocus(false); box->setMaxTextLength(text.size()); box->setTextAlign(mBlockStyle.mAlign); box->setTextColour(mTextStyle.mColour); diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index 8ce26e1d0..ddfd8f662 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -156,13 +156,14 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) MyGUI::Widget* next = keyFocusList[index]; int vertdiff = next->getTop() - focus->getTop(); int horizdiff = next->getLeft() - focus->getLeft(); - if (direction == D_Right && horizdiff <= 0) + bool isVertical = std::abs(vertdiff) > std::abs(horizdiff); + if (direction == D_Right && (horizdiff <= 0 || isVertical)) return false; - else if (direction == D_Left && horizdiff >= 0) + else if (direction == D_Left && (horizdiff >= 0 || isVertical)) return false; - else if (direction == D_Down && vertdiff <= 0) + else if (direction == D_Down && (vertdiff <= 0 || !isVertical)) return false; - else if (direction == D_Up && vertdiff >= 0) + else if (direction == D_Up && (vertdiff >= 0 || !isVertical)) return false; MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[index]); diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index a92ef92ab..ea811f5b1 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -47,6 +47,9 @@ namespace MWGui adjustButton(mCloseButton); adjustButton(mTakeButton); + mCloseButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ScrollWindow::onKeyButtonPressed); + mTakeButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ScrollWindow::onKeyButtonPressed); + center(); } @@ -66,14 +69,28 @@ namespace MWGui // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden mTextView->setVisibleVScroll(false); if (size.height > mTextView->getSize().height) - mTextView->setCanvasSize(MyGUI::IntSize(410, size.height)); + mTextView->setCanvasSize(mTextView->getWidth(), size.height); else - mTextView->setCanvasSize(410, mTextView->getSize().height); + mTextView->setCanvasSize(mTextView->getWidth(), mTextView->getSize().height); mTextView->setVisibleVScroll(true); mTextView->setViewOffset(MyGUI::IntPoint(0,0)); setTakeButtonShow(showTakeButton); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); + } + + void ScrollWindow::onKeyButtonPressed(MyGUI::Widget *sender, MyGUI::KeyCode key, MyGUI::Char character) + { + int scroll = 0; + if (key == MyGUI::KeyCode::ArrowUp) + scroll = 40; + else if (key == MyGUI::KeyCode::ArrowDown) + scroll = -40; + + if (scroll != 0) + mTextView->setViewOffset(mTextView->getViewOffset() + MyGUI::IntPoint(0, scroll)); } void ScrollWindow::setTakeButtonShow(bool show) diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 35016e5dc..adc0bd93e 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -26,6 +26,7 @@ namespace MWGui void onCloseButtonClicked (MyGUI::Widget* _sender); void onTakeButtonClicked (MyGUI::Widget* _sender); void setTakeButtonShow(bool show); + void onKeyButtonPressed(MyGUI::Widget* sender, MyGUI::KeyCode key, MyGUI::Char character); private: Gui::ImageButton* mCloseButton; From 0e57f1317b6dc7f0ebc6f14d73477296f6160a4e Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 11:50:55 +0200 Subject: [PATCH 167/505] Remove redundant setVisible(false) --- apps/openmw/mwgui/jailscreen.cpp | 2 -- apps/openmw/mwgui/journalwindow.cpp | 1 - apps/openmw/mwgui/loadingscreen.cpp | 2 -- apps/openmw/mwgui/recharge.cpp | 2 -- apps/openmw/mwgui/screenfader.cpp | 1 - 5 files changed, 8 deletions(-) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 8ac133d76..11d7466a8 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -26,8 +26,6 @@ namespace MWGui { getWidget(mProgressBar, "ProgressBar"); - setVisible(false); - mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &JailScreen::onJailProgressChanged); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &JailScreen::onJailFinished); diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index a0e424021..3a67e857d 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -96,7 +96,6 @@ namespace JournalWindowImpl (MWGui::JournalViewModel::Ptr Model, bool questList) : JournalBooks (Model), JournalWindow() { - mMainWidget->setVisible(false); center(); adviseButtonClick (OptionsBTN, &JournalWindowImpl::notifyOptions ); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 15d9d555f..f22d825dd 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -51,8 +51,6 @@ namespace MWGui mBackgroundImage = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, MyGUI::Align::Stretch, "Menu"); - setVisible(false); - findSplashScreens(); } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 0398112ba..32da7876c 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -46,8 +46,6 @@ Recharge::Recharge() mBox->setDisplayMode(ItemChargeView::DisplayMode_EnchantmentCharge); mGemIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onSelectItem); - - setVisible(false); } void Recharge::onOpen() diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index 1d04e871e..76e79a348 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -74,7 +74,6 @@ namespace MWGui , mRepeat(false) { mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize()); - setVisible(false); MyGUI::ImageBox* imageBox = mMainWidget->castType(false); if (imageBox) From 2c4b0cc40800110b3cbcc92e7451c0c17709642b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 12:11:02 +0200 Subject: [PATCH 168/505] Hide sneak indicator by default --- files/mygui/openmw_hud.layout | 1 + 1 file changed, 1 insertion(+) diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 366b0c4c6..cee3f4682 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -82,6 +82,7 @@ + From 9ed1b165537561dd9b34dbb94a6940f40a4afcd5 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 12:47:50 +0200 Subject: [PATCH 169/505] Extend code that detects whether a key was consumed by the GUI (Fixes #4016) --- apps/openmw/mwgui/windowmanagerimp.cpp | 25 ++++++++++++++++++++++++- apps/openmw/mwinput/inputmanagerimp.cpp | 9 +++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8349ca0bc..6c69dffbc 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -2000,7 +2000,30 @@ namespace MWGui bool WindowManager::injectKeyPress(MyGUI::KeyCode key, unsigned int text) { if (!mKeyboardNavigation->injectKeyPress(key, text)) - return MyGUI::InputManager::getInstance().injectKeyPress(key, text); + { + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + bool widgetActive = MyGUI::InputManager::getInstance().injectKeyPress(key, text); + if (!widgetActive || !focus) + return false; + // FIXME: MyGUI doesn't allow widgets to state if a given key was actually used, so make a guess + if (focus->getTypeName().find("Button") != std::string::npos) + { + switch (key.getValue()) + { + case MyGUI::KeyCode::ArrowDown: + case MyGUI::KeyCode::ArrowUp: + case MyGUI::KeyCode::ArrowLeft: + case MyGUI::KeyCode::ArrowRight: + case MyGUI::KeyCode::Return: + case MyGUI::KeyCode::NumpadEnter: + case MyGUI::KeyCode::Space: + return true; + default: + return false; + } + } + return false; + } else return true; } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index cd17c5175..c5b18ff17 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -674,10 +674,11 @@ namespace MWInput bool consumed = false; if (kc != OIS::KC_UNASSIGNED) { - consumed = SDL_IsTextInputActive() && - ( !(SDLK_SCANCODE_MASK & arg.keysym.sym) && std::isprint(arg.keysym.sym)); // Little trick to check if key is printable - bool guiFocus = MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); - setPlayerControlsEnabled(!guiFocus); + consumed = MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + if (SDL_IsTextInputActive() && // Little trick to check if key is printable + ( !(SDLK_SCANCODE_MASK & arg.keysym.sym) && std::isprint(arg.keysym.sym))) + consumed = true; + setPlayerControlsEnabled(!consumed); } if (arg.repeat) return; From 843106fc616488ca174cd9d30d504254546fe631 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 12:58:14 +0200 Subject: [PATCH 170/505] Handle the wait progress bar as part of the GUI mode --- apps/openmw/mwgui/trainingwindow.cpp | 19 +++++++++++++------ apps/openmw/mwgui/trainingwindow.hpp | 4 ++++ apps/openmw/mwgui/waitdialog.cpp | 20 ++++++++++++-------- apps/openmw/mwgui/waitdialog.hpp | 3 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 4 ++-- 5 files changed, 33 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index c1f7f8ac1..13a0a6883 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -51,12 +51,18 @@ namespace MWGui mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &TrainingWindow::onTrainingProgressChanged); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &TrainingWindow::onTrainingFinished); - - mProgressBar.setVisible(false); } void TrainingWindow::onOpen() { + if (mTimeAdvancer.isRunning()) + { + mProgressBar.setVisible(true); + setVisible(false); + } + else + mProgressBar.setVisible(false); + center(); } @@ -166,15 +172,12 @@ namespace MWGui // add gold to NPC trading gold pool npcStats.setGoldPool(npcStats.getGoldPool() + price); - // go back to game mode - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - // advance time MWBase::Environment::get().getMechanicsManager()->rest(false); MWBase::Environment::get().getMechanicsManager()->rest(false); MWBase::Environment::get().getWorld ()->advanceTime (2); + setVisible(false); mProgressBar.setVisible(true); mProgressBar.setProgress(0, 2); mTimeAdvancer.run(2); @@ -191,6 +194,10 @@ namespace MWGui void TrainingWindow::onTrainingFinished() { mProgressBar.setVisible(false); + + // go back to game mode + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); + MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); } void TrainingWindow::onFrame(float dt) diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index 127c85f6a..fb7b10deb 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -16,10 +16,14 @@ namespace MWGui virtual void onOpen(); + bool exit() { return false; } + void setPtr(const MWWorld::Ptr& actor); void onFrame(float dt); + WindowBase* getProgressBar() { return &mProgressBar; } + void clear() { resetReference(); } protected: diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index cd1d29854..8a360435c 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -75,8 +75,6 @@ namespace MWGui mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &WaitDialog::onWaitingProgressChanged); mTimeAdvancer.eventInterrupted += MyGUI::newDelegate(this, &WaitDialog::onWaitingInterrupted); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &WaitDialog::onWaitingFinished); - - mProgressBar.setVisible (false); } void WaitDialog::setPtr(const MWWorld::Ptr &ptr) @@ -86,11 +84,22 @@ namespace MWGui bool WaitDialog::exit() { - return (!mProgressBar.isVisible()); //Only exit if not currently waiting + return (!mTimeAdvancer.isRunning()); //Only exit if not currently waiting } void WaitDialog::onOpen() { + if (mTimeAdvancer.isRunning()) + { + mProgressBar.setVisible(true); + setVisible(false); + return; + } + else + { + mProgressBar.setVisible(false); + } + if (!MWBase::Environment::get().getWindowManager ()->getRestEnabled ()) { MWBase::Environment::get().getWindowManager()->popGuiMode (); @@ -262,11 +271,6 @@ namespace MWGui } } - void WaitDialog::clear() - { - mProgressBar.setVisible(false); - } - void WaitDialog::stopWaiting () { MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2f); diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 6bd90473f..c7ccee025 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -34,12 +34,13 @@ namespace MWGui virtual bool exit(); void onFrame(float dt); - void clear(); bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } void wakeUp(); void autosave(); + WindowBase* getProgressBar() { return &mProgressBar; } + protected: MyGUI::TextBox* mDateTimeText; MyGUI::TextBox* mRestText; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6c69dffbc..c572bce54 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -414,7 +414,7 @@ namespace MWGui mWaitDialog = new WaitDialog(); mWindows.push_back(mWaitDialog); - mGuiModeStates[GM_Rest] = GuiModeState(mWaitDialog); + mGuiModeStates[GM_Rest] = GuiModeState({mWaitDialog->getProgressBar(), mWaitDialog}); SpellCreationDialog* spellCreationDialog = new SpellCreationDialog(); mWindows.push_back(spellCreationDialog); @@ -426,7 +426,7 @@ namespace MWGui TrainingWindow* trainingWindow = new TrainingWindow(); mWindows.push_back(trainingWindow); - mGuiModeStates[GM_Training] = GuiModeState(trainingWindow); + mGuiModeStates[GM_Training] = GuiModeState({trainingWindow->getProgressBar(), trainingWindow}); MerchantRepair* merchantRepair = new MerchantRepair(); mWindows.push_back(merchantRepair); From 8ae7e4c958a0b59a0b555b9c60a227521f5da327 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 13:05:52 +0200 Subject: [PATCH 171/505] Make Enter on a name edit accept the dialog --- apps/openmw/mwgui/alchemywindow.cpp | 9 +++++++++ apps/openmw/mwgui/alchemywindow.hpp | 1 + apps/openmw/mwgui/enchantingdialog.cpp | 8 ++++++++ apps/openmw/mwgui/enchantingdialog.hpp | 3 ++- apps/openmw/mwgui/spellcreationdialog.cpp | 6 ++++++ apps/openmw/mwgui/spellcreationdialog.hpp | 1 + 6 files changed, 27 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 5b1489821..0140653a1 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -54,9 +54,16 @@ namespace MWGui mCreateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCreateButtonClicked); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCancelButtonClicked); + mNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &AlchemyWindow::onAccept); + center(); } + void AlchemyWindow::onAccept(MyGUI::EditBox* sender) + { + onCreateButtonClicked(sender); + } + void AlchemyWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Alchemy); @@ -128,6 +135,8 @@ namespace MWGui } update(); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit); } void AlchemyWindow::onIngredientSelected(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index a27d9c749..2d13a346a 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -44,6 +44,7 @@ namespace MWGui void onCancelButtonClicked(MyGUI::Widget* _sender); void onCreateButtonClicked(MyGUI::Widget* _sender); void onIngredientSelected(MyGUI::Widget* _sender); + void onAccept(MyGUI::EditBox*); void onSelectedItem(int index); diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 88973bd46..74d80d292 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -53,6 +54,7 @@ namespace MWGui mSoulBox->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onSelectSoul); mBuyButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onBuyButtonClicked); mTypeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onTypeButtonClicked); + mName->eventEditSelectAccept += MyGUI::newDelegate(this, &EnchantingDialog::onAccept); } EnchantingDialog::~EnchantingDialog() @@ -63,6 +65,7 @@ namespace MWGui void EnchantingDialog::onOpen() { center(); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mName); } void EnchantingDialog::setSoulGem(const MWWorld::Ptr &gem) @@ -284,6 +287,11 @@ namespace MWGui updateEffectsView(); } + void EnchantingDialog::onAccept(MyGUI::EditBox *sender) + { + onBuyButtonClicked(sender); + } + void EnchantingDialog::onBuyButtonClicked(MyGUI::Widget* sender) { if (mEffects.size() <= 0) diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 39614ebd1..4906de919 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -48,6 +48,7 @@ namespace MWGui void onBuyButtonClicked(MyGUI::Widget* sender); void updateLabels(); void onTypeButtonClicked(MyGUI::Widget* sender); + void onAccept(MyGUI::EditBox* sender); ItemSelectionDialog* mItemSelectionDialog; @@ -60,7 +61,7 @@ namespace MWGui MyGUI::Button* mTypeButton; MyGUI::Button* mBuyButton; - MyGUI::TextBox* mName; + MyGUI::EditBox* mName; MyGUI::TextBox* mEnchantmentPoints; MyGUI::TextBox* mCastCost; MyGUI::TextBox* mCharge; diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index d5dee1139..4aa208d8f 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -349,6 +349,7 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellCreationDialog::onCancelButtonClicked); mBuyButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellCreationDialog::onBuyButtonClicked); + mNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SpellCreationDialog::onAccept); setWidgets(mAvailableEffectsList, mUsedEffectsView); } @@ -416,6 +417,11 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_SpellCreation); } + void SpellCreationDialog::onAccept(MyGUI::EditBox *sender) + { + onBuyButtonClicked(sender); + } + void SpellCreationDialog::onOpen() { center(); diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 855016666..ec90fa3ce 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -162,6 +162,7 @@ namespace MWGui void onCancelButtonClicked (MyGUI::Widget* sender); void onBuyButtonClicked (MyGUI::Widget* sender); + void onAccept(MyGUI::EditBox* sender); virtual void notifyEffectsChanged (); From 67dc4e019acb554b6d36f02eb73f3ef7b190848d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 13:10:50 +0200 Subject: [PATCH 172/505] Make Enter on trade window price attempt the trade --- apps/openmw/mwgui/tradewindow.cpp | 8 ++++++++ apps/openmw/mwgui/tradewindow.hpp | 1 + 2 files changed, 9 insertions(+) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index feccfd942..c2e58b81f 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -96,6 +96,7 @@ namespace MWGui mDecreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &TradeWindow::onBalanceButtonReleased); mTotalBalance->eventValueChanged += MyGUI::newDelegate(this, &TradeWindow::onBalanceValueChanged); + mTotalBalance->eventEditSelectAccept += MyGUI::newDelegate(this, &TradeWindow::onAccept); mTotalBalance->setMinValue(INT_MIN+1); // disallow INT_MIN since abs(INT_MIN) is undefined setCoord(400, 0, 400, 300); @@ -140,6 +141,8 @@ namespace MWGui setTitle(actor.getClass().getName(actor)); onFilterChanged(mFilterAll); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTotalBalance); } void TradeWindow::onFrame(float dt) @@ -364,6 +367,11 @@ namespace MWGui restock(); } + void TradeWindow::onAccept(MyGUI::EditBox *sender) + { + onOfferButtonClicked(sender); + } + void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { exit(); diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 00f38024d..fc692a55a 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -84,6 +84,7 @@ namespace MWGui void onFilterChanged(MyGUI::Widget* _sender); void onOfferButtonClicked(MyGUI::Widget* _sender); + void onAccept(MyGUI::EditBox* sender); void onCancelButtonClicked(MyGUI::Widget* _sender); void onMaxSaleButtonClicked(MyGUI::Widget* _sender); void onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); From 76ddf8d794dc9cc847297c7f994635028ffb1fcb Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 13:17:08 +0200 Subject: [PATCH 173/505] Support Up/DownArrow keys to change NumericEditBox value --- components/widgets/numericeditbox.cpp | 16 ++++++++++++++++ components/widgets/numericeditbox.hpp | 1 + 2 files changed, 17 insertions(+) diff --git a/components/widgets/numericeditbox.cpp b/components/widgets/numericeditbox.cpp index 828a84589..6e884a091 100644 --- a/components/widgets/numericeditbox.cpp +++ b/components/widgets/numericeditbox.cpp @@ -75,4 +75,20 @@ namespace Gui setCaption(MyGUI::utility::toString(mValue)); } + void NumericEditBox::onKeyButtonPressed(MyGUI::KeyCode key, MyGUI::Char character) + { + if (key == MyGUI::KeyCode::ArrowUp) + { + setValue(std::min(mValue+1, mMaxValue)); + eventValueChanged(mValue); + } + else if (key == MyGUI::KeyCode::ArrowDown) + { + setValue(std::max(mValue-1, mMinValue)); + eventValueChanged(mValue); + } + else + Base::onKeyButtonPressed(key, character); + } + } diff --git a/components/widgets/numericeditbox.hpp b/components/widgets/numericeditbox.hpp index 20000b3d3..ca7674f22 100644 --- a/components/widgets/numericeditbox.hpp +++ b/components/widgets/numericeditbox.hpp @@ -33,6 +33,7 @@ namespace Gui private: void onEditTextChange(MyGUI::EditBox* sender); void onKeyLostFocus(MyGUI::Widget* _new); + void onKeyButtonPressed(MyGUI::KeyCode key, MyGUI::Char character); int mValue; From ca3b08b85202ed40845e93bed9800d02f0d86859 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 13:49:35 +0200 Subject: [PATCH 174/505] Make Activate key accept GUI buttons --- apps/openmw/mwinput/inputmanagerimp.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index c5b18ff17..79c689561 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -162,14 +162,13 @@ namespace MWInput void InputManager::setPlayerControlsEnabled(bool enabled) { - int nPlayerChannels = 18; - int playerChannels[] = {A_Activate, A_AutoMove, A_AlwaysRun, A_ToggleWeapon, + int playerChannels[] = {A_AutoMove, A_AlwaysRun, A_ToggleWeapon, A_ToggleSpell, A_Rest, A_QuickKey1, A_QuickKey2, A_QuickKey3, A_QuickKey4, A_QuickKey5, A_QuickKey6, A_QuickKey7, A_QuickKey8, A_QuickKey9, A_QuickKey10, A_Use, A_Journal}; - for(int i = 0; i < nPlayerChannels; i++) { + for(size_t i = 0; i < sizeof(playerChannels)/sizeof(playerChannels[0]); i++) { int pc = playerChannels[i]; mInputBinder->getChannel(pc)->setEnabled(enabled); } @@ -234,8 +233,7 @@ namespace MWInput break; case A_Activate: resetIdleTime(); - if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) - activate(); + activate(); break; case A_Journal: toggleJournal (); @@ -1080,7 +1078,9 @@ namespace MWInput void InputManager::activate() { - if (mControlSwitch["playercontrols"]) + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Return, 0); + else if (mControlSwitch["playercontrols"]) mPlayer->activate(); } From 94b538ac829553ba994054206b50aa90a6299785 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 13:57:09 +0200 Subject: [PATCH 175/505] Fix crash due to not calling WindowModal::onClose() --- apps/openmw/mwgui/race.cpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 2b407ac93..64609cbe6 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -187,6 +187,8 @@ namespace MWGui void RaceDialog::onClose() { + WindowModal::onClose(); + mPreviewImage->setRenderItemTexture(NULL); mPreviewTexture.reset(NULL); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c572bce54..d734d7540 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1738,9 +1738,12 @@ namespace MWGui // Only remove the top if it matches the current pointer. A lot of things hide their visibility before showing it, //so just popping the top would cause massive issues. if(!mCurrentModals.empty()) + { if(input == mCurrentModals.top()) mCurrentModals.pop(); - + else + std::cout << " warning: modal widget " << input << " " << typeid(input).name() << " not found " << std::endl; + } if (mCurrentModals.empty()) mKeyboardNavigation->restoreFocus(getMode()); } From ad8d0c53024d82464cf7a2861ce2908f3252efad Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 15:32:44 +0200 Subject: [PATCH 176/505] Use keypad to control the camera --- apps/openmw/mwinput/inputmanagerimp.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 79c689561..b1f80cae6 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1215,6 +1215,17 @@ namespace MWInput control->setInitialValue(0.0f); mInputBinder->addMouseButtonBinding (control, defaultMouseButtonBindings[i], ICS::Control::INCREASE); } + + if (i == A_LookLeftRight && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_4) && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_6)) + { + mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_6, ICS::Control::INCREASE); + mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_4, ICS::Control::DECREASE); + } + if (i == A_LookUpDown && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_8) && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_2)) + { + mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_2, ICS::Control::INCREASE); + mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_8, ICS::Control::DECREASE); + } } } } From c035548f3737a24e1b699b770c4bba753d806641 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 19:00:51 +0200 Subject: [PATCH 177/505] Make Tab work if selected widget is marked as not needing keyfocus --- apps/openmw/mwgui/keyboardnavigation.cpp | 26 ++++++++---------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index ddfd8f662..da99c72d0 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -63,12 +63,6 @@ void KeyboardNavigation::_unlinkWidget(MyGUI::Widget *widget) w.second = nullptr; } -bool isButtonFocus() -{ - MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); - return focus->getTypeName().find("Button") != std::string::npos; -} - enum Direction { D_Left, @@ -106,7 +100,13 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); - if (!focus && (direction == D_Next || direction == D_Prev)) + if ((focus && focus->getTypeName().find("Button") == std::string::npos) && direction != D_Prev && direction != D_Next) + return false; + + if (focus && (direction == D_Prev || direction == D_Next) && focus->getUserString("AcceptTab") == "true") + return false; + + if ((!focus || !focus->getNeedKeyFocus()) && (direction == D_Next || direction == D_Prev)) { // if nothing is selected, select the first widget MyGUI::VectorWidgetPtr keyFocusList; @@ -120,20 +120,12 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) return true; } } - if (!focus) return false; - if (!isButtonFocus() && direction != D_Prev && direction != D_Next) - return false; - - if ((direction == D_Prev || direction == D_Next) && focus->getUserString("AcceptTab") == "true") - return false; - - MyGUI::Widget* window = MyGUI::InputManager::getInstance().getKeyFocusWidget(); - while (window->getParent()) + MyGUI::Widget* window = focus; + while (window && window->getParent()) window = window->getParent(); - MyGUI::VectorWidgetPtr keyFocusList; getKeyFocusWidgets(window, keyFocusList); From d78e8228331826976f17f8a37801c8eed7488232 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 19:15:39 +0200 Subject: [PATCH 178/505] Add 'delay' argument for screen fading operations --- apps/openmw/mwbase/windowmanager.hpp | 6 +++--- apps/openmw/mwgui/screenfader.cpp | 29 ++++++++++++++++---------- apps/openmw/mwgui/screenfader.hpp | 11 +++++----- apps/openmw/mwgui/trainingwindow.cpp | 11 +--------- apps/openmw/mwgui/trainingwindow.hpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 12 +++++------ apps/openmw/mwgui/windowmanagerimp.hpp | 6 +++--- 7 files changed, 37 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 43d99b6b3..2df3113b3 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -317,11 +317,11 @@ namespace MWBase virtual void pinWindow (MWGui::GuiWindow window) = 0; /// Fade the screen in, over \a time seconds - virtual void fadeScreenIn(const float time, bool clearQueue=true) = 0; + virtual void fadeScreenIn(const float time, bool clearQueue=true, float delay=0.f) = 0; /// Fade the screen out to black, over \a time seconds - virtual void fadeScreenOut(const float time, bool clearQueue=true) = 0; + virtual void fadeScreenOut(const float time, bool clearQueue=true, float delay=0.f) = 0; /// Fade the screen to a specified percentage of black, over \a time seconds - virtual void fadeScreenTo(const int percent, const float time, bool clearQueue=true) = 0; + virtual void fadeScreenTo(const int percent, const float time, bool clearQueue=true, float delay=0.f) = 0; /// Darken the screen to a specified percentage virtual void setBlindness(const int percent) = 0; diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index 76e79a348..d1118848b 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -6,12 +6,13 @@ namespace MWGui { - FadeOp::FadeOp(ScreenFader * fader, float time, float targetAlpha) + FadeOp::FadeOp(ScreenFader * fader, float time, float targetAlpha, float delay) : mFader(fader), - mRemainingTime(time), + mRemainingTime(time+delay), mTargetTime(time), mTargetAlpha(targetAlpha), mStartAlpha(0.f), + mDelay(delay), mRunning(false) { } @@ -26,7 +27,7 @@ namespace MWGui if (mRunning) return; - mRemainingTime = mTargetTime; + mRemainingTime = mTargetTime + mDelay; mStartAlpha = mFader->getCurrentAlpha(); mRunning = true; } @@ -42,6 +43,12 @@ namespace MWGui return; } + if (mRemainingTime > mTargetTime) + { + mRemainingTime -= dt; + return; + } + float currentAlpha = mFader->getCurrentAlpha(); if (mStartAlpha > mTargetAlpha) { @@ -103,19 +110,19 @@ namespace MWGui mMainWidget->setAlpha(1.f-((1.f-mCurrentAlpha) * mFactor)); } - void ScreenFader::fadeIn(float time) + void ScreenFader::fadeIn(float time, float delay) { - queue(time, 1.f); + queue(time, 1.f, delay); } - void ScreenFader::fadeOut(const float time) + void ScreenFader::fadeOut(const float time, float delay) { - queue(time, 0.f); + queue(time, 0.f, delay); } - void ScreenFader::fadeTo(const int percent, const float time) + void ScreenFader::fadeTo(const int percent, const float time, float delay) { - queue(time, percent/100.f); + queue(time, percent/100.f, delay); } void ScreenFader::clear() @@ -135,7 +142,7 @@ namespace MWGui mRepeat = repeat; } - void ScreenFader::queue(float time, float targetAlpha) + void ScreenFader::queue(float time, float targetAlpha, float delay) { if (time < 0.f) return; @@ -147,7 +154,7 @@ namespace MWGui return; } - mQueue.push_back(FadeOp::Ptr(new FadeOp(this, time, targetAlpha))); + mQueue.push_back(FadeOp::Ptr(new FadeOp(this, time, targetAlpha, delay))); } bool ScreenFader::isEmpty() diff --git a/apps/openmw/mwgui/screenfader.hpp b/apps/openmw/mwgui/screenfader.hpp index 19468de3c..88dd0c57b 100644 --- a/apps/openmw/mwgui/screenfader.hpp +++ b/apps/openmw/mwgui/screenfader.hpp @@ -14,7 +14,7 @@ namespace MWGui public: typedef std::shared_ptr Ptr; - FadeOp(ScreenFader * fader, float time, float targetAlpha); + FadeOp(ScreenFader * fader, float time, float targetAlpha, float delay); bool isRunning(); @@ -28,6 +28,7 @@ namespace MWGui float mTargetTime; float mTargetAlpha; float mStartAlpha; + float mDelay; bool mRunning; }; @@ -38,16 +39,16 @@ namespace MWGui void update(float dt); - void fadeIn(const float time); - void fadeOut(const float time); - void fadeTo(const int percent, const float time); + void fadeIn(const float time, float delay=0); + void fadeOut(const float time, float delay=0); + void fadeTo(const int percent, const float time, float delay=0); void clear(); void setFactor (float factor); void setRepeat(bool repeat); - void queue(float time, float targetAlpha); + void queue(float time, float targetAlpha, float delay); bool isEmpty(); void clearQueue(); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 13a0a6883..120ab5cba 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -40,7 +40,6 @@ namespace MWGui TrainingWindow::TrainingWindow() : WindowBase("openmw_trainingwindow.layout") - , mFadeTimeRemaining(0) , mTimeAdvancer(0.05f) { getWidget(mTrainingOptions, "TrainingOptions"); @@ -183,7 +182,7 @@ namespace MWGui mTimeAdvancer.run(2); MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.25); - mFadeTimeRemaining = 0.5; + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.25, false, 0.25); } void TrainingWindow::onTrainingProgressChanged(int cur, int total) @@ -204,13 +203,5 @@ namespace MWGui { checkReferenceAvailable(); mTimeAdvancer.onFrame(dt); - - if (mFadeTimeRemaining <= 0) - return; - - mFadeTimeRemaining -= dt; - - if (mFadeTimeRemaining <= 0) - MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.25); } } diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index fb7b10deb..69a013059 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -39,8 +39,6 @@ namespace MWGui MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; - float mFadeTimeRemaining; - WaitDialogProgressBar mProgressBar; TimeAdvancer mTimeAdvancer; }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index d734d7540..6be754109 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1788,25 +1788,25 @@ namespace MWGui updateVisible(); } - void WindowManager::fadeScreenIn(const float time, bool clearQueue) + void WindowManager::fadeScreenIn(const float time, bool clearQueue, float delay) { if (clearQueue) mScreenFader->clearQueue(); - mScreenFader->fadeOut(time); + mScreenFader->fadeOut(time, delay); } - void WindowManager::fadeScreenOut(const float time, bool clearQueue) + void WindowManager::fadeScreenOut(const float time, bool clearQueue, float delay) { if (clearQueue) mScreenFader->clearQueue(); - mScreenFader->fadeIn(time); + mScreenFader->fadeIn(time, delay); } - void WindowManager::fadeScreenTo(const int percent, const float time, bool clearQueue) + void WindowManager::fadeScreenTo(const int percent, const float time, bool clearQueue, float delay) { if (clearQueue) mScreenFader->clearQueue(); - mScreenFader->fadeTo(percent, time); + mScreenFader->fadeTo(percent, time, delay); } void WindowManager::setBlindness(const int percent) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index f315bb906..56e7d9b7b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -344,11 +344,11 @@ namespace MWGui virtual void pinWindow (MWGui::GuiWindow window); /// Fade the screen in, over \a time seconds - virtual void fadeScreenIn(const float time, bool clearQueue); + virtual void fadeScreenIn(const float time, bool clearQueue, float delay); /// Fade the screen out to black, over \a time seconds - virtual void fadeScreenOut(const float time, bool clearQueue); + virtual void fadeScreenOut(const float time, bool clearQueue, float delay); /// Fade the screen to a specified percentage of black, over \a time seconds - virtual void fadeScreenTo(const int percent, const float time, bool clearQueue); + virtual void fadeScreenTo(const int percent, const float time, bool clearQueue, float delay); /// Darken the screen to a specified percentage virtual void setBlindness(const int percent); From e4c9d8466628061da92779695c0d0eb08746eff6 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 01:03:16 +0200 Subject: [PATCH 179/505] Disable NeedKey for ScrollView skins The widget is set to accept key focus by default for no reason I can tell. Fix in MyGUI TBD --- files/mygui/openmw_map_window.skin.xml | 1 + files/mygui/openmw_scroll.skin.xml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/files/mygui/openmw_map_window.skin.xml b/files/mygui/openmw_map_window.skin.xml index 31a70191f..f6c099630 100644 --- a/files/mygui/openmw_map_window.skin.xml +++ b/files/mygui/openmw_map_window.skin.xml @@ -2,6 +2,7 @@ + diff --git a/files/mygui/openmw_scroll.skin.xml b/files/mygui/openmw_scroll.skin.xml index 415c2479a..cff0ad7eb 100644 --- a/files/mygui/openmw_scroll.skin.xml +++ b/files/mygui/openmw_scroll.skin.xml @@ -3,11 +3,13 @@ + + From 82a211ba030bce61618d6820b9db2787d0a6b936 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 17:47:30 +0200 Subject: [PATCH 180/505] Fix duplicate code --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 14 +------------- components/esm/loadnpc.hpp | 2 +- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index fb4ba1016..bacbd7b2b 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -365,19 +365,7 @@ namespace MWDialogue } // check the available services of this actor - int services = 0; - if (mActor.getTypeName() == typeid(ESM::NPC).name()) - { - MWWorld::LiveCellRef* ref = mActor.get(); - if (ref->mBase->mHasAI) - services = ref->mBase->mAiData.mServices; - } - else if (mActor.getTypeName() == typeid(ESM::Creature).name()) - { - MWWorld::LiveCellRef* ref = mActor.get(); - if (ref->mBase->mHasAI) - services = ref->mBase->mAiData.mServices; - } + int services = mActor.getClass().getServices(mActor); int windowServices = 0; diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 5b89f4055..019baa297 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -46,7 +46,7 @@ struct NPC // Other services Spells = 0x00800, MagicItems = 0x01000, - Training = 0x04000, // What skills? + Training = 0x04000, Spellmaking = 0x08000, Enchanting = 0x10000, Repair = 0x20000 From b7752ec52de5489583fe174f2df2381c5777b06c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 18:07:49 +0200 Subject: [PATCH 181/505] Make TradeWindow not depend on DialogueWindow --- apps/openmw/mwgui/dialogue.cpp | 5 +++++ apps/openmw/mwgui/dialogue.hpp | 2 ++ apps/openmw/mwgui/tradewindow.cpp | 4 +--- apps/openmw/mwgui/tradewindow.hpp | 3 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index ec6dcb2cb..86aa64e8b 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -270,6 +270,11 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); } + void DialogueWindow::onTradeComplete() + { + addResponse(MyGUI::LanguageManager::getInstance().replaceTags("#{sBarterDialog5}")); + } + bool DialogueWindow::exit() { if ((!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 224ecba66..dbb33969f 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -99,6 +99,8 @@ namespace MWGui public: DialogueWindow(); + void onTradeComplete(); + virtual bool exit(); // Events diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index c2e58b81f..341167ab7 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -27,7 +27,6 @@ #include "containeritemmodel.hpp" #include "tradeitemmodel.hpp" #include "countdialog.hpp" -#include "dialogue.hpp" #include "controllers.hpp" namespace @@ -358,8 +357,7 @@ namespace MWGui mPtr.getClass().getCreatureStats(mPtr).getGoldPool() - mCurrentBalance ); } - MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse( - MWBase::Environment::get().getWorld()->getStore().get().find("sBarterDialog5")->getString()); + eventTradeDone(); MWBase::Environment::get().getWindowManager()->playSound("Item Gold Up"); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index fc692a55a..514d24022 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -41,6 +41,9 @@ namespace MWGui virtual void resetReference(); + typedef MyGUI::delegates::CMultiDelegate0 EventHandle_TradeDone; + EventHandle_TradeDone eventTradeDone; + private: ItemView* mItemView; SortFilterItemModel* mSortModel; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6be754109..76f0b029d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -337,7 +337,6 @@ namespace MWGui mTradeWindow = new TradeWindow(); mWindows.push_back(mTradeWindow); trackWindow(mTradeWindow, "barter"); - mGuiModeStates[GM_Barter] = GuiModeState({mInventoryWindow, mTradeWindow}); mConsole = new Console(w,h, mConsoleOnlyScripts); @@ -366,6 +365,7 @@ namespace MWGui mWindows.push_back(mDialogueWindow); trackWindow(mDialogueWindow, "dialogue"); mGuiModeStates[GM_Dialogue] = GuiModeState(mDialogueWindow); + mTradeWindow->eventTradeDone += MyGUI::newDelegate(mDialogueWindow, &DialogueWindow::onTradeComplete); ContainerWindow* containerWindow = new ContainerWindow(mDragAndDrop); mWindows.push_back(containerWindow); From f8ffd851461219cd5b7909b91dbf807f36b17a30 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 18:50:24 +0200 Subject: [PATCH 182/505] Topic passed to keywordSelected() no longer has to be lower case Remove redundant mDialogueMap --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 42 ++++++++----------- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 3 +- apps/openmw/mwgui/dialogue.cpp | 23 ++-------- 3 files changed, 23 insertions(+), 45 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index bacbd7b2b..c29476c7f 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -60,15 +60,6 @@ namespace MWDialogue mChoice = -1; mIsInChoice = false; mCompilerContext.setExtensions (&extensions); - - const MWWorld::Store &dialogs = - MWBase::Environment::get().getWorld()->getStore().get(); - - MWWorld::Store::iterator it = dialogs.begin(); - for (; it != dialogs.end(); ++it) - { - mDialogueMap[Misc::StringUtils::lowerCase(it->mId)] = *it; - } } void DialogueManager::clear() @@ -171,7 +162,7 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), "", false); executeScript (info->mResultScript, mActor); - mLastTopic = Misc::StringUtils::lowerCase(it->mId); + mLastTopic = it->mId; // update topics again to accommodate changes resulting from executeScript updateTopics(); @@ -310,7 +301,7 @@ namespace MWDialogue { if (iter->mId == info->mId) { - MWBase::Environment::get().getJournal()->addTopic (topic, info->mId, mActor); + MWBase::Environment::get().getJournal()->addTopic (Misc::StringUtils::lowerCase(topic), info->mId, mActor); break; } } @@ -327,6 +318,11 @@ namespace MWDialogue } } + const ESM::Dialogue *DialogueManager::searchDialogue(const std::string& id) + { + return MWBase::Environment::get().getWorld()->getStore().get().search(id); + } + void DialogueManager::updateGlobals() { MWBase::Environment::get().getWorld()->updateDialogueGlobals(); @@ -416,12 +412,10 @@ namespace MWDialogue { if(!mIsInChoice) { - if(mDialogueMap.find(keyword) != mDialogueMap.end()) + const ESM::Dialogue* dialogue = searchDialogue(keyword); + if (dialogue && dialogue->mType == ESM::Dialogue::Topic) { - if (mDialogueMap[keyword].mType == ESM::Dialogue::Topic) - { - executeTopic (keyword); - } + executeTopic (keyword); } } @@ -456,14 +450,14 @@ namespace MWDialogue { mChoice = answer; - if (mDialogueMap.find(mLastTopic) != mDialogueMap.end()) + const ESM::Dialogue* dialogue = searchDialogue(mLastTopic); + if (dialogue) { Filter filter (mActor, mChoice, mTalkedTo); - if (mDialogueMap[mLastTopic].mType == ESM::Dialogue::Topic - || mDialogueMap[mLastTopic].mType == ESM::Dialogue::Greeting) + if (dialogue->mType == ESM::Dialogue::Topic || dialogue->mType == ESM::Dialogue::Greeting) { - if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic], true)) + if (const ESM::DialInfo *info = filter.search (*dialogue, true)) { std::string text = info->mResponse; parseText (text); @@ -477,12 +471,12 @@ namespace MWDialogue // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, // in which case it should not be added to the journal. - for (ESM::Dialogue::InfoContainer::const_iterator iter = mDialogueMap[mLastTopic].mInfo.begin(); - iter!=mDialogueMap[mLastTopic].mInfo.end(); ++iter) + for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue->mInfo.begin(); + iter!=dialogue->mInfo.end(); ++iter) { if (iter->mId == info->mId) { - MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId, mActor); + MWBase::Environment::get().getJournal()->addTopic (Misc::StringUtils::lowerCase(mLastTopic), info->mId, mActor); break; } } @@ -737,7 +731,7 @@ namespace MWDialogue if (actor == mActor && !mLastTopic.empty()) { MWBase::Environment::get().getJournal()->removeLastAddedTopicResponse( - mLastTopic, actor.getClass().getName(actor)); + Misc::StringUtils::lowerCase(mLastTopic), actor.getClass().getName(actor)); } } } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 40a24a1f8..81bd2f2b9 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -22,7 +22,6 @@ namespace MWDialogue { class DialogueManager : public MWBase::DialogueManager { - std::map mDialogueMap; std::set mKnownTopics;// Those are the topics the player knows. // Modified faction reactions. > @@ -56,6 +55,8 @@ namespace MWDialogue void executeTopic (const std::string& topic); + const ESM::Dialogue* searchDialogue(const std::string& id); + public: DialogueManager (const Compiler::Extensions& extensions, Translation::Storage& translationDataStorage); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 86aa64e8b..95fa042cf 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -223,7 +223,7 @@ namespace MWGui { MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); - MWBase::Environment::get().getDialogueManager()->keywordSelected(Misc::StringUtils::lowerCase(mTopicId)); + MWBase::Environment::get().getDialogueManager()->keywordSelected(mTopicId); } void Goodbye::activated() @@ -328,7 +328,7 @@ namespace MWGui } if (id >= separatorPos) - MWBase::Environment::get().getDialogueManager()->keywordSelected(Misc::StringUtils::lowerCase(topic)); + MWBase::Environment::get().getDialogueManager()->keywordSelected(topic); else { const MWWorld::Store &gmst = @@ -552,24 +552,7 @@ namespace MWGui void DialogueWindow::addResponse(const std::string &text, const std::string &title, bool needMargin) { - // This is called from the dialogue manager, so text is - // case-smashed - thus we have to retrieve the correct case - // of the title through the topic list. - std::string realTitle = title; - if (realTitle != "") - { - for (size_t i=0; igetItemCount(); ++i) - { - std::string item = mTopicsList->getItemNameAt(i); - if (Misc::StringUtils::ciEqual(item, title)) - { - realTitle = item; - break; - } - } - } - - mHistoryContents.push_back(new Response(text, realTitle, needMargin)); + mHistoryContents.push_back(new Response(text, title, needMargin)); updateHistory(); } From 19e07fad30bb43f0d474f9326fadbc44ab8b894a Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 19:52:20 +0200 Subject: [PATCH 183/505] Remove redundant Services enum --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 39 ------------------- apps/openmw/mwgui/dialogue.cpp | 20 ++++++---- apps/openmw/mwgui/dialogue.hpp | 16 -------- components/esm/loadnpc.hpp | 2 + 4 files changed, 14 insertions(+), 63 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index c29476c7f..dea942349 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -360,47 +360,8 @@ namespace MWDialogue } } - // check the available services of this actor - int services = mActor.getClass().getServices(mActor); - - int windowServices = 0; - - if (services & ESM::NPC::Weapon - || services & ESM::NPC::Armor - || services & ESM::NPC::Clothing - || services & ESM::NPC::Books - || services & ESM::NPC::Ingredients - || services & ESM::NPC::Picks - || services & ESM::NPC::Probes - || services & ESM::NPC::Lights - || services & ESM::NPC::Apparatus - || services & ESM::NPC::RepairItem - || services & ESM::NPC::Misc) - windowServices |= MWGui::DialogueWindow::Service_Trade; - - if((mActor.getTypeName() == typeid(ESM::NPC).name() && !mActor.get()->mBase->getTransport().empty()) - || (mActor.getTypeName() == typeid(ESM::Creature).name() && !mActor.get()->mBase->getTransport().empty())) - windowServices |= MWGui::DialogueWindow::Service_Travel; - - if (services & ESM::NPC::Spells) - windowServices |= MWGui::DialogueWindow::Service_BuySpells; - - if (services & ESM::NPC::Spellmaking) - windowServices |= MWGui::DialogueWindow::Service_CreateSpells; - - if (services & ESM::NPC::Training) - windowServices |= MWGui::DialogueWindow::Service_Training; - - if (services & ESM::NPC::Enchanting) - windowServices |= MWGui::DialogueWindow::Service_Enchant; - - if (services & ESM::NPC::Repair) - windowServices |= MWGui::DialogueWindow::Service_Repair; - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - win->setServices (windowServices); - // sort again, because the previous sort was case-sensitive keywordList.sort(Misc::StringUtils::ciLess); win->setKeywords(keywordList); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 95fa042cf..e4d0af424 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -237,7 +237,6 @@ namespace MWGui DialogueWindow::DialogueWindow() : WindowBase("openmw_dialogue_window.layout") - , mServices(0) , mEnabled(false) , mGoodbye(false) , mPersuasionDialog() @@ -411,6 +410,11 @@ namespace MWGui mTopicLinks.clear(); mKeywordSearch.clear(); + int services = mPtr.getClass().getServices(mPtr); + + bool travel = (mPtr.getTypeName() == typeid(ESM::NPC).name() && !mPtr.get()->mBase->getTransport().empty()) + || (mPtr.getTypeName() == typeid(ESM::Creature).name() && !mPtr.get()->mBase->getTransport().empty()); + bool isCompanion = !mPtr.getClass().getScript(mPtr).empty() && mPtr.getRefData().getLocals().getIntVar(mPtr.getClass().getScript(mPtr), "companion"); @@ -420,25 +424,25 @@ namespace MWGui if (mPtr.getTypeName() == typeid(ESM::NPC).name()) mTopicsList->addItem(gmst.find("sPersuasion")->getString()); - if (mServices & Service_Trade) + if (services & ESM::NPC::AllItems) mTopicsList->addItem(gmst.find("sBarter")->getString()); - if (mServices & Service_BuySpells) + if (services & ESM::NPC::Spells) mTopicsList->addItem(gmst.find("sSpells")->getString()); - if (mServices & Service_Travel) + if (services & travel) mTopicsList->addItem(gmst.find("sTravel")->getString()); - if (mServices & Service_CreateSpells) + if (services & ESM::NPC::Spellmaking) mTopicsList->addItem(gmst.find("sSpellmakingMenuTitle")->getString()); - if (mServices & Service_Enchant) + if (services & ESM::NPC::Enchanting) mTopicsList->addItem(gmst.find("sEnchanting")->getString()); - if (mServices & Service_Training) + if (services & ESM::NPC::Training) mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString()); - if (mServices & Service_Repair) + if (services & ESM::NPC::Repair) mTopicsList->addItem(gmst.find("sRepair")->getString()); if (isCompanion) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index dbb33969f..af5fe5efc 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -122,20 +122,6 @@ namespace MWGui void onFrame(float dt); void clear() { resetReference(); } - // make sure to call these before setKeywords() - void setServices(int services) { mServices = services; } - - enum Services - { - Service_Trade = 0x01, - Service_BuySpells = 0x02, - Service_CreateSpells = 0x04, - Service_Enchant = 0x08, - Service_Training = 0x10, - Service_Travel = 0x20, - Service_Repair = 0x40 - }; - protected: void onSelectTopic(const std::string& topic, int id); void onByeClicked(MyGUI::Widget* _sender); @@ -152,8 +138,6 @@ namespace MWGui void updateOptions(); void restock(); - int mServices; - bool mEnabled; bool mGoodbye; diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 019baa297..d7f30e079 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -43,6 +43,8 @@ struct NPC Misc = 0x00400, Potions = 0x02000, + AllItems = Weapon|Armor|Clothing|Books|Ingredients|Picks|Probes|Lights|Apparatus|RepairItem|Misc|Potions, + // Other services Spells = 0x00800, MagicItems = 0x01000, From e14573fa8c05f6e41cbfa74cb6c3a31c4d0f990c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 19:53:42 +0200 Subject: [PATCH 184/505] Add missing null check --- apps/openmw/mwgui/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index e4d0af424..920183c61 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -625,7 +625,7 @@ namespace MWGui void DialogueWindow::onFrame(float dt) { checkReferenceAvailable(); - if(mPtr.getTypeName() == typeid(ESM::NPC).name()) + if(!mPtr.isEmpty() && mPtr.getTypeName() == typeid(ESM::NPC).name()) { int disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr); mDispositionBar->setProgressRange(100); From 717e68fab21b4243118b06e61f74756cbdc1a130 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 19:58:34 +0200 Subject: [PATCH 185/505] Remove redundant resetHistory argument --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 5 +---- apps/openmw/mwgui/dialogue.cpp | 5 +++-- apps/openmw/mwgui/dialogue.hpp | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index dea942349..29bb49ca0 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -127,9 +127,6 @@ namespace MWDialogue MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - // If the dialogue window was already open, keep the existing history - bool resetHistory = (!MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Dialogue)); - //greeting const MWWorld::Store &dialogs = MWBase::Environment::get().getWorld()->getStore().get(); @@ -145,7 +142,7 @@ namespace MWDialogue { //initialise the GUI MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); - win->startDialogue(actor, actor.getClass().getName (actor), resetHistory); + win->startDialogue(actor, actor.getClass().getName (actor)); creatureStats.talkedToPlayer(); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 920183c61..4ec3da50b 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -283,6 +283,7 @@ namespace MWGui } else { + resetReference(); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); mTopicsList->scrollToTop(); return true; @@ -357,7 +358,7 @@ namespace MWGui } } - void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName, bool resetHistory) + void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) { MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); @@ -372,7 +373,7 @@ namespace MWGui mTopicsList->clear(); - if (resetHistory || !sameActor) + if (!sameActor) { for (std::vector::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) delete (*it); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index af5fe5efc..b854e6c1a 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -108,7 +108,7 @@ namespace MWGui void notifyLinkClicked (TypesetBook::InteractiveId link); - void startDialogue(MWWorld::Ptr actor, std::string npcName, bool resetHistory); + void startDialogue(MWWorld::Ptr actor, std::string npcName); void setKeywords(std::list keyWord); void addResponse (const std::string& text, const std::string& title="", bool needMargin = true); From 36c192a1ddf98efb6ee4cf551353708316c91ae8 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 21:03:52 +0200 Subject: [PATCH 186/505] Undo the console portion of 84657271c760 because it results in the console forgetting its object on opening --- apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwgui/console.cpp | 6 +++--- apps/openmw/mwgui/console.hpp | 5 +---- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 2 ++ 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 2df3113b3..51a17d380 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -151,6 +151,8 @@ namespace MWBase virtual void updateSpellWindow() = 0; + virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; + /// Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0; virtual void setValue (int parSkill, const MWMechanics::SkillValue& value) = 0; diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 182b6ef97..6094111f8 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -417,7 +417,7 @@ namespace MWGui setCoord(10,10, width-10, height/2); } - void Console::setPtr(const MWWorld::Ptr& object) + void Console::setSelectedObject(const MWWorld::Ptr& object) { if (!object.isEmpty()) { @@ -443,12 +443,12 @@ namespace MWGui void Console::onReferenceUnavailable() { - setPtr(MWWorld::Ptr()); + setSelectedObject(MWWorld::Ptr()); } void Console::resetReference() { ReferenceInterface::resetReference(); - setPtr(MWWorld::Ptr()); + setSelectedObject(MWWorld::Ptr()); } } diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index f243b8387..f5647e9ea 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -25,7 +25,7 @@ namespace MWGui { public: /// Set the implicit object for script execution - void setPtr(const MWWorld::Ptr& object); + void setSelectedObject(const MWWorld::Ptr& object); MyGUI::EditBox* mCommandLine; MyGUI::EditBox* mHistory; @@ -42,12 +42,9 @@ namespace MWGui virtual void onOpen(); virtual void onClose(); - void onFrame(float dt) { checkReferenceAvailable(); } - void setFont(const std::string &fntName); void onResChange(int width, int height); - void clear() { resetReference(); } // Print a message to the console, in specified color. void print(const std::string &msg, const std::string& color = "#FFFFFF"); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 779e358d3..1db2691f4 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -260,7 +260,7 @@ namespace MWGui MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); if (mode == GM_Console) - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Console, object); + MWBase::Environment::get().getWindowManager()->setConsoleSelectedObject(object); else if ((mode == GM_Container) || (mode == GM_Inventory)) { // pick up object diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 76f0b029d..85f57a75e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1884,6 +1884,11 @@ namespace MWGui mSpellWindow->updateSpells(); } + void WindowManager::setConsoleSelectedObject(const MWWorld::Ptr &object) + { + mConsole->setSelectedObject(object); + } + std::string WindowManager::correctIconPath(const std::string& path) { return Misc::ResourceHelpers::correctIconPath(path, mResourceSystem->getVFS()); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 56e7d9b7b..53b2dc33a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -190,6 +190,8 @@ namespace MWGui virtual void updateSpellWindow(); + virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); + ///< Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value); virtual void setValue (int parSkill, const MWMechanics::SkillValue& value); From e8c6a3b225828fac735ba7b409ddccc9446e7640 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 21:21:51 +0200 Subject: [PATCH 187/505] Fix crash in dialogue filter if local variables are not configured This could happen e.g. by 'some_npc_in_remote_cell->forcegreeting' --- apps/openmw/mwdialogue/filter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 67bb53e71..e8757e4a3 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -193,7 +193,8 @@ bool MWDialogue::Filter::testFunctionLocal(const MWDialogue::SelectWrapper& sele return false; // shouldn't happen, we checked that variable has a type above, so must exist const MWScript::Locals& locals = mActor.getRefData().getLocals(); - + if (locals.isEmpty()) + return select.selectCompare(0); switch (type) { case 's': return select.selectCompare (static_cast (locals.mShorts[index])); From c5613e384ea3dae8af6c6d8521e102a65424fb9c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 21:29:06 +0200 Subject: [PATCH 188/505] Remove duplicate disposition code --- apps/openmw/mwgui/dialogue.cpp | 17 ++++------------- apps/openmw/mwgui/dialogue.hpp | 2 +- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 4ec3da50b..869b83928 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -384,7 +384,7 @@ namespace MWGui delete (*it); mLinks.clear(); - updateOptions(); + updateDisposition(); restock(); } @@ -579,13 +579,10 @@ namespace MWGui updateHistory(); } - void DialogueWindow::updateOptions() + void DialogueWindow::updateDisposition() { - //Clear the list of topics - mTopicsList->clear(); - bool dispositionVisible = false; - if (mPtr.getClass().isNpc()) + if (!mPtr.isEmpty() && mPtr.getClass().isNpc()) { dispositionVisible = true; mDispositionBar->setProgressRange(100); @@ -626,12 +623,6 @@ namespace MWGui void DialogueWindow::onFrame(float dt) { checkReferenceAvailable(); - if(!mPtr.isEmpty() && mPtr.getTypeName() == typeid(ESM::NPC).name()) - { - int disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr); - mDispositionBar->setProgressRange(100); - mDispositionBar->setProgressPosition(disp); - mDispositionText->setCaption(MyGUI::utility::toString(disp)+std::string("/100")); - } + updateDisposition(); } } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index b854e6c1a..83f1eb1de 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -135,7 +135,7 @@ namespace MWGui virtual void onReferenceUnavailable(); private: - void updateOptions(); + void updateDisposition(); void restock(); bool mEnabled; From 476bec41c5c80c98981b491a6ca9593146c07901 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 21:47:35 +0200 Subject: [PATCH 189/505] Remove redundant code --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 29bb49ca0..ffa26e211 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -330,14 +330,12 @@ namespace MWDialogue updateGlobals(); std::list keywordList; - int choice = mChoice; - mChoice = -1; mActorKnownTopics.clear(); const MWWorld::Store &dialogs = MWBase::Environment::get().getWorld()->getStore().get(); - Filter filter (mActor, mChoice, mTalkedTo); + Filter filter (mActor, -1, mTalkedTo); for (MWWorld::Store::iterator iter = dialogs.begin(); iter != dialogs.end(); ++iter) { @@ -362,8 +360,6 @@ namespace MWDialogue // sort again, because the previous sort was case-sensitive keywordList.sort(Misc::StringUtils::ciLess); win->setKeywords(keywordList); - - mChoice = choice; } void DialogueManager::keywordSelected (const std::string& keyword) From 2ce79e07a461d4be141a4c5574474d7b9116467b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 21:38:38 +0200 Subject: [PATCH 190/505] Refactor dialogue GUI to talk to the dialogue manager, not the other way around and not both ways. - Fix memory leaks in DialogueWindow - Fix Link objects being deleted from their own event handler --- apps/openmw/mwbase/dialoguemanager.hpp | 21 ++- apps/openmw/mwbase/windowmanager.hpp | 1 - apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 125 +++++++------- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 24 ++- apps/openmw/mwgui/dialogue.cpp | 152 ++++++++++++------ apps/openmw/mwgui/dialogue.hpp | 39 +++-- apps/openmw/mwgui/enchantingdialog.cpp | 1 + apps/openmw/mwgui/tradewindow.cpp | 1 + apps/openmw/mwgui/trainingwindow.cpp | 1 + apps/openmw/mwgui/travelwindow.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 1 - apps/openmw/mwgui/windowmanagerimp.hpp | 1 - apps/openmw/mwscript/dialogueextensions.cpp | 5 +- apps/openmw/mwworld/actiontalk.cpp | 4 +- 14 files changed, 229 insertions(+), 148 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index 18f249e56..c928fa940 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -2,6 +2,8 @@ #define GAME_MWBASE_DIALOGUEMANAGER_H #include +#include +#include #include @@ -42,24 +44,29 @@ namespace MWBase virtual bool isInChoice() const = 0; - virtual void startDialogue (const MWWorld::Ptr& actor) = 0; + typedef std::pair Response; // title, text + virtual bool startDialogue (const MWWorld::Ptr& actor, Response& response) = 0; virtual void addTopic (const std::string& topic) = 0; - virtual void askQuestion (const std::string& question,int choice) = 0; + virtual void addChoice (const std::string& text,int choice) = 0; + virtual const std::vector >& getChoices() = 0; + + virtual bool isGoodbye() = 0; virtual void goodbye() = 0; virtual void say(const MWWorld::Ptr &actor, const std::string &topic) = 0; - //calbacks for the GUI - virtual void keywordSelected (const std::string& keyword) = 0; + virtual Response keywordSelected (const std::string& keyword) = 0; virtual void goodbyeSelected() = 0; - virtual void questionAnswered (int answer) = 0; + virtual Response questionAnswered (int answer) = 0; + + virtual std::list getAvailableTopics() = 0; - virtual bool checkServiceRefused () = 0; + virtual bool checkServiceRefused (Response& response) = 0; - virtual void persuade (int type) = 0; + virtual Response persuade (int type) = 0; virtual int getTemporaryDispositionChange () const = 0; /// @note This change is temporary and gets discarded when dialogue ends. diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 51a17d380..d8bce67e4 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -140,7 +140,6 @@ namespace MWBase virtual bool isAllowed (MWGui::GuiWindow wnd) const = 0; /// \todo investigate, if we really need to expose every single lousy UI element to the outside world - virtual MWGui::DialogueWindow* getDialogueWindow() = 0; virtual MWGui::InventoryWindow* getInventoryWindow() = 0; virtual MWGui::CountDialog* getCountDialog() = 0; virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index ffa26e211..4ed3b82a9 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -33,8 +34,6 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwgui/dialogue.hpp" - #include "../mwscript/compilercontext.hpp" #include "../mwscript/interpretercontext.hpp" #include "../mwscript/extensions.hpp" @@ -59,6 +58,7 @@ namespace MWDialogue { mChoice = -1; mIsInChoice = false; + mGoodbye = false; mCompilerContext.setExtensions (&extensions); } @@ -99,17 +99,15 @@ namespace MWDialogue if (mActorKnownTopics.count( topicId )) mKnownTopics.insert( topicId ); } - - updateTopics(); } - void DialogueManager::startDialogue (const MWWorld::Ptr& actor) + bool DialogueManager::startDialogue (const MWWorld::Ptr& actor, Response& response) { updateGlobals(); // Dialogue with dead actor (e.g. through script) should not be allowed. if (actor.getClass().getCreatureStats(actor).isDead()) - return; + return false; mLastTopic = ""; mPermanentDispositionChange = 0; @@ -117,6 +115,8 @@ namespace MWDialogue mChoice = -1; mIsInChoice = false; + mGoodbye = false; + mChoices.clear(); mActor = actor; @@ -125,8 +125,6 @@ namespace MWDialogue mActorKnownTopics.clear(); - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - //greeting const MWWorld::Store &dialogs = MWBase::Environment::get().getWorld()->getStore().get(); @@ -140,10 +138,6 @@ namespace MWDialogue // Search a response (we do not accept a fallback to "Info refusal" here) if (const ESM::DialInfo *info = filter.search (*it, false)) { - //initialise the GUI - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); - win->startDialogue(actor, actor.getClass().getName (actor)); - creatureStats.talkedToPlayer(); if (!info->mSound.empty()) @@ -152,29 +146,23 @@ namespace MWDialogue } // first topics update so that parseText knows the keywords to highlight - updateTopics(); + updateActorKnownTopics(); parseText (info->mResponse); MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), "", false); + response = Response ("", Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript, mActor); mLastTopic = it->mId; // update topics again to accommodate changes resulting from executeScript - updateTopics(); + updateActorKnownTopics(); - return; + return true; } } } - - // No greetings found. The dialogue window should not be shown. - // If this is a companion, we must show the companion window directly (used by BM_bear_be_unique). - bool isCompanion = !mActor.getClass().getScript(mActor).empty() - && mActor.getRefData().getLocals().getIntVar(mActor.getClass().getScript(mActor), "companion"); - if (isCompanion) - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, mActor); + return false; } bool DialogueManager::compile (const std::string& cmd, std::vector& code, const MWWorld::Ptr& actor) @@ -252,8 +240,9 @@ namespace MWDialogue } } - void DialogueManager::executeTopic (const std::string& topic) + DialogueManager::Response DialogueManager::executeTopic (const std::string& topic) { + DialogueManager::Response response; Filter filter (mActor, mChoice, mTalkedTo); const MWWorld::Store &dialogues = @@ -261,8 +250,6 @@ namespace MWDialogue const ESM::Dialogue& dialogue = *dialogues.find (topic); - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - const ESM::DialInfo* info = filter.search(dialogue, true); if (info) { @@ -287,7 +274,7 @@ namespace MWDialogue title = topic; MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), title); + response = Response(title, Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); if (dialogue.mType == ESM::Dialogue::Topic) { @@ -308,11 +295,7 @@ namespace MWDialogue mLastTopic = topic; } - else - { - // no response found, print a fallback text - win->addResponse ("…", topic); - } + return response; } const ESM::Dialogue *DialogueManager::searchDialogue(const std::string& id) @@ -325,11 +308,10 @@ namespace MWDialogue MWBase::Environment::get().getWorld()->updateDialogueGlobals(); } - void DialogueManager::updateTopics() + void DialogueManager::updateActorKnownTopics() { updateGlobals(); - std::list keywordList; mActorKnownTopics.clear(); const MWWorld::Store &dialogs = @@ -345,35 +327,42 @@ namespace MWDialogue { std::string lower = Misc::StringUtils::lowerCase(iter->mId); mActorKnownTopics.insert (lower); - - //does the player know the topic? - if (mKnownTopics.count(lower)) - { - keywordList.push_back (iter->mId); - } } } } - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + } + + std::list DialogueManager::getAvailableTopics() + { + updateActorKnownTopics(); + + std::list keywordList; + + for (const std::string& topic : mActorKnownTopics) + { + //does the player know the topic? + if (mKnownTopics.count(Misc::StringUtils::lowerCase(topic))) + keywordList.push_back(topic); + } // sort again, because the previous sort was case-sensitive keywordList.sort(Misc::StringUtils::ciLess); - win->setKeywords(keywordList); + return keywordList; } - void DialogueManager::keywordSelected (const std::string& keyword) + DialogueManager::Response DialogueManager::keywordSelected (const std::string& keyword) { + Response response; if(!mIsInChoice) { const ESM::Dialogue* dialogue = searchDialogue(keyword); if (dialogue && dialogue->mType == ESM::Dialogue::Topic) { - executeTopic (keyword); + response = executeTopic (keyword); } } - - updateTopics(); + return response; } bool DialogueManager::isInChoice() const @@ -383,8 +372,6 @@ namespace MWDialogue void DialogueManager::goodbyeSelected() { - MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); - // Apply disposition change to NPC's base disposition if (mActor.getClass().isNpc()) { @@ -400,9 +387,10 @@ namespace MWDialogue mTemporaryDispositionChange = 0; } - void DialogueManager::questionAnswered (int answer) + DialogueManager::Response DialogueManager::questionAnswered (int answer) { mChoice = answer; + DialogueManager::Response response; const ESM::Dialogue* dialogue = searchDialogue(mLastTopic); if (dialogue) @@ -418,10 +406,10 @@ namespace MWDialogue mChoice = -1; mIsInChoice = false; - MWBase::Environment::get().getWindowManager()->getDialogueWindow()->clearChoices(); + mChoices.clear(); MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse (Interpreter::fixDefinesDialog(text, interpreterContext)); + response = Response("", Interpreter::fixDefinesDialog(text, interpreterContext)); // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, // in which case it should not be added to the journal. @@ -441,32 +429,39 @@ namespace MWDialogue { mChoice = -1; mIsInChoice = false; - MWBase::Environment::get().getWindowManager()->getDialogueWindow()->clearChoices(); + mChoices.clear(); } } } - updateTopics(); + updateActorKnownTopics(); + return response; } - void DialogueManager::askQuestion (const std::string& question, int choice) + void DialogueManager::addChoice (const std::string& text, int choice) { mIsInChoice = true; - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - win->addChoice(question, choice); + mChoices.push_back(std::make_pair(text, choice)); } - void DialogueManager::goodbye() + const std::vector >& DialogueManager::getChoices() { - mIsInChoice = true; + return mChoices; + } - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + bool DialogueManager::isGoodbye() + { + return mGoodbye; + } - win->goodbye(); + void DialogueManager::goodbye() + { + mIsInChoice = false; + mGoodbye = true; } - void DialogueManager::persuade(int type) + DialogueManager::Response DialogueManager::persuade(int type) { bool success; float temp, perm; @@ -515,7 +510,7 @@ namespace MWDialogue text = "Bribe"; } - executeTopic (text + (success ? " Success" : " Fail")); + return executeTopic (text + (success ? " Success" : " Fail")); } int DialogueManager::getTemporaryDispositionChange() const @@ -528,7 +523,7 @@ namespace MWDialogue mTemporaryDispositionChange += delta; } - bool DialogueManager::checkServiceRefused() + bool DialogueManager::checkServiceRefused(Response& response) { Filter filter (mActor, mChoice, mTalkedTo); @@ -536,7 +531,6 @@ namespace MWDialogue MWBase::Environment::get().getWorld()->getStore().get(); const ESM::Dialogue& dialogue = *dialogues.find ("Service Refusal"); - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); std::vector infos = filter.list (dialogue, false, false, true); if (!infos.empty()) @@ -550,8 +544,7 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), - gmsts.find ("sServiceRefusal")->getString()); + response = Response(gmsts.find ("sServiceRefusal")->getString(), Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript, mActor); return true; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 81bd2f2b9..d9c622120 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -41,19 +41,22 @@ namespace MWDialogue int mChoice; std::string mLastTopic; // last topic ID, lowercase bool mIsInChoice; + bool mGoodbye; + + std::vector > mChoices; float mTemporaryDispositionChange; float mPermanentDispositionChange; void parseText (const std::string& text); - void updateTopics(); + void updateActorKnownTopics(); void updateGlobals(); bool compile (const std::string& cmd, std::vector& code, const MWWorld::Ptr& actor); void executeScript (const std::string& script, const MWWorld::Ptr& actor); - void executeTopic (const std::string& topic); + Response executeTopic (const std::string& topic); const ESM::Dialogue* searchDialogue(const std::string& id); @@ -65,24 +68,29 @@ namespace MWDialogue virtual bool isInChoice() const; - virtual void startDialogue (const MWWorld::Ptr& actor); + virtual bool startDialogue (const MWWorld::Ptr& actor, Response& response); + + std::list getAvailableTopics(); virtual void addTopic (const std::string& topic); - virtual void askQuestion (const std::string& question,int choice); + virtual void addChoice (const std::string& text,int choice); + const std::vector >& getChoices(); + + virtual bool isGoodbye(); virtual void goodbye(); - virtual bool checkServiceRefused (); + virtual bool checkServiceRefused (Response& response); virtual void say(const MWWorld::Ptr &actor, const std::string &topic); //calbacks for the GUI - virtual void keywordSelected (const std::string& keyword); + virtual Response keywordSelected (const std::string& keyword); virtual void goodbyeSelected(); - virtual void questionAnswered (int answer); + virtual Response questionAnswered (int answer); - virtual void persuade (int type); + virtual Response persuade (int type); virtual int getTemporaryDispositionChange () const; /// @note This change is temporary and gets discarded when dialogue ends. diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 869b83928..a7f18561e 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -68,7 +68,9 @@ namespace MWGui else /*if (sender == mBribe1000Button)*/ type = MWBase::MechanicsManager::PT_Bribe1000; - MWBase::Environment::get().getDialogueManager()->persuade(type); + MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->persuade(type); + + eventPersuadeMsg(response.first, response.second); setVisible(false); } @@ -214,30 +216,26 @@ namespace MWGui void Choice::activated() { - MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); - MWBase::Environment::get().getDialogueManager()->questionAnswered(mChoiceId); + eventChoiceActivated(mChoiceId); } void Topic::activated() { - MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); - MWBase::Environment::get().getDialogueManager()->keywordSelected(mTopicId); + eventTopicActivated(mTopicId); } void Goodbye::activated() { - MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + eventActivated(); } // -------------------------------------------------------------------------------------------------- DialogueWindow::DialogueWindow() : WindowBase("openmw_dialogue_window.layout") - , mEnabled(false) , mGoodbye(false) , mPersuasionDialog() { @@ -245,13 +243,14 @@ namespace MWGui center(); mPersuasionDialog.setVisible(false); + mPersuasionDialog.eventPersuadeMsg += MyGUI::newDelegate(this, &DialogueWindow::onPersuadeResult); //History view getWidget(mHistory, "History"); //Topics list getWidget(mTopicsList, "TopicsList"); - mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); + mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectListItem); getWidget(mGoodbyeButton, "ByeButton"); mGoodbyeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); @@ -269,15 +268,27 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); } + DialogueWindow::~DialogueWindow() + { + mPersuasionDialog.eventPersuadeMsg.clear(); + + deleteLater(); + for (Link* link : mLinks) + delete link; + for (auto link : mTopicLinks) + delete link.second; + for (auto history : mHistoryContents) + delete history; + } + void DialogueWindow::onTradeComplete() { - addResponse(MyGUI::LanguageManager::getInstance().replaceTags("#{sBarterDialog5}")); + addResponse("", MyGUI::LanguageManager::getInstance().replaceTags("#{sBarterDialog5}")); } bool DialogueWindow::exit() { - if ((!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) - && !mGoodbye) + if ((MWBase::Environment::get().getDialogueManager()->isInChoice())) { return false; } @@ -315,9 +326,9 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } - void DialogueWindow::onSelectTopic(const std::string& topic, int id) + void DialogueWindow::onSelectListItem(const std::string& topic, int id) { - if (!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) + if (mGoodbye || MWBase::Environment::get().getDialogueManager()->isInChoice()) return; int separatorPos = 0; @@ -328,17 +339,18 @@ namespace MWGui } if (id >= separatorPos) - MWBase::Environment::get().getDialogueManager()->keywordSelected(topic); + onTopicActivated(topic); else { const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); + MWBase::DialogueManager::Response response; if (topic == gmst.find("sPersuasion")->getString()) mPersuasionDialog.setVisible(true); else if (topic == gmst.find("sCompanionShare")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion, mPtr); - else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) + else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused(response)) { if (topic == gmst.find("sBarter")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter, mPtr); @@ -355,21 +367,30 @@ namespace MWGui else if (topic == gmst.find("sRepair")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair, mPtr); } + else + addResponse(response.first, response.second); } } - void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) + void DialogueWindow::setPtr(const MWWorld::Ptr& actor) { + MWBase::DialogueManager::Response response; + if (!MWBase::Environment::get().getDialogueManager()->startDialogue(actor, response)) + { + // No greetings found. The dialogue window should not be shown. + // If this is a companion, we must show the companion window directly (used by BM_bear_be_unique). + if (isCompanion()) + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, mPtr); + return; + } + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); mGoodbye = false; - mEnabled = true; bool sameActor = (mPtr == actor); mPtr = actor; mTopicsList->setEnabled(true); - setTitle(npcName); - - clearChoices(); + setTitle(mPtr.getClass().getName(mPtr)); mTopicsList->clear(); @@ -381,12 +402,13 @@ namespace MWGui } for (std::vector::iterator it = mLinks.begin(); it != mLinks.end(); ++it) - delete (*it); + mDeleteLater.push_back(*it); // Links are not deleted right away to prevent issues with event handlers mLinks.clear(); updateDisposition(); - restock(); + + addResponse(response.first, response.second, false); } void DialogueWindow::restock() @@ -403,11 +425,18 @@ namespace MWGui } } + void DialogueWindow::deleteLater() + { + for (Link* link : mDeleteLater) + delete link; + mDeleteLater.clear(); + } + void DialogueWindow::setKeywords(std::list keyWords) { mTopicsList->clear(); for (std::map::iterator it = mTopicLinks.begin(); it != mTopicLinks.end(); ++it) - delete it->second; + mDeleteLater.push_back(it->second); mTopicLinks.clear(); mKeywordSearch.clear(); @@ -416,9 +445,6 @@ namespace MWGui bool travel = (mPtr.getTypeName() == typeid(ESM::NPC).name() && !mPtr.get()->mBase->getTransport().empty()) || (mPtr.getTypeName() == typeid(ESM::Creature).name() && !mPtr.get()->mBase->getTransport().empty()); - bool isCompanion = !mPtr.getClass().getScript(mPtr).empty() - && mPtr.getRefData().getLocals().getIntVar(mPtr.getClass().getScript(mPtr), "companion"); - const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -446,7 +472,7 @@ namespace MWGui if (services & ESM::NPC::Repair) mTopicsList->addItem(gmst.find("sRepair")->getString()); - if (isCompanion) + if (isCompanion()) mTopicsList->addItem(gmst.find("sCompanionShare")->getString()); if (mTopicsList->getItemCount() > 0) @@ -458,6 +484,7 @@ namespace MWGui mTopicsList->addItem(*it); Topic* t = new Topic(*it); + t->eventTopicActivated += MyGUI::newDelegate(this, &DialogueWindow::onTopicActivated); mTopicLinks[Misc::StringUtils::lowerCase(*it)] = t; mKeywordSearch.seed(Misc::StringUtils::lowerCase(*it), intptr_t(t)); @@ -491,9 +518,11 @@ namespace MWGui typesetter->sectionBreak(9); // choices const TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); - for (std::vector >::iterator it = mChoices.begin(); it != mChoices.end(); ++it) + mChoices = MWBase::Environment::get().getDialogueManager()->getChoices(); + for (std::vector >::const_iterator it = mChoices.begin(); it != mChoices.end(); ++it) { Choice* link = new Choice(it->second); + link->eventChoiceActivated += MyGUI::newDelegate(this, &DialogueWindow::onChoiceActivated); mLinks.push_back(link); typesetter->lineBreak(); @@ -503,9 +532,11 @@ namespace MWGui typesetter->write(questionStyle, to_utf8_span(it->first.c_str())); } + mGoodbye = MWBase::Environment::get().getDialogueManager()->isGoodbye(); if (mGoodbye) { Goodbye* link = new Goodbye(); + link->eventActivated += MyGUI::newDelegate(this, &DialogueWindow::onGoodbyeActivated); mLinks.push_back(link); std::string goodbye = MWBase::Environment::get().getWorld()->getStore().get().find("sGoodbye")->getString(); BookTypesetter::Style* questionStyle = typesetter->createHotStyle(body, textColours.answer, textColours.answerOver, @@ -550,32 +581,40 @@ namespace MWGui reinterpret_cast(link)->activated(); } - void DialogueWindow::onScrollbarMoved(MyGUI::ScrollBar *sender, size_t pos) + void DialogueWindow::onTopicActivated(const std::string &topicId) { - mHistory->setPosition(0, static_cast(pos) * -1); + MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->keywordSelected(topicId); + addResponse(response.first, response.second); } - void DialogueWindow::addResponse(const std::string &text, const std::string &title, bool needMargin) + void DialogueWindow::onChoiceActivated(int id) { - mHistoryContents.push_back(new Response(text, title, needMargin)); - updateHistory(); + MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->questionAnswered(id); + addResponse(response.first, response.second); } - void DialogueWindow::addMessageBox(const std::string& text) + void DialogueWindow::onGoodbyeActivated() { - mHistoryContents.push_back(new Message(text)); - updateHistory(); + MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); + resetReference(); + } + + void DialogueWindow::onScrollbarMoved(MyGUI::ScrollBar *sender, size_t pos) + { + mHistory->setPosition(0, static_cast(pos) * -1); } - void DialogueWindow::addChoice(const std::string& choice, int id) + void DialogueWindow::addResponse(const std::string &title, const std::string &text, bool needMargin) { - mChoices.push_back(std::make_pair(choice, id)); + mHistoryContents.push_back(new Response(text, title, needMargin)); updateHistory(); + updateTopics(); } - void DialogueWindow::clearChoices() + void DialogueWindow::addMessageBox(const std::string& text) { - mChoices.clear(); + mHistoryContents.push_back(new Message(text)); updateHistory(); } @@ -608,13 +647,6 @@ namespace MWGui } } - void DialogueWindow::goodbye() - { - mGoodbye = true; - mEnabled = false; - updateHistory(); - } - void DialogueWindow::onReferenceUnavailable() { MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); @@ -623,6 +655,30 @@ namespace MWGui void DialogueWindow::onFrame(float dt) { checkReferenceAvailable(); + if (mPtr.isEmpty()) + return; + updateDisposition(); + deleteLater(); + + if (mChoices != MWBase::Environment::get().getDialogueManager()->getChoices() + || mGoodbye != MWBase::Environment::get().getDialogueManager()->isGoodbye()) + updateHistory(); + } + + void DialogueWindow::updateTopics() + { + setKeywords(MWBase::Environment::get().getDialogueManager()->getAvailableTopics()); + } + + bool DialogueWindow::isCompanion() + { + return !mPtr.getClass().getScript(mPtr).empty() + && mPtr.getRefData().getLocals().getIntVar(mPtr.getClass().getScript(mPtr), "companion"); + } + + void DialogueWindow::onPersuadeResult(const std::string &title, const std::string &text) + { + addResponse(title, text); } } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 83f1eb1de..c83906588 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -8,6 +8,8 @@ #include "../mwdialogue/keywordsearch.hpp" +#include + namespace Gui { class MWList; @@ -20,14 +22,14 @@ namespace MWGui namespace MWGui { - class DialogueHistoryViewModel; - class BookPage; - class PersuasionDialog : public WindowModal { public: PersuasionDialog(); + typedef MyGUI::delegates::CMultiDelegate2 EventHandle_Result; + EventHandle_Result eventPersuadeMsg; + virtual void onOpen(); private: @@ -53,6 +55,8 @@ namespace MWGui struct Topic : Link { + typedef MyGUI::delegates::CMultiDelegate1 EventHandle_TopicId; + EventHandle_TopicId eventTopicActivated; Topic(const std::string& id) : mTopicId(id) {} std::string mTopicId; virtual void activated (); @@ -60,6 +64,8 @@ namespace MWGui struct Choice : Link { + typedef MyGUI::delegates::CMultiDelegate1 EventHandle_ChoiceId; + EventHandle_ChoiceId eventChoiceActivated; Choice(int id) : mChoiceId(id) {} int mChoiceId; virtual void activated (); @@ -67,6 +73,8 @@ namespace MWGui struct Goodbye : Link { + typedef MyGUI::delegates::CMultiDelegate0 Event_Activated; + Event_Activated eventActivated; virtual void activated (); }; @@ -98,6 +106,7 @@ namespace MWGui { public: DialogueWindow(); + ~DialogueWindow(); void onTradeComplete(); @@ -108,25 +117,29 @@ namespace MWGui void notifyLinkClicked (TypesetBook::InteractiveId link); - void startDialogue(MWWorld::Ptr actor, std::string npcName); + void setPtr(const MWWorld::Ptr& actor); + void setKeywords(std::list keyWord); - void addResponse (const std::string& text, const std::string& title="", bool needMargin = true); + void addResponse (const std::string& title, const std::string& text, bool needMargin = true); void addMessageBox(const std::string& text); - void addChoice(const std::string& choice, int id); - void clearChoices(); - - void goodbye(); void onFrame(float dt); void clear() { resetReference(); } protected: - void onSelectTopic(const std::string& topic, int id); + void updateTopics(); + bool isCompanion(); + + void onPersuadeResult(const std::string& title, const std::string& text); + void onSelectListItem(const std::string& topic, int id); void onByeClicked(MyGUI::Widget* _sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); void onWindowResize(MyGUI::Window* _sender); + void onTopicActivated(const std::string& topicId); + void onChoiceActivated(int id); + void onGoodbyeActivated(); void onScrollbarMoved (MyGUI::ScrollBar* sender, size_t pos); @@ -137,17 +150,19 @@ namespace MWGui private: void updateDisposition(); void restock(); + void deleteLater(); bool mEnabled; - bool mGoodbye; - std::vector mHistoryContents; std::vector > mChoices; + bool mGoodbye; std::vector mLinks; std::map mTopicLinks; + std::vector mDeleteLater; + KeywordSearchT mKeywordSearch; BookPage* mHistory; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 74d80d292..6b0b33a0a 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -353,6 +353,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); return; } } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 341167ab7..939f70b59 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -323,6 +323,7 @@ namespace MWGui onCancelButtonClicked(mCancelButton); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); return; } } diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 120ab5cba..1081ee81e 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -197,6 +197,7 @@ namespace MWGui // go back to game mode MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } void TrainingWindow::onFrame(float dt) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 02df6bd8e..c9f19ad92 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -178,6 +178,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); // Teleports any followers, too. MWWorld::ActionTeleport action(interior ? cellname : "", pos, true); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 85f57a75e..f5825f08d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1288,7 +1288,6 @@ namespace MWGui mConsole->executeFile (path); } - MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 53b2dc33a..f6b2707ad 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -179,7 +179,6 @@ namespace MWGui virtual bool isAllowed(GuiWindow wnd) const; /// \todo investigate, if we really need to expose every single lousy UI element to the outside world - virtual MWGui::DialogueWindow* getDialogueWindow(); virtual MWGui::InventoryWindow* getInventoryWindow(); virtual MWGui::CountDialog* getCountDialog(); virtual MWGui::ConfirmationDialog* getConfirmationDialog(); diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index fcb7e8f3b..21d8d469b 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -11,6 +11,7 @@ #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/journal.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" #include "../mwmechanics/npcstats.hpp" @@ -116,7 +117,7 @@ namespace MWScript runtime.pop(); arg0 = arg0 -1; } - dialogue->askQuestion(question,choice); + dialogue->addChoice(question,choice); } } }; @@ -133,7 +134,7 @@ namespace MWScript if (!ptr.getRefData().isEnabled()) return; - MWBase::Environment::get().getDialogueManager()->startDialogue (ptr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue, ptr); } }; diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index 051380ff5..c7bb6a26e 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -1,7 +1,7 @@ #include "actiontalk.hpp" #include "../mwbase/environment.hpp" -#include "../mwbase/dialoguemanager.hpp" +#include "../mwbase/windowmanager.hpp" namespace MWWorld { @@ -9,6 +9,6 @@ namespace MWWorld void ActionTalk::executeImp (const Ptr& actor) { - MWBase::Environment::get().getDialogueManager()->startDialogue (getTarget()); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue, getTarget()); } } From cde2c1390002ac631f1279b5950770fd87b025c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Tue, 26 Sep 2017 14:14:28 +0200 Subject: [PATCH 191/505] make water depth independent of view frustum --- apps/openmw/mwrender/renderingmanager.cpp | 8 +++++- apps/openmw/mwrender/renderingmanager.hpp | 3 +++ apps/openmw/mwrender/water.cpp | 2 +- files/shaders/water_fragment.glsl | 32 ++++++++++++++--------- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5c22de12e..3a66c264b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -279,11 +279,14 @@ namespace MWRender mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); mFieldOfView = Settings::Manager::getFloat("field of view", "Camera"); mFirstPersonFieldOfView = Settings::Manager::getFloat("first person field of view", "Camera"); - updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip)); mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance)); + + mUniformNear = mRootNode->getOrCreateStateSet()->getUniform("near"); + mUniformFar = mRootNode->getOrCreateStateSet()->getUniform("far"); + updateProjectionMatrix(); } RenderingManager::~RenderingManager() @@ -889,6 +892,9 @@ namespace MWRender if (mFieldOfViewOverridden) fov = mFieldOfViewOverride; mViewer->getCamera()->setProjectionMatrixAsPerspective(fov, aspect, mNearClip, mViewDistance); + + mUniformNear->set(mNearClip); + mUniformFar->set(mViewDistance); } void RenderingManager::updateTextureFiltering() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index e575456d9..f0087e43d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -83,6 +83,9 @@ namespace MWRender SceneUtil::UnrefQueue* getUnrefQueue(); Terrain::World* getTerrain(); + osg::Uniform* mUniformNear; + osg::Uniform* mUniformFar; + void preloadCommonAssets(); double getReferenceTime() const; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 9679533be..68c07c1ab 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -112,7 +112,7 @@ class ClipCullNode : public osg::Group } // move the plane back along its normal a little bit to prevent bleeding at the water shore - const float clipFudge = -6; + const float clipFudge = -5; modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * clipFudge); cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 1e3a1e17b..9c8e56191 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -6,7 +6,7 @@ // tweakables -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -const float VISIBILITY = 1200.0; // how far you can look through water +const float VISIBILITY = 2.5; const float BIG_WAVES_X = 0.1; // strength of big waves const float BIG_WAVES_Y = 0.1; @@ -31,7 +31,7 @@ const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction const float SPEC_HARDNESS = 256.0; // specular highlights hardness -const float BUMP_SUPPRESS_DEPTH = 0.03; // at what water depth bumpmap will be supressed for reflections and refractions (prevents artifacts at shores) +const float BUMP_SUPPRESS_DEPTH = 0.3; // at what water depth bumpmap will be supressed for reflections and refractions (prevents artifacts at shores) const vec2 WIND_DIR = vec2(0.5f, -0.8f); const float WIND_SPEED = 0.2f; @@ -58,9 +58,9 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) return result; } -varying vec3 screenCoordsPassthrough; -varying vec4 position; -varying float depthPassthrough; +varying vec3 screenCoordsPassthrough; +varying vec4 position; +varying float depthPassthrough; uniform sampler2D normalMap; @@ -76,15 +76,18 @@ uniform float near; uniform float far; uniform vec3 nodePosition; -float linearizeDepth(float depth) // helper for transforming water depth +float frustumDepth; + +float linearizeDepth(float depth) // takes <0,1> non-linear depth value and returns <0,1> linearized value { float z_n = 2.0 * depth - 1.0; - depth = 2.0 * near * far / (far + near - z_n * (far - near)); - return depth - depthPassthrough; + depth = 2.0 * near * far / (far + near - z_n * frustumDepth); + return depth / frustumDepth; } void main(void) { + frustumDepth = abs(far - near); vec3 worldPos = position.xyz + nodePosition.xyz; vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; UV.y *= -1.0; @@ -157,8 +160,13 @@ void main(void) fresnel = clamp(fresnel, 0.0, 1.0); #if REFRACTION - float realWaterDepth = linearizeDepth(texture2D(refractionDepthMap, screenCoords).x); - float shore = clamp(realWaterDepth / (BUMP_SUPPRESS_DEPTH * (far - near)),0,1); + float normalization = frustumDepth / 1000; + float depthSample = linearizeDepth(texture2D(refractionDepthMap,screenCoords).x) * normalization; + float depthSampleDistorted = linearizeDepth(texture2D(refractionDepthMap,screenCoords-(normal.xy*REFR_BUMP)).x) * normalization; + float surfaceDepth = linearizeDepth(gl_FragCoord.z) * normalization; + float realWaterDepth = depthSample - surfaceDepth; // undistorted water depth in view direction, independent of frustum + + float shore = clamp(realWaterDepth / BUMP_SUPPRESS_DEPTH,0,1); #else float shore = 1.0; #endif @@ -180,10 +188,8 @@ void main(void) waterColor = waterColor * length(gl_LightModel.ambient.xyz); #if REFRACTION - float waterDepth = linearizeDepth(texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x); - if (cameraPos.z > 0.0) - refraction = mix(refraction, waterColor, clamp(waterDepth/VISIBILITY, 0.0, 1.0)); + refraction = mix(refraction, waterColor, clamp(depthSampleDistorted/VISIBILITY, 0.0, 1.0)); gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * gl_LightSource[0].specular.xyz; #else From 6062cd4b9c7a3a3e7f05d6f12f27db4b85c14ee7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 26 Sep 2017 13:28:15 +0400 Subject: [PATCH 192/505] Make physics framerate configurable --- apps/openmw/mwphysics/physicssystem.cpp | 7 ++++++- docs/source/reference/modding/settings/physics.rst | 13 +++++++++++++ files/settings-default.cfg | 4 ++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 docs/source/reference/modding/settings/physics.rst diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index ee368ad24..068ff3186 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include // FindRecIndexVisitor @@ -1357,7 +1358,11 @@ namespace MWPhysics mMovementResults.clear(); mTimeAccum += dt; - const float physicsDt = 1.f/60.0f; + + static const float physFramerate = Settings::Manager::getFloat("physics framerate", "Physics"); + + // Allow to use a physics framerate between 10 and 60 FPS + static const float physicsDt = 1.f / std::max(10.f, std::min(60.f, physFramerate)); const int maxAllowedSteps = 20; int numSteps = mTimeAccum / (physicsDt); diff --git a/docs/source/reference/modding/settings/physics.rst b/docs/source/reference/modding/settings/physics.rst new file mode 100644 index 000000000..e4f970a79 --- /dev/null +++ b/docs/source/reference/modding/settings/physics.rst @@ -0,0 +1,13 @@ +Physics Settings +################ + +physics framerate +--------------- + +:Type: floating point +:Range: 10.0 to 60.0 +:Default: 60.0 + +Allows to set how frequently an engine will do physics calculations. A default value is 60 times per second. +This setting allows developers with low-clocked CPUs to test an engine. +Changing from default value can lead to physics bugs. Change this setting on your own risk, and reset a value to default before filling a physics-related bugreport! diff --git a/files/settings-default.cfg b/files/settings-default.cfg index aec667a9c..f4c7f0a4a 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -277,6 +277,10 @@ camera y multiplier = 1.0 # Invert the vertical axis while not in GUI mode. invert y axis = false +[Physics] +# Framerate of the physics system +physics framerate = 60.0 + [Saves] # Name of last character played, and default for loading save files. From 9b91ea5d34413c674a637692a984046c0886b728 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 16:51:19 +0200 Subject: [PATCH 193/505] Exit drag-and-drop if dragged item is deleted (Fixes #3097) --- apps/openmw/mwgui/draganddrop.cpp | 6 ++++++ apps/openmw/mwgui/draganddrop.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 6 +----- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index fe0ad3374..d81b2ed00 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -121,6 +121,12 @@ void DragAndDrop::drop(ItemModel *targetModel, ItemView *targetView) mSourceView->update(); } +void DragAndDrop::onFrame() +{ + if (mIsOnDragAndDrop && mItem.mBase.getRefData().getCount() == 0) + finish(); +} + void DragAndDrop::finish() { mIsOnDragAndDrop = false; diff --git a/apps/openmw/mwgui/draganddrop.hpp b/apps/openmw/mwgui/draganddrop.hpp index a356fe4e2..dff8cd73c 100644 --- a/apps/openmw/mwgui/draganddrop.hpp +++ b/apps/openmw/mwgui/draganddrop.hpp @@ -29,6 +29,7 @@ namespace MWGui void startDrag (int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count); void drop (ItemModel* targetModel, ItemView* targetView); + void onFrame(); void finish(); }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index f5825f08d..7e3741ae6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -876,11 +876,7 @@ namespace MWGui MWBase::StateManager::State_NoGame) return; - if (mDragAndDrop->mIsOnDragAndDrop) - { - assert(mDragAndDrop->mDraggedWidget); - mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); - } + mDragAndDrop->onFrame(); updateMap(); From 62177ebb30a55a1cb8b62360ee0aa70056aa903c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 26 Sep 2017 21:19:53 +0400 Subject: [PATCH 194/505] Move physics framerate from setting to environment variable --- apps/openmw/mwphysics/physicssystem.cpp | 30 ++++++++++++------- apps/openmw/mwphysics/physicssystem.hpp | 2 ++ .../reference/modding/settings/physics.rst | 13 -------- files/settings-default.cfg | 4 --- 4 files changed, 22 insertions(+), 27 deletions(-) delete mode 100644 docs/source/reference/modding/settings/physics.rst diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 068ff3186..887189a85 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1,5 +1,6 @@ #include "physicssystem.hpp" +#include #include #include @@ -24,7 +25,6 @@ #include #include #include -#include #include // FindRecIndexVisitor @@ -684,6 +684,7 @@ namespace MWPhysics , mWaterHeight(0) , mWaterEnabled(false) , mParentNode(parentNode) + , mPhysicsDt(1.f / 60.f) { mResourceSystem->addResourceManager(mShapeManager.get()); @@ -696,6 +697,20 @@ namespace MWPhysics // Don't update AABBs of all objects every frame. Most objects in MW are static, so we don't need this. // Should a "static" object ever be moved, we have to update its AABB manually using DynamicsWorld::updateSingleAabb. mCollisionWorld->setForceUpdateAllAabbs(false); + + // Check if a user decided to override a physics system FPS + const char* env = getenv("OPENMW_PHYSICS_FPS"); + if (env) + { + std::string str(env); + + float physFramerate = std::atof(env); + if (physFramerate > 0) + { + mPhysicsDt = 1.f / physFramerate; + std::cerr << "Warning: physics framerate was overriden (a new value is " << physFramerate << ")." << std::endl; + } + } } PhysicsSystem::~PhysicsSystem() @@ -1359,16 +1374,11 @@ namespace MWPhysics mTimeAccum += dt; - static const float physFramerate = Settings::Manager::getFloat("physics framerate", "Physics"); - - // Allow to use a physics framerate between 10 and 60 FPS - static const float physicsDt = 1.f / std::max(10.f, std::min(60.f, physFramerate)); - const int maxAllowedSteps = 20; - int numSteps = mTimeAccum / (physicsDt); + int numSteps = mTimeAccum / (mPhysicsDt); numSteps = std::min(numSteps, maxAllowedSteps); - mTimeAccum -= numSteps * physicsDt; + mTimeAccum -= numSteps * mPhysicsDt; if (numSteps) { @@ -1417,7 +1427,7 @@ namespace MWPhysics bool positionChanged = false; for (int i=0; igetPtr(), physicActor, iter->second, physicsDt, + position = MovementSolver::move(position, physicActor->getPtr(), physicActor, iter->second, mPhysicsDt, flying, waterlevel, slowFall, mCollisionWorld, mStandingCollisions); if (position != physicActor->getPosition()) positionChanged = true; @@ -1426,7 +1436,7 @@ namespace MWPhysics if (positionChanged) mCollisionWorld->updateSingleAabb(physicActor->getCollisionObject()); - float interpolationFactor = mTimeAccum / physicsDt; + float interpolationFactor = mTimeAccum / mPhysicsDt; osg::Vec3f interpolated = position * interpolationFactor + physicActor->getPreviousPosition() * (1.f - interpolationFactor); float heightDiff = position.z() - oldHeight; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index aaf55e2b6..3ef9990f5 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -220,6 +220,8 @@ namespace MWPhysics osg::ref_ptr mParentNode; + float mPhysicsDt; + PhysicsSystem (const PhysicsSystem&); PhysicsSystem& operator= (const PhysicsSystem&); }; diff --git a/docs/source/reference/modding/settings/physics.rst b/docs/source/reference/modding/settings/physics.rst deleted file mode 100644 index e4f970a79..000000000 --- a/docs/source/reference/modding/settings/physics.rst +++ /dev/null @@ -1,13 +0,0 @@ -Physics Settings -################ - -physics framerate ---------------- - -:Type: floating point -:Range: 10.0 to 60.0 -:Default: 60.0 - -Allows to set how frequently an engine will do physics calculations. A default value is 60 times per second. -This setting allows developers with low-clocked CPUs to test an engine. -Changing from default value can lead to physics bugs. Change this setting on your own risk, and reset a value to default before filling a physics-related bugreport! diff --git a/files/settings-default.cfg b/files/settings-default.cfg index f4c7f0a4a..aec667a9c 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -277,10 +277,6 @@ camera y multiplier = 1.0 # Invert the vertical axis while not in GUI mode. invert y axis = false -[Physics] -# Framerate of the physics system -physics framerate = 60.0 - [Saves] # Name of last character played, and default for loading save files. From 60604ef5e8cb3939a716877823d5fa3f98903a00 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 23:07:58 +0000 Subject: [PATCH 195/505] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index d9782ccf3..8c84fd1ed 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -40,6 +40,7 @@ Programmers Chris Robinson (KittyCat) Cory F. Cohen (cfcohen) Cris Mihalache (Mirceam) + crussell187 darkf devnexen Dieho From 09e93319f5620278bfb2bd5957948118fe36faed Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 17:20:07 +0200 Subject: [PATCH 196/505] Restrict the 'fake mouse movement' workaround to where it's actually required (Fixes #3978) --- apps/openmw/mwinput/inputmanagerimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index b1f80cae6..cf52cbd18 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -366,8 +366,6 @@ namespace MWInput mInputManager->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible()); mInputManager->capture(disableEvents); - // inject some fake mouse movement to force updating MyGUI's widget states - MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); if (mControlsDisabled) { @@ -764,6 +762,8 @@ namespace MWInput mMouseWheel = int(arg.z); MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); + // FIXME: inject twice to force updating focused widget states (tooltips) resulting from changing the viewport by scroll wheel + MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); } if (mMouseLookEnabled && !mControlsDisabled) From fce9a14986e352af26270d814add9085c609c01c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 17:44:35 +0200 Subject: [PATCH 197/505] Hide the mouse cursor until it's used --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 12 +++++++++++- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++++ apps/openmw/mwinput/inputmanagerimp.cpp | 3 +++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index d8bce67e4..d454067c8 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -180,6 +180,7 @@ namespace MWBase virtual void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) = 0; virtual void setCursorVisible(bool visible) = 0; + virtual void setCursorActive(bool active) = 0; virtual void getMousePosition(int &x, int &y) = 0; virtual void getMousePosition(float &x, float &y) = 0; virtual void setDragDrop(bool dragDrop) = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7e3741ae6..8272568d3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -176,6 +176,7 @@ namespace MWGui , mWerewolfOverlayEnabled(Settings::Manager::getBool ("werewolf overlay", "GUI")) , mHudEnabled(true) , mCursorVisible(true) + , mCursorActive(false) , mPlayerName() , mPlayerRaceId() , mPlayerAttributes() @@ -1009,7 +1010,16 @@ namespace MWGui void WindowManager::setCursorVisible(bool visible) { + if (visible == mCursorVisible) + return; mCursorVisible = visible; + if (!visible) + mCursorActive = false; + } + + void WindowManager::setCursorActive(bool active) + { + mCursorActive = active; } void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result) @@ -1518,7 +1528,7 @@ namespace MWGui bool WindowManager::getCursorVisible() { - return mCursorVisible; + return mCursorVisible && mCursorActive; } void WindowManager::trackWindow(Layout *layout, const std::string &name) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index f6b2707ad..612470a7e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -320,6 +320,9 @@ namespace MWGui virtual bool getCursorVisible(); + /// Call when mouse cursor or buttons are used. + virtual void setCursorActive(bool active); + /// Clear all savegame-specific data virtual void clear(); @@ -447,6 +450,7 @@ namespace MWGui bool mWerewolfOverlayEnabled; bool mHudEnabled; bool mCursorVisible; + bool mCursorActive; void setCursorVisible(bool visible); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index cf52cbd18..6f0b3b1b4 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -718,6 +718,7 @@ namespace MWInput MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); } } + MWBase::Environment::get().getWindowManager()->setCursorActive(true); } setPlayerControlsEnabled(!guiMode); @@ -764,6 +765,8 @@ namespace MWInput MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); // FIXME: inject twice to force updating focused widget states (tooltips) resulting from changing the viewport by scroll wheel MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); + + MWBase::Environment::get().getWindowManager()->setCursorActive(true); } if (mMouseLookEnabled && !mControlsDisabled) From c88c535e0ecf786384d7b209a2446d65a37b3aaf Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 17:59:45 +0200 Subject: [PATCH 198/505] Fix HBox/VBox not using Client widget with MyGUI <= 3.2.2 --- components/widgets/box.cpp | 16 ++++++++++++++++ components/widgets/box.hpp | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/components/widgets/box.cpp b/components/widgets/box.cpp index eeddc22dd..a7bd573f4 100644 --- a/components/widgets/box.cpp +++ b/components/widgets/box.cpp @@ -238,6 +238,14 @@ namespace Gui align(); } + void HBox::initialiseOverride() + { + Base::initialiseOverride(); + MyGUI::Widget* client = 0; + assignWidget(client, "Client"); + setWidgetClient(client); + } + void HBox::onWidgetCreated(MyGUI::Widget* _widget) { align(); @@ -385,6 +393,14 @@ namespace Gui align(); } + void VBox::initialiseOverride() + { + Base::initialiseOverride(); + MyGUI::Widget* client = 0; + assignWidget(client, "Client"); + setWidgetClient(client); + } + MyGUI::IntSize VBox::getRequestedSize () { MyGUI::IntSize size(0,0); diff --git a/components/widgets/box.hpp b/components/widgets/box.hpp index 70f73ce42..467d4b82d 100644 --- a/components/widgets/box.hpp +++ b/components/widgets/box.hpp @@ -99,6 +99,8 @@ namespace Gui virtual void setCoord (const MyGUI::IntCoord &_value); protected: + virtual void initialiseOverride(); + virtual void align(); virtual MyGUI::IntSize getRequestedSize(); @@ -116,6 +118,8 @@ namespace Gui virtual void setCoord (const MyGUI::IntCoord &_value); protected: + virtual void initialiseOverride(); + virtual void align(); virtual MyGUI::IntSize getRequestedSize(); From 2514cc5cc8162e24b299ea9690562475bda57f42 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 18:20:24 +0200 Subject: [PATCH 199/505] Workaround key focus being reset in BookWindow when next/prev are hidden --- apps/openmw/mwgui/bookwindow.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index ae20b8e43..a86146f2f 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -1,6 +1,7 @@ #include "bookwindow.hpp" #include +#include #include @@ -153,20 +154,16 @@ namespace MWGui mLeftPageNumber->setCaption( MyGUI::utility::toString(mCurrentPage*2 + 1) ); mRightPageNumber->setCaption( MyGUI::utility::toString(mCurrentPage*2 + 2) ); - //If it is the last page, hide the button "Next Page" - if ( (mCurrentPage+1)*2 == mPages.size() - || (mCurrentPage+1)*2 == mPages.size() + 1) - { - mNextPageButton->setVisible(false); - } else { - mNextPageButton->setVisible(true); - } - //If it is the fist page, hide the button "Prev Page" - if (mCurrentPage == 0) { - mPrevPageButton->setVisible(false); - } else { - mPrevPageButton->setVisible(true); - } + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + bool nextPageVisible = (mCurrentPage+1)*2 < mPages.size(); + mNextPageButton->setVisible(nextPageVisible); + bool prevPageVisible = mCurrentPage != 0; + mPrevPageButton->setVisible(prevPageVisible); + + if (focus == mNextPageButton && !nextPageVisible && prevPageVisible) + MyGUI::InputManager::getInstance().setKeyFocusWidget(mPrevPageButton); + else if (focus == mPrevPageButton && !prevPageVisible && nextPageVisible) + MyGUI::InputManager::getInstance().setKeyFocusWidget(mNextPageButton); if (mPages.empty()) return; From a0ee1c563049216350ae8ed5c5678806de0567b7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 18:24:43 +0200 Subject: [PATCH 200/505] Fix order of buttons in book window layout for key cycling --- files/mygui/openmw_book.layout | 77 +++++++++++++++++----------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/files/mygui/openmw_book.layout b/files/mygui/openmw_book.layout index 7c158af8d..a7bea5eb5 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -5,49 +5,50 @@ - - - - - - - - + + + + + + + - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - - + + + From 010a7ea5b36ea6e412375fe94106ded92850fbf7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 18:33:32 +0200 Subject: [PATCH 201/505] Fix tooltip widgets being set to accept key focus --- apps/openmw/mwgui/tooltips.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 9b89c3957..a611b1f06 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -422,18 +422,20 @@ namespace MWGui std::string realImage = MWBase::Environment::get().getWindowManager()->correctIconPath(image); MyGUI::EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", MyGUI::IntCoord(0, 0, 300, 300), MyGUI::Align::Left | MyGUI::Align::Top, "ToolTipCaption"); - captionWidget->setProperty("Static", "true"); + captionWidget->setEditStatic(true); + captionWidget->setNeedKeyFocus(false); captionWidget->setCaptionWithReplacing(caption); MyGUI::IntSize captionSize = captionWidget->getTextSize(); int captionHeight = std::max(caption != "" ? captionSize.height : 0, imageSize); MyGUI::EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", MyGUI::IntCoord(0, captionHeight+imageCaptionVPadding, 300, 300-captionHeight-imageCaptionVPadding), MyGUI::Align::Stretch, "ToolTipText"); - textWidget->setProperty("Static", "true"); - textWidget->setProperty("MultiLine", "true"); - textWidget->setProperty("WordWrap", info.wordWrap ? "true" : "false"); + textWidget->setEditStatic(true); + textWidget->setEditMultiLine(true); + textWidget->setEditWordWrap(info.wordWrap); textWidget->setCaptionWithReplacing(text); textWidget->setTextAlign(MyGUI::Align::HCenter | MyGUI::Align::Top); + textWidget->setNeedKeyFocus(false); MyGUI::IntSize textSize = textWidget->getTextSize(); captionSize += MyGUI::IntSize(imageSize, 0); // adjust for image From b9341925f2947b31562d7eca9a3c95d6edc20fb6 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 18:33:41 +0200 Subject: [PATCH 202/505] Set AutoSizedEditBox as Static by default Would look very odd anyway to use it for editable text, with the widget resizing as you type. --- components/widgets/box.cpp | 7 +++++++ components/widgets/box.hpp | 3 +++ 2 files changed, 10 insertions(+) diff --git a/components/widgets/box.cpp b/components/widgets/box.cpp index a7bd573f4..bf18cef5b 100644 --- a/components/widgets/box.cpp +++ b/components/widgets/box.cpp @@ -66,6 +66,13 @@ namespace Gui notifySizeChange (this); } + void AutoSizedEditBox::initialiseOverride() + { + Base::initialiseOverride(); + setNeedKeyFocus(false); + setEditStatic(true); + } + void AutoSizedEditBox::setPropertyOverride(const std::string& _key, const std::string& _value) { if (_key == "ExpandDirection") diff --git a/components/widgets/box.hpp b/components/widgets/box.hpp index 467d4b82d..66be00719 100644 --- a/components/widgets/box.hpp +++ b/components/widgets/box.hpp @@ -39,9 +39,12 @@ namespace Gui MYGUI_RTTI_DERIVED( AutoSizedEditBox ) public: + virtual MyGUI::IntSize getRequestedSize(); virtual void setCaption(const MyGUI::UString& _value); + virtual void initialiseOverride(); + protected: virtual void setPropertyOverride(const std::string& _key, const std::string& _value); }; From 475ac46f3eb10bcb977387ccb1e084407229bdd3 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 19:22:23 +0200 Subject: [PATCH 203/505] Workaround keyfocus issues in current versions of MyGUI --- apps/openmw/mwgui/keyboardnavigation.cpp | 58 +++++++++++++++++++++++- apps/openmw/mwgui/keyboardnavigation.hpp | 4 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 2 + 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index da99c72d0..c9ad5a587 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" @@ -30,7 +31,13 @@ void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& resu } } +bool shouldAcceptKeyFocus(MyGUI::Widget* w) +{ + return w && !w->castType(false) && w->getInheritedEnabled() && w->getInheritedVisible() && w->getVisible() && w->getEnabled(); +} + KeyboardNavigation::KeyboardNavigation() + : mCurrentFocus(nullptr) { MyGUI::WidgetManager::getInstance().registerUnlinker(this); } @@ -42,7 +49,11 @@ KeyboardNavigation::~KeyboardNavigation() void KeyboardNavigation::saveFocus(int mode) { - mKeyFocus[mode] = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + if (shouldAcceptKeyFocus(focus)) + mKeyFocus[mode] = focus; + else + mKeyFocus[mode] = mCurrentFocus; } void KeyboardNavigation::restoreFocus(int mode) @@ -61,6 +72,51 @@ void KeyboardNavigation::_unlinkWidget(MyGUI::Widget *widget) for (std::pair& w : mKeyFocus) if (w.second == widget) w.second = nullptr; + if (widget == mCurrentFocus) + mCurrentFocus = nullptr; +} + +void styleFocusedButton(MyGUI::Widget* w) +{ + if (w) + { + if (MyGUI::Button* b = w->castType(false)) + { + b->_setWidgetState("highlighted"); + } + } +} + +void KeyboardNavigation::onFrame() +{ + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + + if (focus == mCurrentFocus) + { + styleFocusedButton(mCurrentFocus); + return; + } + + // workaround incorrect key focus resets (fix in MyGUI TBD) + if (!shouldAcceptKeyFocus(focus) && shouldAcceptKeyFocus(mCurrentFocus)) + { + MyGUI::InputManager::getInstance().setKeyFocusWidget(mCurrentFocus); + focus = mCurrentFocus; + } + + // style highlighted button (won't be needed for MyGUI 3.2.3) + if (focus != mCurrentFocus) + { + if (mCurrentFocus) + { + if (MyGUI::Button* b = mCurrentFocus->castType(false)) + b->_setWidgetState("normal"); + } + + mCurrentFocus = focus; + } + + styleFocusedButton(mCurrentFocus); } enum Direction diff --git a/apps/openmw/mwgui/keyboardnavigation.hpp b/apps/openmw/mwgui/keyboardnavigation.hpp index fff36d862..15aa0d6a8 100644 --- a/apps/openmw/mwgui/keyboardnavigation.hpp +++ b/apps/openmw/mwgui/keyboardnavigation.hpp @@ -21,6 +21,8 @@ namespace MWGui void _unlinkWidget(MyGUI::Widget* widget); + void onFrame(); + private: bool switchFocus(int direction, bool wrap); @@ -28,6 +30,8 @@ namespace MWGui bool accept(); std::map mKeyFocus; + + MyGUI::Widget* mCurrentFocus; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8272568d3..950b1edc3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -866,6 +866,8 @@ namespace MWGui if (!mCurrentModals.empty()) mCurrentModals.top()->onFrame(frameDuration); + mKeyboardNavigation->onFrame(); + mMessageBoxManager->onFrame(frameDuration); mToolTips->onFrame(frameDuration); From 41fe16013b5f7908964d7837f306bb333446b461 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 19:37:33 +0200 Subject: [PATCH 204/505] Select first widget if we can't find the current widget --- apps/openmw/mwgui/keyboardnavigation.cpp | 38 ++++++++++++++++-------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index c9ad5a587..d4d0a8c43 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -152,6 +152,21 @@ bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text) } } +bool selectFirstWidget() +{ + MyGUI::VectorWidgetPtr keyFocusList; + MyGUI::EnumeratorWidgetPtr enumerator = MyGUI::Gui::getInstance().getEnumerator(); + while (enumerator.next()) + getKeyFocusWidgets(enumerator.current(), keyFocusList); + + if (!keyFocusList.empty()) + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]); + return true; + } + return false; +} + bool KeyboardNavigation::switchFocus(int direction, bool wrap) { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); @@ -159,22 +174,14 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) if ((focus && focus->getTypeName().find("Button") == std::string::npos) && direction != D_Prev && direction != D_Next) return false; - if (focus && (direction == D_Prev || direction == D_Next) && focus->getUserString("AcceptTab") == "true") + bool isCycle = (direction == D_Prev || direction == D_Next); + if (focus && isCycle && focus->getUserString("AcceptTab") == "true") return false; - if ((!focus || !focus->getNeedKeyFocus()) && (direction == D_Next || direction == D_Prev)) + if ((!focus || !focus->getNeedKeyFocus()) && isCycle) { // if nothing is selected, select the first widget - MyGUI::VectorWidgetPtr keyFocusList; - MyGUI::EnumeratorWidgetPtr enumerator = MyGUI::Gui::getInstance().getEnumerator(); - while (enumerator.next()) - getKeyFocusWidgets(enumerator.current(), keyFocusList); - - if (!keyFocusList.empty()) - { - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]); - return true; - } + return selectFirstWidget(); } if (!focus) return false; @@ -190,7 +197,12 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) MyGUI::VectorWidgetPtr::iterator found = std::find(keyFocusList.begin(), keyFocusList.end(), focus); if (found == keyFocusList.end()) - return false; + { + if (isCycle) + return selectFirstWidget(); + else + return false; + } bool forward = (direction == D_Next || direction == D_Right || direction == D_Down); From 1714271a7692e884fa0337cc56ef9d5d5bf74236 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 22:21:30 +0200 Subject: [PATCH 205/505] Improve KeyboardNavigation to better handle modal windows It's no longer possible to cycle to widgets that aren't part of the current modal window. The window manager will remember the focused widget of a modal window on a limited basis (it'll be discarded when a different modal window opens). --- apps/openmw/mwgui/dialogue.cpp | 7 ++- apps/openmw/mwgui/dialogue.hpp | 2 + apps/openmw/mwgui/keyboardnavigation.cpp | 70 ++++++++++++++++++------ apps/openmw/mwgui/keyboardnavigation.hpp | 8 +++ apps/openmw/mwgui/windowbase.cpp | 5 +- apps/openmw/mwgui/windowbase.hpp | 2 + apps/openmw/mwgui/windowmanagerimp.cpp | 12 ++++ files/mygui/openmw_text.skin.xml | 1 + 8 files changed, 87 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index a7f18561e..b7da86f4e 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -77,7 +77,6 @@ namespace MWGui void PersuasionDialog::onOpen() { - WindowModal::onOpen(); center(); MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -88,6 +87,12 @@ namespace MWGui mBribe1000Button->setEnabled (playerGold >= 1000); mGoldLabel->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); + WindowModal::onOpen(); + } + + MyGUI::Widget* PersuasionDialog::getDefaultKeyFocus() + { + return mAdmireButton; } // -------------------------------------------------------------------------------------------------- diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index c83906588..6535ad4b2 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -32,6 +32,8 @@ namespace MWGui virtual void onOpen(); + virtual MyGUI::Widget* getDefaultKeyFocus(); + private: MyGUI::Button* mCancelButton; MyGUI::Button* mAdmireButton; diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index d4d0a8c43..6e1113a4f 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -38,6 +38,7 @@ bool shouldAcceptKeyFocus(MyGUI::Widget* w) KeyboardNavigation::KeyboardNavigation() : mCurrentFocus(nullptr) + , mModalWindow(nullptr) { MyGUI::WidgetManager::getInstance().registerUnlinker(this); } @@ -51,9 +52,13 @@ void KeyboardNavigation::saveFocus(int mode) { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); if (shouldAcceptKeyFocus(focus)) + { mKeyFocus[mode] = focus; + } else + { mKeyFocus[mode] = mCurrentFocus; + } } void KeyboardNavigation::restoreFocus(int mode) @@ -87,6 +92,13 @@ void styleFocusedButton(MyGUI::Widget* w) } } +bool isRootParent(MyGUI::Widget* widget, MyGUI::Widget* root) +{ + while (widget && widget->getParent()) + widget = widget->getParent(); + return widget == root; +} + void KeyboardNavigation::onFrame() { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); @@ -98,7 +110,7 @@ void KeyboardNavigation::onFrame() } // workaround incorrect key focus resets (fix in MyGUI TBD) - if (!shouldAcceptKeyFocus(focus) && shouldAcceptKeyFocus(mCurrentFocus)) + if (!shouldAcceptKeyFocus(focus) && shouldAcceptKeyFocus(mCurrentFocus) && (!mModalWindow || isRootParent(mCurrentFocus, mModalWindow))) { MyGUI::InputManager::getInstance().setKeyFocusWidget(mCurrentFocus); focus = mCurrentFocus; @@ -119,6 +131,25 @@ void KeyboardNavigation::onFrame() styleFocusedButton(mCurrentFocus); } +void KeyboardNavigation::setDefaultFocus(MyGUI::Widget *window, MyGUI::Widget *defaultFocus) +{ + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + if (!focus || !shouldAcceptKeyFocus(focus)) + { + MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus); + } + else + { + if (!isRootParent(focus, window)) + MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus); + } +} + +void KeyboardNavigation::setModalWindow(MyGUI::Widget *window) +{ + mModalWindow = window; +} + enum Direction { D_Left, @@ -152,29 +183,15 @@ bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text) } } -bool selectFirstWidget() -{ - MyGUI::VectorWidgetPtr keyFocusList; - MyGUI::EnumeratorWidgetPtr enumerator = MyGUI::Gui::getInstance().getEnumerator(); - while (enumerator.next()) - getKeyFocusWidgets(enumerator.current(), keyFocusList); - - if (!keyFocusList.empty()) - { - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]); - return true; - } - return false; -} - bool KeyboardNavigation::switchFocus(int direction, bool wrap) { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); - if ((focus && focus->getTypeName().find("Button") == std::string::npos) && direction != D_Prev && direction != D_Next) + bool isCycle = (direction == D_Prev || direction == D_Next); + + if ((focus && focus->getTypeName().find("Button") == std::string::npos) && !isCycle) return false; - bool isCycle = (direction == D_Prev || direction == D_Next); if (focus && isCycle && focus->getUserString("AcceptTab") == "true") return false; @@ -230,6 +247,23 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) return true; } +bool KeyboardNavigation::selectFirstWidget() +{ + MyGUI::VectorWidgetPtr keyFocusList; + MyGUI::EnumeratorWidgetPtr enumerator = MyGUI::Gui::getInstance().getEnumerator(); + if (mModalWindow) + enumerator = mModalWindow->getEnumerator(); + while (enumerator.next()) + getKeyFocusWidgets(enumerator.current(), keyFocusList); + + if (!keyFocusList.empty()) + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]); + return true; + } + return false; +} + bool KeyboardNavigation::accept() { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); diff --git a/apps/openmw/mwgui/keyboardnavigation.hpp b/apps/openmw/mwgui/keyboardnavigation.hpp index 15aa0d6a8..728f16a3d 100644 --- a/apps/openmw/mwgui/keyboardnavigation.hpp +++ b/apps/openmw/mwgui/keyboardnavigation.hpp @@ -23,15 +23,23 @@ namespace MWGui void onFrame(); + /// Set a key focus widget for this window, if one isn't already set. + void setDefaultFocus(MyGUI::Widget* window, MyGUI::Widget* defaultFocus); + + void setModalWindow(MyGUI::Widget* window); + private: bool switchFocus(int direction, bool wrap); + bool selectFirstWidget(); + /// Send button press event to focused button bool accept(); std::map mKeyFocus; MyGUI::Widget* mCurrentFocus; + MyGUI::Widget* mModalWindow; }; } diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index e563d9aa9..a0e7eedde 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -67,14 +67,17 @@ WindowModal::WindowModal(const std::string& parLayout) void WindowModal::onOpen() { - // Order important. We need to save the key focus widget before its unset MWBase::Environment::get().getWindowManager()->addCurrentModal(this); //Set so we can escape it if needed + + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); + MyGUI::InputManager::getInstance().setKeyFocusWidget(focus); } void WindowModal::onClose() { MWBase::Environment::get().getWindowManager()->removeCurrentModal(this); + MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); } diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index f183c97fe..56901c95a 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -23,6 +23,8 @@ namespace MWGui public: WindowBase(const std::string& parLayout); + virtual MyGUI::Widget* getDefaultKeyFocus() { return NULL; } + // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 950b1edc3..0b51b2b3f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1738,6 +1738,10 @@ namespace MWGui mKeyboardNavigation->saveFocus(getMode()); mCurrentModals.push(input); + mKeyboardNavigation->restoreFocus(-1); + + mKeyboardNavigation->setModalWindow(input->mMainWidget); + mKeyboardNavigation->setDefaultFocus(input->mMainWidget, input->getDefaultKeyFocus()); } void WindowManager::removeCurrentModal(WindowModal* input) @@ -1747,12 +1751,20 @@ namespace MWGui if(!mCurrentModals.empty()) { if(input == mCurrentModals.top()) + { mCurrentModals.pop(); + mKeyboardNavigation->saveFocus(-1); + } else std::cout << " warning: modal widget " << input << " " << typeid(input).name() << " not found " << std::endl; } if (mCurrentModals.empty()) + { + mKeyboardNavigation->setModalWindow(NULL); mKeyboardNavigation->restoreFocus(getMode()); + } + else + mKeyboardNavigation->setModalWindow(mCurrentModals.top()->mMainWidget); } void WindowManager::onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index 163b9d134..edc103443 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -81,6 +81,7 @@ color_misc=0,205,205 # ???? + From 22929e53fad10f2be52b67ccf77ab8e5d90c00b9 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 22:25:10 +0200 Subject: [PATCH 206/505] Don't ignore my own advice Can't wait until MyGUI 3.2.2 is a build dependency, then we can use key focus events to handle the SDL text input. --- apps/openmw/mwgui/bookwindow.cpp | 4 ++-- apps/openmw/mwgui/keyboardnavigation.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index a86146f2f..c18548dad 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -161,9 +161,9 @@ namespace MWGui mPrevPageButton->setVisible(prevPageVisible); if (focus == mNextPageButton && !nextPageVisible && prevPageVisible) - MyGUI::InputManager::getInstance().setKeyFocusWidget(mPrevPageButton); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mPrevPageButton); else if (focus == mPrevPageButton && !prevPageVisible && nextPageVisible) - MyGUI::InputManager::getInstance().setKeyFocusWidget(mNextPageButton); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNextPageButton); if (mPages.empty()) return; diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index 6e1113a4f..2b06de295 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -112,7 +112,7 @@ void KeyboardNavigation::onFrame() // workaround incorrect key focus resets (fix in MyGUI TBD) if (!shouldAcceptKeyFocus(focus) && shouldAcceptKeyFocus(mCurrentFocus) && (!mModalWindow || isRootParent(mCurrentFocus, mModalWindow))) { - MyGUI::InputManager::getInstance().setKeyFocusWidget(mCurrentFocus); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCurrentFocus); focus = mCurrentFocus; } @@ -136,12 +136,12 @@ void KeyboardNavigation::setDefaultFocus(MyGUI::Widget *window, MyGUI::Widget *d MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); if (!focus || !shouldAcceptKeyFocus(focus)) { - MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(defaultFocus); } else { if (!isRootParent(focus, window)) - MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(defaultFocus); } } From 44720bf41a1cae7a920dec6537abe7dfc15664dc Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 23:26:40 +0200 Subject: [PATCH 207/505] Allow MWList items to retain key focus --- components/widgets/list.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index c5a459f22..9318e32ed 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -72,6 +72,7 @@ namespace Gui button->getSubWidgetText()->setTextAlign(MyGUI::Align::Left); button->eventMouseWheel += MyGUI::newDelegate(this, &MWList::onMouseWheelMoved); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWList::onItemSelected); + button->setNeedKeyFocus(true); int height = button->getTextSize().height; button->setSize(MyGUI::IntSize(button->getSize().width, height)); From 7a64098da399e4853fe824f477b878eab01050c4 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 23:27:00 +0200 Subject: [PATCH 208/505] Avoid rebuilding the dialogue topics pane unnecessarily Also retaining key focus. --- apps/openmw/mwgui/dialogue.cpp | 16 +++++++++++++++- apps/openmw/mwgui/dialogue.hpp | 4 ++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index b7da86f4e..b726bf0d9 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -241,6 +241,7 @@ namespace MWGui DialogueWindow::DialogueWindow() : WindowBase("openmw_dialogue_window.layout") + , mIsCompanion(false) , mGoodbye(false) , mPersuasionDialog() { @@ -404,6 +405,9 @@ namespace MWGui for (std::vector::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) delete (*it); mHistoryContents.clear(); + + mKeywords.clear(); + updateTopicsPane(); } for (std::vector::iterator it = mLinks.begin(); it != mLinks.end(); ++it) @@ -438,6 +442,16 @@ namespace MWGui } void DialogueWindow::setKeywords(std::list keyWords) + { + if (mKeywords == keyWords && isCompanion() == mIsCompanion) + return; + mIsCompanion = isCompanion(); + mKeywords = keyWords; + + updateTopicsPane(); + } + + void DialogueWindow::updateTopicsPane() { mTopicsList->clear(); for (std::map::iterator it = mTopicLinks.begin(); it != mTopicLinks.end(); ++it) @@ -484,7 +498,7 @@ namespace MWGui mTopicsList->addSeparator(); - for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); ++it) + for(std::list::iterator it = mKeywords.begin(); it != mKeywords.end(); ++it) { mTopicsList->addItem(*it); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 6535ad4b2..97a0e8b37 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -132,6 +132,7 @@ namespace MWGui protected: void updateTopics(); + void updateTopicsPane(); bool isCompanion(); void onPersuadeResult(const std::string& title, const std::string& text); @@ -156,6 +157,9 @@ namespace MWGui bool mEnabled; + bool mIsCompanion; + std::list mKeywords; + std::vector mHistoryContents; std::vector > mChoices; bool mGoodbye; From 8964fc93d60341deb22cdbf702ba3c114b4034a2 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 23:27:53 +0200 Subject: [PATCH 209/505] Fix dialogue window not being exited properly --- apps/openmw/mwgui/companionwindow.cpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 5 +---- apps/openmw/mwgui/spellbuyingwindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 5 ++--- apps/openmw/mwgui/trainingwindow.cpp | 4 +--- apps/openmw/mwgui/travelwindow.cpp | 6 ++---- 6 files changed, 8 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 90ef32ced..739acee48 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -164,7 +164,7 @@ void CompanionWindow::onMessageBoxButtonClicked(int button) { MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion); // Important for Calvus' contract script to work properly - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } } diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 6b0b33a0a..3616b8b62 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -9,7 +9,6 @@ #include #include -#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -176,7 +175,6 @@ namespace MWGui void EnchantingDialog::onReferenceUnavailable () { - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); resetReference(); } @@ -352,8 +350,7 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, item, mPtr, 1); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); return; } } diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index aeb5cfbe5..d9c3a5f16 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -187,7 +187,7 @@ namespace MWGui { // remove both Spells and Dialogue (since you always trade with the NPC/creature that you have previously talked to) MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellBuying); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } void SpellBuyingWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 939f70b59..2eeeafe0d 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -322,8 +322,7 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, it->mBase, mPtr, it->mCount); onCancelButtonClicked(mCancelButton); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); return; } } @@ -503,7 +502,7 @@ namespace MWGui { // remove both Trade and Dialogue (since you always trade with the NPC/creature that you have previously talked to) MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } int TradeWindow::getMerchantGold() diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 1081ee81e..b6504d223 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -6,7 +6,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwbase/dialoguemanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -196,8 +195,7 @@ namespace MWGui // go back to game mode MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } void TrainingWindow::onFrame(float dt) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index c9f19ad92..7c7cdb63e 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -8,7 +8,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwbase/dialoguemanager.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/actorutil.hpp" @@ -177,8 +176,7 @@ namespace MWGui } MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); // Teleports any followers, too. MWWorld::ActionTeleport action(interior ? cellname : "", pos, true); @@ -208,7 +206,7 @@ namespace MWGui void TravelWindow::onReferenceUnavailable() { MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } void TravelWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) From 05814c092959ab9481c9453e7364216f2e278133 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 00:04:01 +0200 Subject: [PATCH 210/505] Add key focus handling for WaitDialog Default is 'until healed'. Up/Down arrows change the hour slider and implicitely change the button to 'Wait'. --- apps/openmw/mwgui/waitdialog.cpp | 22 ++++++++++++++++++++++ apps/openmw/mwgui/waitdialog.hpp | 1 + 2 files changed, 23 insertions(+) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 8a360435c..43c6f135a 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -1,6 +1,7 @@ #include "waitdialog.hpp" #include +#include #include @@ -72,6 +73,10 @@ namespace MWGui mWaitButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WaitDialog::onWaitButtonClicked); mHourSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &WaitDialog::onHourSliderChangedPosition); + mCancelButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &WaitDialog::onKeyButtonPressed); + mWaitButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &WaitDialog::onKeyButtonPressed); + mUntilHealedButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &WaitDialog::onKeyButtonPressed); + mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &WaitDialog::onWaitingProgressChanged); mTimeAdvancer.eventInterrupted += MyGUI::newDelegate(this, &WaitDialog::onWaitingInterrupted); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &WaitDialog::onWaitingFinished); @@ -80,6 +85,11 @@ namespace MWGui void WaitDialog::setPtr(const MWWorld::Ptr &ptr) { setCanRest(!ptr.isEmpty() || MWBase::Environment::get().getWorld ()->canRest () == 0); + + if (mUntilHealedButton->getVisible()) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mUntilHealedButton); + else + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mWaitButton); } bool WaitDialog::exit() @@ -195,6 +205,18 @@ namespace MWGui { mHourText->setCaptionWithReplacing (MyGUI::utility::toString(position+1) + " #{sRestMenu2}"); mManualHours = position+1; + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mWaitButton); + } + + void WaitDialog::onKeyButtonPressed(MyGUI::Widget *sender, MyGUI::KeyCode key, MyGUI::Char character) + { + if (key == MyGUI::KeyCode::ArrowDown) + mHourSlider->setScrollPosition(std::min(mHourSlider->getScrollPosition()+1, mHourSlider->getScrollRange()-1)); + else if (key == MyGUI::KeyCode::ArrowUp) + mHourSlider->setScrollPosition(std::max(static_cast(mHourSlider->getScrollPosition())-1, 0)); + else + return; + onHourSliderChangedPosition(mHourSlider, mHourSlider->getScrollPosition()); } void WaitDialog::onWaitingProgressChanged(int cur, int total) diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index c7ccee025..eb6a55640 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -65,6 +65,7 @@ namespace MWGui void onWaitButtonClicked(MyGUI::Widget* sender); void onCancelButtonClicked(MyGUI::Widget* sender); void onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position); + void onKeyButtonPressed(MyGUI::Widget* sender, MyGUI::KeyCode key, MyGUI::Char character); void onWaitingProgressChanged(int cur, int total); void onWaitingInterrupted(); From 7a3fbfb34ae918cf00badd32c3b0b45ac875c4ab Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 00:21:20 +0200 Subject: [PATCH 211/505] Slightly improve journal window keyboard navigation --- apps/openmw/mwgui/journalwindow.cpp | 40 ++++++++++++++++++++++++++--- files/mygui/openmw_journal.layout | 32 +++++++++++------------ 2 files changed, 52 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 3a67e857d..30a440b58 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -84,10 +85,16 @@ namespace void adviseButtonClick (char const * name, void (JournalWindowImpl::*Handler) (MyGUI::Widget* _sender)) { - getWidget (name) -> + getWidget (name) -> eventMouseButtonClick += newDelegate(this, Handler); } + void adviseKeyPress (char const * name, void (JournalWindowImpl::*Handler) (MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char character)) + { + getWidget (name) -> + eventKeyButtonPressed += newDelegate(this, Handler); + } + MWGui::BookPage* getPage (char const * name) { return getWidget (name); @@ -111,6 +118,12 @@ namespace adviseButtonClick (ShowAllBTN, &JournalWindowImpl::notifyShowAll ); adviseButtonClick (ShowActiveBTN, &JournalWindowImpl::notifyShowActive); + adviseKeyPress (OptionsBTN, &JournalWindowImpl::notifyKeyPress); + adviseKeyPress (PrevPageBTN, &JournalWindowImpl::notifyKeyPress); + adviseKeyPress (NextPageBTN, &JournalWindowImpl::notifyKeyPress); + adviseKeyPress (CloseBTN, &JournalWindowImpl::notifyKeyPress); + adviseKeyPress (JournalBTN, &JournalWindowImpl::notifyKeyPress); + Gui::MWList* list = getWidget(QuestsList); list->eventItemSelected += MyGUI::newDelegate(this, &JournalWindowImpl::notifyQuestClicked); @@ -237,6 +250,8 @@ namespace --page; } updateShowingPages(); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(getWidget(CloseBTN)); } void onClose() @@ -348,8 +363,19 @@ namespace relPages = 0; } - setVisible (PrevPageBTN, page > 0); - setVisible (NextPageBTN, relPages > 2); + MyGUI::Widget* nextPageBtn = getWidget(NextPageBTN); + MyGUI::Widget* prevPageBtn = getWidget(PrevPageBTN); + + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + bool nextPageVisible = relPages > 2; + nextPageBtn->setVisible(nextPageVisible); + bool prevPageVisible = page > 0; + prevPageBtn->setVisible(prevPageVisible); + + if (focus == nextPageBtn && !nextPageVisible && prevPageVisible) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(prevPageBtn); + else if (focus == prevPageBtn && !prevPageVisible && nextPageVisible) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(nextPageBtn); setVisible (PageOneNum, relPages > 0); setVisible (PageTwoNum, relPages > 1); @@ -361,6 +387,14 @@ namespace setText (PageTwoNum, page + 2); } + void notifyKeyPress(MyGUI::Widget* sender, MyGUI::KeyCode key, MyGUI::Char character) + { + if (key == MyGUI::KeyCode::ArrowUp) + notifyPrevPage(sender); + else if (key == MyGUI::KeyCode::ArrowDown) + notifyNextPage(sender); + } + void notifyTopicClicked (intptr_t linkId) { Book topicBook = createTopicBook (linkId); diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index 1131b1bbc..964b5ea95 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -3,32 +3,27 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + @@ -36,11 +31,14 @@ + + + From 879da9c69a6e7828a3e0d0bf1913e69e97629cbc Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 00:28:15 +0200 Subject: [PATCH 212/505] Add key focus for some more button skins --- files/mygui/openmw_text.skin.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index edc103443..5f96d0a57 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -66,6 +66,7 @@ color_misc=0,205,205 # ???? + @@ -97,6 +98,7 @@ color_misc=0,205,205 # ???? + @@ -104,6 +106,7 @@ color_misc=0,205,205 # ???? + From 87311d86b58193cc15018777585d45e1bf99a29c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 12:12:16 +0200 Subject: [PATCH 213/505] Fix what looks like a copy/paste error --- apps/openmw/mwgui/widgets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 744ef236f..45767bf01 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -105,7 +105,7 @@ namespace MWGui assignWidget(button, "StatValueButton"); if (button) { - mSkillNameWidget = button; + mSkillValueWidget = button; button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked); } } From 3d2ad2d3391aaf887010742afa45ce092a2157c6 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 12:40:47 +0200 Subject: [PATCH 214/505] Include cleanup --- apps/openmw/mwgui/alchemywindow.cpp | 3 +++ apps/openmw/mwgui/alchemywindow.hpp | 1 - apps/openmw/mwgui/companionwindow.cpp | 1 + apps/openmw/mwgui/companionwindow.hpp | 6 +++++- apps/openmw/mwgui/dialogue.cpp | 3 ++- apps/openmw/mwgui/recharge.cpp | 1 - apps/openmw/mwgui/repair.cpp | 2 -- apps/openmw/mwgui/savegamedialog.cpp | 1 - apps/openmw/mwgui/waitdialog.cpp | 3 +-- 9 files changed, 12 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 0140653a1..80284e9b2 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -1,6 +1,8 @@ #include "alchemywindow.hpp" #include +#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -19,6 +21,7 @@ #include "sortfilteritemmodel.hpp" #include "itemview.hpp" #include "itemwidget.hpp" +#include "widgets.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 2d13a346a..d1e54241a 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -5,7 +5,6 @@ #include "../mwmechanics/alchemy.hpp" -#include "widgets.hpp" #include "windowbase.hpp" namespace MWMechanics diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 739acee48..ad71be7df 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -13,6 +13,7 @@ #include "companionitemmodel.hpp" #include "draganddrop.hpp" #include "countdialog.hpp" +#include "widgets.hpp" namespace { diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 891106853..8ca350617 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -1,12 +1,16 @@ #ifndef OPENMW_MWGUI_COMPANIONWINDOW_H #define OPENMW_MWGUI_COMPANIONWINDOW_H -#include "widgets.hpp" #include "windowbase.hpp" #include "referenceinterface.hpp" namespace MWGui { + namespace Widgets + { + class MWDynamicStat; + } + class MessageBoxManager; class ItemView; class DragAndDrop; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index b726bf0d9..4e36fe117 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include @@ -20,7 +22,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/actorutil.hpp" -#include "widgets.hpp" #include "bookpage.hpp" #include "textcolours.hpp" diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 32da7876c..26a364f72 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -21,7 +21,6 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/actorutil.hpp" -#include "widgets.hpp" #include "itemwidget.hpp" #include "itemchargeview.hpp" #include "sortfilteritemmodel.hpp" diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index a461f7b3d..11a8aece2 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -17,8 +17,6 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" -#include "widgets.hpp" - #include "itemwidget.hpp" #include "itemchargeview.hpp" #include "sortfilteritemmodel.hpp" diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index e7c27b268..0e4ff1cf4 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -29,7 +29,6 @@ #include "../mwstate/character.hpp" #include "confirmationdialog.hpp" -#include "widgets.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 43c6f135a..a7ad687cb 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -24,8 +25,6 @@ #include "../mwstate/charactermanager.hpp" -#include "widgets.hpp" - namespace MWGui { From 74e806d9745e6f14be6cc4f04320586b3df3cace Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 13:14:26 +0200 Subject: [PATCH 215/505] Additionally use movement keys (default WASD) to navigate GUI buttons --- apps/openmw/mwinput/inputmanagerimp.cpp | 29 +++++++++++++++++++++++++ apps/openmw/mwinput/inputmanagerimp.hpp | 1 + 2 files changed, 30 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6f0b3b1b4..0637b6d83 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -174,6 +174,29 @@ namespace MWInput } } + void InputManager::handleGuiArrowKey(int action) + { + MyGUI::KeyCode key; + switch (action) + { + case A_MoveLeft: + key = MyGUI::KeyCode::ArrowLeft; + break; + case A_MoveRight: + key = MyGUI::KeyCode::ArrowRight; + break; + case A_MoveForward: + key = MyGUI::KeyCode::ArrowUp; + break; + case A_MoveBackward: + default: + key = MyGUI::KeyCode::ArrowDown; + break; + } + + MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0); + } + void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) { resetIdleTime (); @@ -235,6 +258,12 @@ namespace MWInput resetIdleTime(); activate(); break; + case A_MoveLeft: + case A_MoveRight: + case A_MoveForward: + case A_MoveBackward: + handleGuiArrowKey(action); + break; case A_Journal: toggleJournal (); break; diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 8809f44cd..cba7fc743 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -214,6 +214,7 @@ namespace MWInput void updateIdleTime(float dt); void setPlayerControlsEnabled(bool enabled); + void handleGuiArrowKey(int action); void updateCursorMode(); From c7a82704c6344ee62fd4a4848144b5f250fbf804 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 13:32:46 +0200 Subject: [PATCH 216/505] Fix key focus resets in SaveGameDialog --- apps/openmw/mwgui/savegamedialog.cpp | 12 ++++++++++++ apps/openmw/mwgui/savegamedialog.hpp | 2 ++ 2 files changed, 14 insertions(+) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 0e4ff1cf4..eb7f158d7 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -105,6 +105,11 @@ namespace MWGui } } + void SaveGameDialog::onDeleteSlotCancel() + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList); + } + void SaveGameDialog::onSaveNameChanged(MyGUI::EditBox *sender) { // This might have previously been a save slot from the list. If so, that is no longer the case @@ -225,6 +230,11 @@ namespace MWGui accept(true); } + void SaveGameDialog::onConfirmationCancel() + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList); + } + void SaveGameDialog::accept(bool reallySure) { // Remove for MyGUI 3.2.2 @@ -240,6 +250,7 @@ namespace MWGui dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationGiven); dialog->eventCancelClicked.clear(); + dialog->eventCancelClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationCancel); return; } if (mSaveNameEdit->getCaption().empty()) @@ -260,6 +271,7 @@ namespace MWGui dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationGiven); dialog->eventCancelClicked.clear(); + dialog->eventCancelClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationCancel); return; } } diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 39e3d310a..a51124705 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -37,10 +37,12 @@ namespace MWGui void onSlotMouseClick(MyGUI::ListBox* sender, size_t pos); void onDeleteSlotConfirmed(); + void onDeleteSlotCancel(); void onEditSelectAccept (MyGUI::EditBox* sender); void onSaveNameChanged (MyGUI::EditBox* sender); void onConfirmationGiven(); + void onConfirmationCancel(); void accept(bool reallySure=false); From 0ee57effcceaf6050a3b85c6b91cc63615c7400e Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 13:43:33 +0200 Subject: [PATCH 217/505] Make 'Delete game' button not accept keyfocus, to prevent accidents --- apps/openmw/mwgui/savegamedialog.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index eb7f158d7..423dbb036 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -57,6 +57,9 @@ namespace MWGui mSaveList->eventKeyButtonPressed += MyGUI::newDelegate(this, &SaveGameDialog::onKeyButtonPressed); mSaveNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onEditSelectAccept); mSaveNameEdit->eventEditTextChange += MyGUI::newDelegate(this, &SaveGameDialog::onSaveNameChanged); + + // To avoid accidental deletions + mDeleteButton->setNeedKeyFocus(false); } void SaveGameDialog::onSlotActivated(MyGUI::ListBox *sender, size_t pos) From f2146a2dc0164adfd078e20e5aee1cf6901cfab9 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 13:15:22 +0000 Subject: [PATCH 218/505] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 8c84fd1ed..02eb30da0 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -106,6 +106,7 @@ Programmers Michael Papageorgiou (werdanith) Michał Bień (Glorf) Michał Moroz (dragonee) + Miloslav Číž (drummyfish) Miroslav Puda (pakanek) MiroslavR Mitchell Schwitzer (schwitzerm) From 5c50506c83262bf82681a580e89a81ed7eb99eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Wed, 27 Sep 2017 17:13:21 +0200 Subject: [PATCH 219/505] water shader refactor plus basic rain ripples --- files/shaders/water_fragment.glsl | 113 +++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 19 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 9c8e56191..f7f87ce77 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -38,10 +38,85 @@ const float WIND_SPEED = 0.2f; const vec3 WATER_COLOR = vec3(0.090195, 0.115685, 0.12745); + + + + + + + + + + + + +const float RAIN_RIPPLE_GAPS = 5.0; +const float RAIN_RIPPLE_RADIUS = 0.1; + +int modulo(int v1, int v2) +{ + return v1 - v2 * int(floor(float(v1) / float(v2))); +} + +vec2 randOffset(vec2 c) +{ + return fract(vec2( + c.x * c.y / 8.0 + c.y * 0.3 + c.x * 0.2, + c.x * c.y / 14.0 + c.y * 0.5 + c.x * 0.7)); +} + +float randPhase(vec2 c) +{ + return fract((c.x * c.y) / (c.x + c.y + 0.1)); +} + +float circle(vec2 coords, vec2 i_part, float phase) +{ + float d = distance(vec2(0.5,0.5) + (0.5 - RAIN_RIPPLE_RADIUS) * (2.0 * randOffset(i_part) - 1.0),coords); + float r = RAIN_RIPPLE_RADIUS * phase; + + if (d > r) + return 0.0; + + float sinValue = (sin(d / r * 1.2) + 0.7) / 2.0; + + return (1.0 - abs(phase)) * pow(sinValue,3.0); +} + +float rain(vec2 uv, float time) +{ + vec2 i_part = floor(uv * RAIN_RIPPLE_GAPS); + vec2 f_part = fract(uv * RAIN_RIPPLE_GAPS); + return circle(f_part,i_part,fract(time * 1.2 + randPhase(i_part))); +} + +float rainCombined(vec2 uv, float time) +{ + return + rain(uv,time) + + rain(uv + vec2(10.5,5.7),time) + + rain(uv * 0.75 + vec2(3.7,18.9),time) + + rain(uv * 0.9 + vec2(5.7,30.1),time) + + rain(uv * 0.8 + vec2(1.2,3.0),time); +} + + + + + + + + + + + + + + // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) -{ + { float c = abs(dot(Incoming, Normal)); float g = eta * eta - 1.0 + c * c; float result; @@ -56,7 +131,12 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) result = 1.0; /* TIR (no refracted component) */ return result; -} + } + +vec2 normalCoords(vec2 uv, float scale, float speed, float time, float timer1, float timer2, vec3 previousNormal) + { + return uv * (WAVE_SCALE * scale) + WIND_DIR * time * (WIND_SPEED * speed) -(previousNormal.xy/previousNormal.zz) * WAVE_CHOPPYNESS + vec2(time * timer1,time * timer2); + } varying vec3 screenCoordsPassthrough; varying vec4 position; @@ -101,22 +181,12 @@ void main(void) #define waterTimer osg_SimulationTime - nCoord = UV * (WAVE_SCALE * 0.05) + WIND_DIR * waterTimer * (WIND_SPEED*0.04); - vec3 normal0 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.015,-waterTimer*0.005)).rgb - 1.0; - nCoord = UV * (WAVE_SCALE * 0.1) + WIND_DIR * waterTimer * (WIND_SPEED*0.08)-(normal0.xy/normal0.zz)*WAVE_CHOPPYNESS; - vec3 normal1 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.020,+waterTimer*0.015)).rgb - 1.0; - - nCoord = UV * (WAVE_SCALE * 0.25) + WIND_DIR * waterTimer * (WIND_SPEED*0.07)-(normal1.xy/normal1.zz)*WAVE_CHOPPYNESS; - vec3 normal2 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.04,-waterTimer*0.03)).rgb - 1.0; - nCoord = UV * (WAVE_SCALE * 0.5) + WIND_DIR * waterTimer * (WIND_SPEED*0.09)-(normal2.xy/normal2.z)*WAVE_CHOPPYNESS; - vec3 normal3 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.03,+waterTimer*0.04)).rgb - 1.0; - - nCoord = UV * (WAVE_SCALE* 1.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.4)-(normal3.xy/normal3.zz)*WAVE_CHOPPYNESS; - vec3 normal4 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.02,+waterTimer*0.1)).rgb - 1.0; - nCoord = UV * (WAVE_SCALE * 2.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.7)-(normal4.xy/normal4.zz)*WAVE_CHOPPYNESS; - vec3 normal5 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.1,-waterTimer*0.06)).rgb - 1.0; - - + vec3 normal0 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.05, 0.04, waterTimer, -0.015, -0.005, vec3(0.0,0.0,0.0))).rgb - 1.0; + vec3 normal1 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.1, 0.08, waterTimer, 0.02, 0.015, normal0)).rgb - 1.0; + vec3 normal2 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.25, 0.07, waterTimer, -0.04, -0.03, normal1)).rgb - 1.0; + vec3 normal3 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.5, 0.09, waterTimer, 0.03, 0.04, normal2)).rgb - 1.0; + vec3 normal4 = 2.0 * texture2D(normalMap,normalCoords(UV, 1.0, 0.4, waterTimer, -0.02, 0.1, normal3)).rgb - 1.0; + vec3 normal5 = 2.0 * texture2D(normalMap,normalCoords(UV, 2.0, 0.7, waterTimer, 0.1, -0.06, normal4)).rgb - 1.0; vec3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + @@ -126,6 +196,10 @@ void main(void) normal = vec3(-normal.x, -normal.y, normal.z); + float rainRipple = rainCombined(position.xy / 1000.0,osg_SimulationTime); + +//normal.y += 2 * rainRipple; + // normal for sunlight scattering vec3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + @@ -133,7 +207,6 @@ void main(void) lNormal = normalize(vec3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); lNormal = vec3(-lNormal.x, -lNormal.y, lNormal.z); - vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(gl_LightSource[0].position.xyz, 0.0)).xyz); vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0,0,0,1)).xyz; @@ -200,6 +273,8 @@ void main(void) float fogValue = clamp((depthPassthrough - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); +gl_FragData[0].xyz += vec3(rainRipple) * 0.2; + #if REFRACTION gl_FragData[0].w = 1.0; #else From 668a947210afe2d7cadd26a3ba9312aad0115f2b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 27 Sep 2017 20:00:41 +0400 Subject: [PATCH 220/505] Inherit owner, if an item is in container (regression #4128) --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 5d9ef726a..574444a8f 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1012,14 +1012,17 @@ namespace MWMechanics MWWorld::Ptr victim; + bool isAllowed = true; const MWWorld::CellRef* ownerCellRef = &item.getCellRef(); if (!container.isEmpty()) { // Inherit the owner of the container ownerCellRef = &container.getCellRef(); + isAllowed = isAllowedToUse(ptr, container, victim); } else { + isAllowed = isAllowedToUse(ptr, item, victim); if (!item.getCellRef().hasContentFile()) { // this is a manually placed item, which means it was already stolen @@ -1027,7 +1030,7 @@ namespace MWMechanics } } - if (isAllowedToUse(ptr, item, victim)) + if (isAllowed) return; Owner owner; From 4a332a180764af345d939c93b0ebda696b81c9ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Wed, 27 Sep 2017 21:25:14 +0200 Subject: [PATCH 221/505] improve rain ripples --- files/shaders/water_fragment.glsl | 69 ++++++++++++------------------- 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index f7f87ce77..23bd688ab 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -38,17 +38,7 @@ const float WIND_SPEED = 0.2f; const vec3 WATER_COLOR = vec3(0.090195, 0.115685, 0.12745); - - - - - - - - - - - +// ---------------- rain ripples related stuff --------------------- const float RAIN_RIPPLE_GAPS = 5.0; const float RAIN_RIPPLE_RADIUS = 0.1; @@ -70,27 +60,32 @@ float randPhase(vec2 c) return fract((c.x * c.y) / (c.x + c.y + 0.1)); } -float circle(vec2 coords, vec2 i_part, float phase) +vec4 circle(vec2 coords, vec2 i_part, float phase) { - float d = distance(vec2(0.5,0.5) + (0.5 - RAIN_RIPPLE_RADIUS) * (2.0 * randOffset(i_part) - 1.0),coords); + vec2 center = vec2(0.5,0.5) + (0.5 - RAIN_RIPPLE_RADIUS) * (2.0 * randOffset(i_part) - 1.0); + vec2 toCenter = coords - center; + float d = length(toCenter); float r = RAIN_RIPPLE_RADIUS * phase; if (d > r) - return 0.0; + return vec4(0.0,0.0,1.0,0.0); float sinValue = (sin(d / r * 1.2) + 0.7) / 2.0; + float height = (1.0 - abs(phase)) * pow(sinValue,3.0); + + vec3 normal = normalize(mix(vec3(0.0,0.0,1.0),vec3(normalize(toCenter),0.0),height)); - return (1.0 - abs(phase)) * pow(sinValue,3.0); + return vec4(normal,height); } -float rain(vec2 uv, float time) +vec4 rain(vec2 uv, float time) { vec2 i_part = floor(uv * RAIN_RIPPLE_GAPS); vec2 f_part = fract(uv * RAIN_RIPPLE_GAPS); return circle(f_part,i_part,fract(time * 1.2 + randPhase(i_part))); } -float rainCombined(vec2 uv, float time) +vec4 rainCombined(vec2 uv, float time) // returns ripple normal in xyz and ripple height in w { return rain(uv,time) + @@ -100,19 +95,6 @@ float rainCombined(vec2 uv, float time) rain(uv * 0.8 + vec2(1.2,3.0),time); } - - - - - - - - - - - - - // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) @@ -188,22 +170,24 @@ void main(void) vec3 normal4 = 2.0 * texture2D(normalMap,normalCoords(UV, 1.0, 0.4, waterTimer, -0.02, 0.1, normal3)).rgb - 1.0; vec3 normal5 = 2.0 * texture2D(normalMap,normalCoords(UV, 2.0, 0.7, waterTimer, 0.1, -0.06, normal4)).rgb - 1.0; + vec4 rainRipple = rainCombined(position.xy / 1000.0,waterTimer); + vec3 rippleAdd = rainRipple.xyz * rainRipple.w * 10.0; + vec3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + - normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y); + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y + + rippleAdd); normal = normalize(vec3(normal.x * BUMP, normal.y * BUMP, normal.z)); normal = vec3(-normal.x, -normal.y, normal.z); - float rainRipple = rainCombined(position.xy / 1000.0,osg_SimulationTime); - -//normal.y += 2 * rainRipple; - // normal for sunlight scattering vec3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + - normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1).xyz; + normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1 + + rippleAdd).xyz; + lNormal = normalize(vec3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); lNormal = vec3(-lNormal.x, -lNormal.y, lNormal.z); @@ -224,10 +208,10 @@ void main(void) float s = clamp(dot(lR, vVec)*2.0-1.2, 0.0, 1.0); float lightScatter = shadow * clamp(dot(lVec,lNormal)*0.7+0.3, 0.0, 1.0) * s * SCATTER_AMOUNT * sunFade * clamp(1.0-exp(-sunHeight), 0.0, 1.0); - vec3 scatterColour = mix(vec3(SCATTER_COLOUR)*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0)); + vec3 scatterColour = mix(vec3(SCATTER_COLOUR)*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0)); // fresnel - float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); //air to water; water to air + float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); // air to water; water to air float fresnel = fresnel_dielectric(vVec, normal, ior); fresnel = clamp(fresnel, 0.0, 1.0); @@ -243,12 +227,14 @@ void main(void) #else float shore = 1.0; #endif + vec2 screenCoordsOffset = ( (normal.xy + rainRipple.w * vec2(0.0,2.0)) * REFL_BUMP * shore); + // reflection - vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP*shore)).rgb; + vec3 reflection = texture2D(reflectionMap, screenCoords + screenCoordsOffset).rgb; // refraction #if REFRACTION - vec3 refraction = texture2D(refractionMap, screenCoords-(normal.xy*REFR_BUMP*shore)).rgb; + vec3 refraction = texture2D(refractionMap, screenCoords - screenCoordsOffset).rgb; // brighten up the refraction underwater refraction = (cameraPos.z < 0.0) ? clamp(refraction * 1.5, 0.0, 1.0) : refraction; @@ -268,12 +254,11 @@ void main(void) #else gl_FragData[0].xyz = mix(reflection, waterColor, (1.0-fresnel)*0.5) + specular * gl_LightSource[0].specular.xyz; #endif - // fog float fogValue = clamp((depthPassthrough - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); -gl_FragData[0].xyz += vec3(rainRipple) * 0.2; + gl_FragData[0].xyz += vec3(rainRipple.w) * 0.2; #if REFRACTION gl_FragData[0].w = 1.0; From 0240a6c38b3b62ea35ed84ce0b2903a89b8b1115 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 21:30:12 +0200 Subject: [PATCH 222/505] Fix controls window regression --- apps/openmw/mwinput/inputmanagerimp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 0637b6d83..e6acbbd52 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -697,7 +697,7 @@ namespace MWInput SDL_StopTextInput(); bool consumed = false; - if (kc != OIS::KC_UNASSIGNED) + if (kc != OIS::KC_UNASSIGNED && !mInputBinder->detectingBindingState()) { consumed = MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); if (SDL_IsTextInputActive() && // Little trick to check if key is printable @@ -726,7 +726,8 @@ namespace MWInput mJoystickLastUsed = false; OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); - setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); + if (!mInputBinder->detectingBindingState()) + setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); mInputBinder->keyReleased (arg); } From fb8306b61f66650bc5ce5421a17fa496c70822fe Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 21:30:31 +0200 Subject: [PATCH 223/505] Disable keyfocus for world map button Fixes 'Tab' no longer working as a keybinding for closing the inventory window. --- files/mygui/openmw_map_window.layout | 1 + 1 file changed, 1 insertion(+) diff --git a/files/mygui/openmw_map_window.layout b/files/mygui/openmw_map_window.layout index b38097dce..8d45022f8 100644 --- a/files/mygui/openmw_map_window.layout +++ b/files/mygui/openmw_map_window.layout @@ -31,6 +31,7 @@ + From a0f5e32113352217a372b040774a9a3292c79208 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 21:38:15 +0200 Subject: [PATCH 224/505] Fix 'new game' from the main menu not removing menu afterwards --- apps/openmw/mwgui/mainmenu.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 4e629403a..00e4e30a5 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -80,6 +80,7 @@ namespace MWGui void MainMenu::onNewGameConfirmed() { + MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_MainMenu); MWBase::Environment::get().getStateManager()->newGame(); } From db650df416991bd9485634cedb0b03eb12a67790 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 21:40:59 +0200 Subject: [PATCH 225/505] Fix 'blocking' messageboxes not handling key focus properly --- apps/openmw/mwgui/windowmanagerimp.cpp | 1 + files/mygui/openmw_interactive_messagebox_notransp.layout | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 0b51b2b3f..fbee52c82 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -773,6 +773,7 @@ namespace MWGui double dt = frameTimer.time_s(); frameTimer.setStartTick(); + mKeyboardNavigation->onFrame(); mMessageBoxManager->onFrame(dt); MWBase::Environment::get().getInputManager()->update(dt, true, false); diff --git a/files/mygui/openmw_interactive_messagebox_notransp.layout b/files/mygui/openmw_interactive_messagebox_notransp.layout index 6b79b9417..f5a462977 100644 --- a/files/mygui/openmw_interactive_messagebox_notransp.layout +++ b/files/mygui/openmw_interactive_messagebox_notransp.layout @@ -9,6 +9,7 @@ + From e9d81fdf5aa7bfa4f5f4c668473fb722e7f8050f Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 22:00:20 +0200 Subject: [PATCH 226/505] Fix being able to escape interactive messageboxes --- apps/openmw/mwgui/messagebox.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 38e6590b7..53b277416 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -77,6 +77,8 @@ namespace MWGui void mousePressed (MyGUI::Widget* _widget); int readPressedButton (); + virtual bool exit() { return false; } + bool mMarkedToDelete; private: From 0deda69a272813423518c406ee0fb6ceac563f79 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 22:04:36 +0200 Subject: [PATCH 227/505] Fix wrong skin for levelup attribute values --- apps/openmw/mwgui/levelupdialog.cpp | 4 +--- files/mygui/openmw_levelup_dialog.layout | 16 ++++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index a068d71f3..286405f79 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -41,6 +41,7 @@ namespace MWGui { MyGUI::TextBox* t; getWidget(t, "AttribVal" + MyGUI::utility::toString(i)); + mAttributeValues.push_back(t); MyGUI::Button* b; getWidget(b, "Attrib" + MyGUI::utility::toString(i)); @@ -48,10 +49,7 @@ namespace MWGui b->eventMouseButtonClick += MyGUI::newDelegate(this, &LevelupDialog::onAttributeClicked); mAttributes.push_back(b); - mAttributeValues.push_back(t); - getWidget(t, "AttribMultiplier" + MyGUI::utility::toString(i)); - mAttributeMultipliers.push_back(t); } diff --git a/files/mygui/openmw_levelup_dialog.layout b/files/mygui/openmw_levelup_dialog.layout index fc11ddfd7..66855373a 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 d53e7f8a3c836344176d8f7f5500dd3128d52b06 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 22:07:49 +0200 Subject: [PATCH 228/505] Remove redundant code Already worked around in WindowBase::setVisible --- apps/openmw/mwgui/console.cpp | 7 ------- apps/openmw/mwgui/console.hpp | 1 - 2 files changed, 8 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 6094111f8..2d016ddf1 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -152,13 +152,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine); } - void Console::onClose() - { - // Apparently, hidden widgets can retain key focus - // Remove for MyGUI 3.2.2 - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL); - } - void Console::setFont(const std::string &fntName) { mHistory->setFontName(fntName); diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index f5647e9ea..7ee39770d 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -40,7 +40,6 @@ namespace MWGui Console(int w, int h, bool consoleOnlyScripts); virtual void onOpen(); - virtual void onClose(); void setFont(const std::string &fntName); From 0ae009eb21eb2f079379320edb34fd2deb0d3a2a Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 22:18:47 +0200 Subject: [PATCH 229/505] Hide message box before deleting it Fixes a crash when closing the game window during the 'plugin mismatch' dialog. Modal windows have to be hidden before they are deleted to prevent a dangling pointer in WindowManager. --- apps/openmw/mwgui/messagebox.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index dd0495051..6c421de5e 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -36,8 +36,13 @@ namespace MWGui void MessageBoxManager::clear() { - delete mInterMessageBoxe; - mInterMessageBoxe = NULL; + if (mInterMessageBoxe) + { + mInterMessageBoxe->setVisible(false); + + delete mInterMessageBoxe; + mInterMessageBoxe = NULL; + } std::vector::iterator it(mMessageBoxes.begin()); for (; it != mMessageBoxes.end(); ++it) From 6ec66fa95fb64be4510c1c80777d0d7dfb1d614b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 28 Sep 2017 16:57:55 +0000 Subject: [PATCH 230/505] Restore keyfocus to goodbye when selecting a topic --- apps/openmw/mwgui/dialogue.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 4e36fe117..27a5003db 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -346,7 +346,10 @@ namespace MWGui } if (id >= separatorPos) + { onTopicActivated(topic); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); + } else { const MWWorld::Store &gmst = From 14c9e858c819adf667f7ef022a246c72fa6d9e60 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 28 Sep 2017 17:00:07 +0000 Subject: [PATCH 231/505] Check to make sure button is enabled --- apps/openmw/mwgui/dialogue.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 27a5003db..95fa00469 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -348,7 +348,8 @@ namespace MWGui if (id >= separatorPos) { onTopicActivated(topic); - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); + if (mGoodbyeButton->getEnabled()) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); } else { From 8416feaf5b302c3222df110a4e9a50bbaba6c02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 28 Sep 2017 19:04:31 +0200 Subject: [PATCH 232/505] link rain water ripple effect to actual rain --- apps/openmw/mwrender/renderingmanager.cpp | 5 +++++ apps/openmw/mwrender/renderingmanager.hpp | 1 + apps/openmw/mwrender/sky.cpp | 19 +++++++++++++++++-- apps/openmw/mwrender/sky.hpp | 1 + files/shaders/water_fragment.glsl | 12 +++++++++++- 5 files changed, 35 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3a66c264b..23fc4ec28 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -251,6 +251,10 @@ namespace MWRender sceneRoot->setNodeMask(Mask_Scene); sceneRoot->setName("Scene Root"); + mUniformRainIntensity = new osg::Uniform("rainIntensity",(float) 0.0); + + mRootNode->getOrCreateStateSet()->addUniform(mUniformRainIntensity); + mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager())); source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); @@ -799,6 +803,7 @@ namespace MWRender { mEffectManager->clear(); mWater->clearRipples(); + mUniformRainIntensity->set((float) 0.0); // for interiors } void RenderingManager::clear() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index f0087e43d..1673003c4 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -85,6 +85,7 @@ namespace MWRender osg::Uniform* mUniformNear; osg::Uniform* mUniformFar; + osg::Uniform* mUniformRainIntensity; void preloadCommonAssets(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index e6aa013ec..5bf5dbcb3 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1305,13 +1305,19 @@ public: std::vector > mAlphaFaders; }; -private: +protected: float mAlpha; }; class RainFader : public AlphaFader { public: + + RainFader(osg::Uniform *rainIntensityUniform): AlphaFader() + { + mRainIntensityUniform = rainIntensityUniform; + } + virtual void setDefaults(osg::StateSet* stateset) { osg::ref_ptr mat (new osg::Material); @@ -1320,6 +1326,15 @@ public: mat->setColorMode(osg::Material::OFF); stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); } + + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) + { + AlphaFader::apply(stateset,nv); + mRainIntensityUniform->set((float) (mAlpha * 2.0)); // mAlpha is limited to 0.6 so multiply by 2 to reach full intensity + } + +protected: + osg::Uniform* mRainIntensityUniform; }; void SkyManager::createRain() @@ -1375,7 +1390,7 @@ void SkyManager::createRain() mRainNode->addChild(mRainParticleSystem); mRainNode->addChild(updater); - mRainFader = new RainFader; + mRainFader = new RainFader(mRootNode->getParent(0)->getParent(0)->getStateSet()->getUniform("rainIntensity")); mRainNode->addUpdateCallback(mRainFader); mRainNode->addCullCallback(mUnderwaterSwitch); mRainNode->setNodeMask(Mask_WeatherParticles); diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 863ecc77d..8278c7101 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 23bd688ab..9da7abc01 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -65,12 +65,14 @@ vec4 circle(vec2 coords, vec2 i_part, float phase) vec2 center = vec2(0.5,0.5) + (0.5 - RAIN_RIPPLE_RADIUS) * (2.0 * randOffset(i_part) - 1.0); vec2 toCenter = coords - center; float d = length(toCenter); + float r = RAIN_RIPPLE_RADIUS * phase; if (d > r) return vec4(0.0,0.0,1.0,0.0); float sinValue = (sin(d / r * 1.2) + 0.7) / 2.0; + float height = (1.0 - abs(phase)) * pow(sinValue,3.0); vec3 normal = normalize(mix(vec3(0.0,0.0,1.0),vec3(normalize(toCenter),0.0),height)); @@ -138,6 +140,8 @@ uniform float near; uniform float far; uniform vec3 nodePosition; +uniform float rainIntensity; + float frustumDepth; float linearizeDepth(float depth) // takes <0,1> non-linear depth value and returns <0,1> linearized value @@ -170,7 +174,13 @@ void main(void) vec3 normal4 = 2.0 * texture2D(normalMap,normalCoords(UV, 1.0, 0.4, waterTimer, -0.02, 0.1, normal3)).rgb - 1.0; vec3 normal5 = 2.0 * texture2D(normalMap,normalCoords(UV, 2.0, 0.7, waterTimer, 0.1, -0.06, normal4)).rgb - 1.0; - vec4 rainRipple = rainCombined(position.xy / 1000.0,waterTimer); + vec4 rainRipple; + + if (rainIntensity > 0.01) + rainRipple = rainCombined(position.xy / 1000.0,waterTimer) * clamp(rainIntensity,0.0,1.0); + else + rainRipple = vec4(0.0,0.0,0.0,0.0); + vec3 rippleAdd = rainRipple.xyz * rainRipple.w * 10.0; vec3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + From c9c6326d8726a6c11cd5bff04732a142fbd9c119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 28 Sep 2017 19:23:37 +0200 Subject: [PATCH 233/505] fix non-refraction water rain ripples --- files/shaders/water_fragment.glsl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 9da7abc01..ee7ac6255 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -231,8 +231,7 @@ void main(void) float depthSample = linearizeDepth(texture2D(refractionDepthMap,screenCoords).x) * normalization; float depthSampleDistorted = linearizeDepth(texture2D(refractionDepthMap,screenCoords-(normal.xy*REFR_BUMP)).x) * normalization; float surfaceDepth = linearizeDepth(gl_FragCoord.z) * normalization; - float realWaterDepth = depthSample - surfaceDepth; // undistorted water depth in view direction, independent of frustum - + float realWaterDepth = depthSample - surfaceDepth; // undistorted water depth in view direction, independent of frustum float shore = clamp(realWaterDepth / BUMP_SUPPRESS_DEPTH,0,1); #else float shore = 1.0; @@ -268,11 +267,15 @@ void main(void) float fogValue = clamp((depthPassthrough - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); +#if REFRACTION gl_FragData[0].xyz += vec3(rainRipple.w) * 0.2; +#else + gl_FragData[0].xyz += vec3(rainRipple.w) * 0.7; +#endif #if REFRACTION gl_FragData[0].w = 1.0; #else - gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); + gl_FragData[0].w = clamp(fresnel*6.0 + specular, 0.0, 1.0); //clamp(fresnel*2.0 + specular, 0.0, 1.0); #endif } From 7bb0a76df2a2a2f1db5d92d0bf1f108d54b88745 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 28 Sep 2017 19:42:16 +0200 Subject: [PATCH 234/505] Fix tooltips showing when cursor isn't visible --- apps/openmw/mwgui/tooltips.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index a611b1f06..e6de9c42c 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -97,6 +97,8 @@ namespace MWGui if (guiMode) { + if (!MWBase::Environment::get().getWindowManager()->getCursorVisible()) + return; const MyGUI::IntPoint& mousePos = MyGUI::InputManager::getInstance().getMousePosition(); if (MWBase::Environment::get().getWindowManager()->getWorldMouseOver() && ((MWBase::Environment::get().getWindowManager()->getMode() == GM_Console) From 64793a55dc1ef9fc6faa2ad5bb62505a321d7595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 28 Sep 2017 20:44:43 +0200 Subject: [PATCH 235/505] get rid of buggy shader trick --- files/shaders/water_fragment.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index ee7ac6255..931422d5e 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -236,7 +236,7 @@ void main(void) #else float shore = 1.0; #endif - vec2 screenCoordsOffset = ( (normal.xy + rainRipple.w * vec2(0.0,2.0)) * REFL_BUMP * shore); + vec2 screenCoordsOffset = normal.xy * REFL_BUMP * shore; // reflection vec3 reflection = texture2D(reflectionMap, screenCoords + screenCoordsOffset).rgb; From 5b10e3128eda8a2d914d2e46efd9f333caebfbf4 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 29 Sep 2017 14:58:25 +0000 Subject: [PATCH 236/505] Use first resolution in fullscreen if current is not supported (Fixes #4113) --- apps/openmw/mwgui/settingswindow.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index c239fc12f..9bf6e4385 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -353,24 +353,31 @@ namespace MWGui } bool supported = false; + int fallbackX = 0, fallbackY = 0; for (unsigned int i=0; igetItemCount(); ++i) { std::string resStr = mResolutionList->getItemNameAt(i); int resX, resY; parseResolution (resX, resY, resStr); + if (i == 0) + { + fallbackX = resX; + fallbackY = resY; + } + if (resX == Settings::Manager::getInt("resolution x", "Video") && resY == Settings::Manager::getInt("resolution y", "Video")) supported = true; } - if (!supported) + if (!supported && mResolutionList->getItemCount()) { - std::string msg = "This resolution is not supported in Fullscreen mode. Please select a resolution from the list."; - MWBase::Environment::get().getWindowManager()-> - messageBox(msg); - _sender->castType()->setCaption(off); - return; + if (fallbackX != 0 && fallbackY != 0) + { + Settings::Manager::setInt("resolution x", "Video", fallbackX); + Settings::Manager::setInt("resolution y", "Video", fallbackY); + } } mWindowBorderButton->setEnabled(!newState); From 4999c667b62654ba580bcd9cdb9ebeb784f5797d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 29 Sep 2017 19:56:16 +0200 Subject: [PATCH 237/505] fix rain ripple bug --- apps/openmw/mwrender/renderingmanager.cpp | 9 ++++++++- apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwrender/sky.cpp | 10 ++++++++++ apps/openmw/mwrender/sky.hpp | 4 ++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 23fc4ec28..3826fd5f6 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -504,6 +504,9 @@ namespace MWRender mWater->update(dt); } + if (!mSky->isEnabled() || !mSky->hasRain()) + clearRainRipples(); + mCamera->update(dt, paused); osg::Vec3f focal, cameraPos; @@ -803,7 +806,11 @@ namespace MWRender { mEffectManager->clear(); mWater->clearRipples(); - mUniformRainIntensity->set((float) 0.0); // for interiors + } + + void RenderingManager::clearRainRipples() + { + mUniformRainIntensity->set((float) 0.0); } void RenderingManager::clear() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 1673003c4..43059ab6d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -160,6 +160,8 @@ namespace MWRender /// Clear all worldspace-specific data void notifyWorldSpaceChanged(); + void clearRainRipples(); + void update(float dt, bool paused); Animation* getAnimation(const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 5bf5dbcb3..178c753c6 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1431,6 +1431,16 @@ int SkyManager::getSecundaPhase() const return mSecunda->getPhaseInt(); } +bool SkyManager::isEnabled() +{ + return mEnabled; +} + +bool SkyManager::hasRain() +{ + return mRainNode != NULL; +} + void SkyManager::update(float duration) { if (!mEnabled) return; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 8278c7101..59a8ddc4e 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -138,6 +138,10 @@ namespace MWRender void sunDisable(); + bool isEnabled(); + + bool hasRain(); + void setRainSpeed(float speed); void setStormDirection(const osg::Vec3f& direction); From 03daf2b9e3bf08737dd84614874ce2e43a09b982 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 29 Sep 2017 22:28:09 +0400 Subject: [PATCH 238/505] Fix a failed assert in the getCell() check during a new game start --- apps/openmw/mwworld/worldimp.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2a25d5bbc..9c7fba9fa 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2118,7 +2118,9 @@ namespace MWWorld pos.z() += heightRatio*2*mPhysics->getRenderingHalfExtents(object).z(); - return isUnderwater(object.getCell(), pos); + const CellStore *currCell = object.isInCell() ? object.getCell() : NULL; // currCell == NULL should only happen for player, during initial startup + + return isUnderwater(currCell, pos); } bool World::isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const From dfcbee3ab162e5c7ff8809bb753dafc083848548 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 30 Sep 2017 00:04:52 -0400 Subject: [PATCH 239/505] Ignore case when comparing textures, also add new textures to lookup map. --- apps/opencs/model/world/idtable.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 54d65ac3f..bde5af3d9 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,5 +1,7 @@ #include "idtable.hpp" +#include +#include #include #include #include @@ -346,8 +348,10 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import for (int i = 0; i < idCollection()->getSize(); ++i) { auto& record = static_cast&>(idCollection()->getRecord(i)); + std::string texture = record.get().mTexture; + std::transform(texture.begin(), texture.end(), texture.begin(), tolower); if (record.isModified()) - reverseLookupMap.emplace(record.get().mTexture, idCollection()->getId(i)); + reverseLookupMap.emplace(texture, idCollection()->getId(i)); } for (const std::string& id : ids) @@ -366,7 +370,9 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import // Look for a pre-existing record auto& record = static_cast&>(idCollection()->getRecord(oldRow)); - auto searchIt = reverseLookupMap.find(record.get().mTexture); + std::string texture = record.get().mTexture; + std::transform(texture.begin(), texture.end(), texture.begin(), tolower); + auto searchIt = reverseLookupMap.find(texture); if (searchIt != reverseLookupMap.end()) { results.recordMapping.push_back(std::make_pair(id, searchIt->second)); @@ -385,6 +391,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import cloneRecord(id, newId, UniversalId::Type_LandTexture); results.createdRecords.push_back(newId); results.recordMapping.push_back(std::make_pair(id, newId)); + reverseLookupMap.emplace(texture, newId); break; } From 097b9d90bc101a0a55eced4baed9acf423e611f1 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 30 Sep 2017 16:53:39 +0200 Subject: [PATCH 240/505] Fix travel service not showing --- apps/openmw/mwgui/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 95fa00469..8dd027c4a 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -481,7 +481,7 @@ namespace MWGui if (services & ESM::NPC::Spells) mTopicsList->addItem(gmst.find("sSpells")->getString()); - if (services & travel) + if (travel) mTopicsList->addItem(gmst.find("sTravel")->getString()); if (services & ESM::NPC::Spellmaking) From 3c62a8c5c29fe5b1d0ed0531bee39a52f517735f Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 30 Sep 2017 16:57:07 +0200 Subject: [PATCH 241/505] Fix console selected object persisting on a new game --- apps/openmw/mwgui/console.cpp | 5 +++++ apps/openmw/mwgui/console.hpp | 2 ++ 2 files changed, 7 insertions(+) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 2d016ddf1..e8ac33f6d 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -215,6 +215,11 @@ namespace MWGui } } + void Console::clear() + { + resetReference(); + } + void Console::keyPress(MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char _char) diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 7ee39770d..bbff34c8d 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -60,6 +60,8 @@ namespace MWGui void executeFile (const std::string& path); + void clear(); + virtual void resetReference (); protected: From 04452b094963d8cbe1e453d9344d8407c4cf11f8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 20:11:53 +0400 Subject: [PATCH 242/505] Use a pickpocket crime instead of theft when pickpocketing was failed --- apps/openmw/mwgui/container.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 57c756762..a70d833c7 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -136,7 +136,7 @@ namespace MWGui bool loot = mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead(); - if (mPtr.getTypeName() == typeid(ESM::NPC).name() && !loot) + if (mPtr.getClass().isNpc() && !loot) { // we are stealing stuff MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -271,9 +271,8 @@ namespace MWGui MWMechanics::Pickpocket pickpocket(player, mPtr); if (pickpocket.pick(item.mBase, count)) { - int value = item.mBase.getClass().getValue(item.mBase) * count; MWBase::Environment::get().getMechanicsManager()->commitCrime( - player, mPtr, MWBase::MechanicsManager::OT_Theft, value, true); + player, mPtr, MWBase::MechanicsManager::OT_Pickpocket, 0, true); MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); mPickpocketDetected = true; return false; From 34895157f91e25f2990afa59e2d4572ff837db37 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 20:22:26 +0400 Subject: [PATCH 243/505] Consider taking items from unconscious NPC as a theft --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwgui/tooltips.hpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 23 +++++++++++++++---- .../mwmechanics/mechanicsmanagerimp.hpp | 4 ++-- 6 files changed, 25 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index d9068b285..398439ad8 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -238,7 +238,7 @@ namespace MWBase /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::ConstPtr& item, MWWorld::Ptr& victim) = 0; + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) = 0; /// Turn actor into werewolf or normal form. virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf) = 0; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index e6de9c42c..a9930db4f 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -325,7 +325,7 @@ namespace MWGui } } - void ToolTips::setFocusObject(const MWWorld::ConstPtr& focus) + void ToolTips::setFocusObject(const MWWorld::Ptr& focus) { mFocusObject = focus; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index bb2affc63..2793e6544 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -59,7 +59,7 @@ namespace MWGui void setDelay(float delay); - void setFocusObject(const MWWorld::ConstPtr& focus); + void setFocusObject(const MWWorld::Ptr& focus); void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); ///< set the screen-space position of the tooltip for focused object @@ -96,7 +96,7 @@ namespace MWGui private: MyGUI::Widget* mDynamicToolTipBox; - MWWorld::ConstPtr mFocusObject; + MWWorld::Ptr mFocusObject; MyGUI::IntSize getToolTipViaPtr (int count, bool image=true); ///< @return requested tooltip size diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index fbee52c82..e96743b91 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1573,7 +1573,7 @@ namespace MWGui mMessageBoxManager->clear(); - mToolTips->setFocusObject(MWWorld::ConstPtr()); + mToolTips->setFocusObject(MWWorld::Ptr()); mSelectedSpell.clear(); mCustomMarkers.clear(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 574444a8f..950cf8a01 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -840,17 +840,30 @@ namespace MWMechanics mAI = true; } - bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::ConstPtr& item, MWWorld::Ptr& victim) + bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) { - const MWWorld::CellRef& cellref = item.getCellRef(); + const MWWorld::CellRef& cellref = target.getCellRef(); // there is no harm to use unlocked doors - if (item.getClass().isDoor() && cellref.getLockLevel() <= 0 && ptr.getCellRef().getTrap().empty()) + if (target.getClass().isDoor() && cellref.getLockLevel() <= 0 && ptr.getCellRef().getTrap().empty()) return true; - // TODO: implement a better check to check if item is owned bed - if (item.getClass().isActivator() && item.getClass().getScript(item).compare(0, 3, "Bed") != 0) + // TODO: implement a better check to check if target is owned bed + if (target.getClass().isActivator() && target.getClass().getScript(target).compare(0, 3, "Bed") != 0) return true; + if (target.getClass().isNpc()) + { + if (target.getClass().getCreatureStats(target).isDead()) + return true; + + // check if a player tries to pickpocket a target NPC + if(ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak) + || target.getClass().getCreatureStats(target).getKnockedDown()) + return false; + + return true; + } + const std::string& owner = cellref.getOwner(); bool isOwned = !owner.empty() && owner != "player"; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 1bf3a8d22..ee4cf28af 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -204,8 +204,8 @@ namespace MWMechanics /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); - /// @return is \a ptr allowed to take/use \a cellref or is it a crime? - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::ConstPtr& item, MWWorld::Ptr& victim); + /// @return is \a ptr allowed to take/use \a target or is it a crime? + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim); virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf); virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor); From 3ebb18ce18b89407464f388c00fb36455500be36 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 20:31:06 +0400 Subject: [PATCH 244/505] Make unconscious actors do not report about crimes --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 950cf8a01..525749c38 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1097,6 +1097,10 @@ namespace MWMechanics if (it->getClass().getCreatureStats(*it).isDead()) continue; + // Unconsious actor can not report about crime + if (it->getClass().getCreatureStats(*it).getKnockedDown()) + continue; + if ((*it == victim && victimAware) || (MWBase::Environment::get().getWorld()->getLOS(player, *it) && awarenessCheck(player, *it) ) // Murder crime can be reported even if no one saw it (hearing is enough, I guess). @@ -1208,12 +1212,16 @@ namespace MWMechanics // Tell everyone (including the original reporter) in alarm range for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { - if ( *it == player + if (*it == player || !it->getClass().isNpc() || it->getClass().getCreatureStats(*it).isDead()) continue; if (it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(victim)) continue; + // Unconsious actor can not report about crime and should not become hostile + if (it->getClass().getCreatureStats(*it).getKnockedDown()) + continue; + // Player's followers should not attack player, or try to arrest him if (it->getClass().getCreatureStats(*it).getAiSequence().hasPackage(AiPackage::TypeIdFollow)) { From f26206b63026253e91993003a69bc29dbb9acb19 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 20:55:42 +0400 Subject: [PATCH 245/505] Make unconscious actors do not speak and do not track targets --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 6 ++++++ apps/openmw/mwmechanics/actors.cpp | 14 +++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 4ed3b82a9..6fac03e92 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -567,6 +567,12 @@ namespace MWDialogue return; } + if (actor.getClass().getCreatureStats(actor).getKnockedDown()) + { + // Unconscious actors can not speak + return; + } + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const ESM::Dialogue *dial = store.get().find(topic); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index cef429504..d0fe5a755 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1232,13 +1232,17 @@ namespace MWMechanics float sqrHeadTrackDistance = std::numeric_limits::max(); MWWorld::Ptr headTrackTarget; - for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it) + // Unconsious actor can not track target + if (!iter->first.getClass().getCreatureStats(iter->first).getKnockedDown()) { - if (it->first == iter->first) - continue; - updateHeadTracking(iter->first, it->first, headTrackTarget, sqrHeadTrackDistance); + for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it) + { + if (it->first == iter->first) + continue; + updateHeadTracking(iter->first, it->first, headTrackTarget, sqrHeadTrackDistance); + } + iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget); } - iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget); } if (iter->first.getClass().isNpc() && iter->first != player) From b8fd530ee1111372f34f6e084fd0b966eb7c9dd0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 21:20:38 +0400 Subject: [PATCH 246/505] Do not speak with unconscious creatures --- apps/openmw/mwclass/creature.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index d6926f11d..2e16b13aa 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -470,6 +470,9 @@ namespace MWClass if(stats.getAiSequence().isInCombat()) return std::shared_ptr(new MWWorld::FailedAction("")); + if(stats.getKnockedDown()) + return std::shared_ptr(new MWWorld::FailedAction("")); + return std::shared_ptr(new MWWorld::ActionTalk(ptr)); } From c5fcb9684efe3c0b41a0d7901af4887d7b9ca003 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 21:29:02 +0400 Subject: [PATCH 247/505] Improve owned crosshair feature behaviour --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 525749c38..da98e7f5f 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -856,6 +856,9 @@ namespace MWMechanics if (target.getClass().getCreatureStats(target).isDead()) return true; + if (target.getClass().getCreatureStats(target).getAiSequence().isInCombat()) + return true; + // check if a player tries to pickpocket a target NPC if(ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak) || target.getClass().getCreatureStats(target).getKnockedDown()) From 21b6bd176f2c40f1e953fd599030d5f64e8abae5 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 1 Oct 2017 17:11:30 +0400 Subject: [PATCH 248/505] AI: Autoequip armor when bound armor spell expires --- apps/openmw/mwmechanics/actors.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index cef429504..69ccdf9e4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -71,7 +71,9 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a } else { - actor.getClass().getContainerStore(actor).remove(item, 1, actor); + MWWorld::Ptr itemPtr = actor.getClass().getInventoryStore(actor).search(item); + if (!itemPtr.isEmpty()) + actor.getClass().getInventoryStore(actor).remove(itemPtr, 1, actor, true); } } From 137ea872d34683c8e2631b7b96b4fe9d716a2ec3 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 2 Oct 2017 15:56:22 -0400 Subject: [PATCH 249/505] Hide base land textures. --- apps/opencs/CMakeLists.txt | 2 +- .../world/landtexturetableproxymodel.cpp | 21 ++++++++++++++++++ .../world/landtexturetableproxymodel.hpp | 22 +++++++++++++++++++ apps/opencs/view/world/table.cpp | 6 +++++ 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/world/landtexturetableproxymodel.cpp create mode 100644 apps/opencs/model/world/landtexturetableproxymodel.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 36ff8cf67..f10525e08 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -18,7 +18,7 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world - idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree infotableproxymodel + idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree infotableproxymodel landtexturetableproxymodel ) diff --git a/apps/opencs/model/world/landtexturetableproxymodel.cpp b/apps/opencs/model/world/landtexturetableproxymodel.cpp new file mode 100644 index 000000000..cf33fab9e --- /dev/null +++ b/apps/opencs/model/world/landtexturetableproxymodel.cpp @@ -0,0 +1,21 @@ +#include "landtexturetableproxymodel.hpp" + +#include "idtable.hpp" + +namespace CSMWorld +{ + LandTextureTableProxyModel::LandTextureTableProxyModel(QObject* parent) + : IdTableProxyModel(parent) + { + } + + bool LandTextureTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const + { + int columnIndex = mSourceModel->findColumnIndex(Columns::ColumnId_Modification); + QModelIndex index = mSourceModel->index(sourceRow, columnIndex); + if (mSourceModel->data(index).toInt() != RecordBase::State_ModifiedOnly) + return false; + + return IdTableProxyModel::filterAcceptsRow(sourceRow, sourceParent); + } +} diff --git a/apps/opencs/model/world/landtexturetableproxymodel.hpp b/apps/opencs/model/world/landtexturetableproxymodel.hpp new file mode 100644 index 000000000..bbedecb53 --- /dev/null +++ b/apps/opencs/model/world/landtexturetableproxymodel.hpp @@ -0,0 +1,22 @@ +#ifndef CSM_WORLD_LANDTEXTURETABLEPROXYMODEL_H +#define CSM_WORLD_LANDTEXTURETABLEPROXYMODEL_H + +#include "idtableproxymodel.hpp" + +namespace CSMWorld +{ + /// \brief Removes base records from filtered results. + class LandTextureTableProxyModel : public IdTableProxyModel + { + Q_OBJECT + public: + + LandTextureTableProxyModel(QObject* parent = nullptr); + + protected: + + bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const override; + }; +} + +#endif diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 3cccaaa22..34ecd57d0 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -16,6 +16,7 @@ #include "../../model/world/idtableproxymodel.hpp" #include "../../model/world/idtablebase.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/world/landtexturetableproxymodel.hpp" #include "../../model/world/record.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/commanddispatcher.hpp" @@ -236,10 +237,15 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, bool isInfoTable = id.getType() == CSMWorld::UniversalId::Type_TopicInfos || id.getType() == CSMWorld::UniversalId::Type_JournalInfos; + bool isLtexTable = (id.getType() == CSMWorld::UniversalId::Type_LandTextures); if (isInfoTable) { mProxyModel = new CSMWorld::InfoTableProxyModel(id.getType(), this); } + else if (isLtexTable) + { + mProxyModel = new CSMWorld::LandTextureTableProxyModel (this); + } else { mProxyModel = new CSMWorld::IdTableProxyModel (this); From 2f5449a68c6ff2b0c3f7345e0d9746dd59eba490 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 2 Oct 2017 16:13:40 -0400 Subject: [PATCH 250/505] Remove now unnecessary overrides. --- apps/opencs/model/world/idtable.cpp | 26 -------------------------- apps/opencs/model/world/idtable.hpp | 6 ------ 2 files changed, 32 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index bde5af3d9..fcfc8577e 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -313,32 +313,6 @@ CSMWorld::LandTextureIdTable::LandTextureIdTable(CollectionBase* idCollection, u { } -QVariant CSMWorld::LandTextureIdTable::data(const QModelIndex& index, int role) const -{ - if (role==Qt::EditRole && !idCollection()->getRecord(index.row()).isModified()) - return QVariant(); - - return IdTable::data(index, role); -} - -bool CSMWorld::LandTextureIdTable::setData(const QModelIndex& index, const QVariant& value, int role) -{ - if (!idCollection()->getRecord(index.row()).isModified()) - return false; - else - return IdTable::setData(index, value, role); -} - -Qt::ItemFlags CSMWorld::LandTextureIdTable::flags(const QModelIndex& index) const -{ - Qt::ItemFlags flags = IdTable::flags(index); - - if (!idCollection()->getRecord(index.row()).isModified()) - flags &= ~Qt::ItemIsEnabled; - - return flags; -} - CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::importTextures(const std::vector& ids) { ImportResults results; diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index ccc5ac404..4136061e4 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -118,12 +118,6 @@ namespace CSMWorld LandTextureIdTable(CollectionBase* idCollection, unsigned int features=0); - QVariant data(const QModelIndex& index, int role=Qt::DisplayRole) const override; - - bool setData(const QModelIndex& index, const QVariant& value, int role) override; - - Qt::ItemFlags flags (const QModelIndex & index) const override; - /// Finds and maps/recreates the specified ids. ImportResults importTextures(const std::vector& ids); }; From d7a5622485a03ef6324470fcb84976882f444af7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 3 Oct 2017 09:16:46 +0000 Subject: [PATCH 251/505] Fix book window buttons overlap --- files/mygui/openmw_book.layout | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/files/mygui/openmw_book.layout b/files/mygui/openmw_book.layout index a7bea5eb5..c83c4982b 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -14,19 +14,15 @@ - - - - - - + + + + - - - - - - + + + + From c598f1313c4233af2aec6dcb92e4924408120961 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Tue, 3 Oct 2017 17:34:45 +0200 Subject: [PATCH 252/505] [macOS, CI] Update dependencies The following changes are included: - https://github.com/OpenMW/openmw-deps-mac/pull/37 - https://github.com/OpenMW/openmw-deps-mac/pull/38 --- 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 25e1c9517..86e8fb81b 100755 --- a/CI/before_install.osx.sh +++ b/CI/before_install.osx.sh @@ -6,5 +6,5 @@ brew outdated cmake || brew upgrade cmake brew outdated pkgconfig || brew upgrade pkgconfig brew install $macos_qt_formula -curl https://downloads.openmw.org/osx/dependencies/openmw-deps-5e144e2.zip -o ~/openmw-deps.zip +curl https://downloads.openmw.org/osx/dependencies/openmw-deps-c40905f.zip -o ~/openmw-deps.zip unzip ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null From 433028e8d7395db109920e0b74309388ddec8984 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 3 Oct 2017 22:07:56 +0000 Subject: [PATCH 253/505] Fix GUI regressions --- apps/openmw/mwgui/dialogue.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 8dd027c4a..e13e626ae 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -390,6 +390,7 @@ namespace MWGui { // No greetings found. The dialogue window should not be shown. // If this is a companion, we must show the companion window directly (used by BM_bear_be_unique). + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); if (isCompanion()) MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, mPtr); return; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e96743b91..fdf4da8a7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -606,7 +606,7 @@ namespace MWGui mMap->setVisible(false); mStatsWindow->setVisible(false); mSpellWindow->setVisible(false); - mInventoryWindow->setVisible(getMode() == GM_Container || getMode() == GM_Barter); + mInventoryWindow->setVisible(getMode() == GM_Container || getMode() == GM_Barter || getMode() == GM_Companion); } GuiMode mode = mGuiModes.back(); From 1cb7ed5db102117b595b8d026d49a51a6244d068 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 3 Oct 2017 09:59:31 +0400 Subject: [PATCH 254/505] Use owned tooltips for items in containers correctly --- apps/openmw/mwgui/container.cpp | 20 ++++++--- apps/openmw/mwgui/containeritemmodel.cpp | 16 +++++++ apps/openmw/mwgui/containeritemmodel.hpp | 1 + apps/openmw/mwgui/itemmodel.cpp | 10 +++++ apps/openmw/mwgui/itemmodel.hpp | 6 +++ apps/openmw/mwgui/pickpocketitemmodel.cpp | 5 +++ apps/openmw/mwgui/pickpocketitemmodel.hpp | 2 + apps/openmw/mwgui/sortfilteritemmodel.cpp | 5 +++ apps/openmw/mwgui/sortfilteritemmodel.hpp | 1 + apps/openmw/mwgui/tooltips.cpp | 44 +++++++++---------- apps/openmw/mwgui/tooltips.hpp | 4 +- apps/openmw/mwgui/tradeitemmodel.cpp | 5 +++ apps/openmw/mwgui/tradeitemmodel.hpp | 2 + .../mwmechanics/mechanicsmanagerimp.cpp | 3 ++ 14 files changed, 92 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index a70d833c7..74ed4fff9 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -22,6 +22,7 @@ #include "itemview.hpp" #include "itemwidget.hpp" #include "inventoryitemmodel.hpp" +#include "containeritemmodel.hpp" #include "sortfilteritemmodel.hpp" #include "pickpocketitemmodel.hpp" #include "draganddrop.hpp" @@ -136,15 +137,22 @@ namespace MWGui bool loot = mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead(); - if (mPtr.getClass().isNpc() && !loot) + if (mPtr.getClass().hasInventoryStore(mPtr)) { - // we are stealing stuff - MWWorld::Ptr player = MWMechanics::getPlayer(); - mModel = new PickpocketItemModel(player, new InventoryItemModel(container), - !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown()); + if (mPtr.getClass().isNpc() && !loot) + { + // we are stealing stuff + MWWorld::Ptr player = MWMechanics::getPlayer(); + mModel = new PickpocketItemModel(player, new InventoryItemModel(container), + !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown()); + } + else + mModel = new InventoryItemModel(container); } else - mModel = new InventoryItemModel(container); + { + mModel = new ContainerItemModel(container); + } mDisposeCorpseButton->setVisible(loot); diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index d62cd16b0..479638672 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -6,8 +6,11 @@ #include "../mwworld/class.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/environment.hpp" +#include "../mwmechanics/actorutil.hpp" + namespace { @@ -47,6 +50,19 @@ ContainerItemModel::ContainerItemModel (const MWWorld::Ptr& source) mItemSources.push_back(source); } +bool ContainerItemModel::allowedToUseItems() const +{ + if (mItemSources.size() == 0) + return true; + + MWWorld::Ptr ptr = MWMechanics::getPlayer(); + MWWorld::Ptr victim; + + // Check if the player is allowed to use items from opened container + MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); + return mm->isAllowedToUse(ptr, mItemSources[0], victim); +} + ItemStack ContainerItemModel::getItem (ModelIndex index) { if (index < 0) diff --git a/apps/openmw/mwgui/containeritemmodel.hpp b/apps/openmw/mwgui/containeritemmodel.hpp index 7ced6ae34..c6ecafd46 100644 --- a/apps/openmw/mwgui/containeritemmodel.hpp +++ b/apps/openmw/mwgui/containeritemmodel.hpp @@ -17,6 +17,7 @@ namespace MWGui ContainerItemModel (const MWWorld::Ptr& source); + virtual bool allowedToUseItems() const; virtual ItemStack getItem (ModelIndex index); virtual ModelIndex getIndex (ItemStack item); virtual size_t getItemCount(); diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 390bb0586..ffcf9075e 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -119,6 +119,11 @@ namespace MWGui return ret; } + bool ItemModel::allowedToUseItems() const + { + return true; + } + bool ItemModel::allowedToInsertItems() const { return true; @@ -135,6 +140,11 @@ namespace MWGui delete mSourceModel; } + bool ProxyItemModel::allowedToUseItems() const + { + return mSourceModel->allowedToUseItems(); + } + MWWorld::Ptr ProxyItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner) { return mSourceModel->copyItem (item, count, setNewOwner); diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index 20955b206..bc6be8023 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -70,6 +70,9 @@ namespace MWGui virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false) = 0; virtual void removeItem (const ItemStack& item, size_t count) = 0; + /// Is the player allowed to use items from this item model? (default true) + virtual bool allowedToUseItems() const; + /// Is the player allowed to insert items into this model? (default true) virtual bool allowedToInsertItems() const; @@ -85,6 +88,9 @@ namespace MWGui public: ProxyItemModel(); virtual ~ProxyItemModel(); + + bool allowedToUseItems() const; + virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); virtual ModelIndex getIndex (ItemStack item); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index 238fb5913..ec4b378a0 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -26,6 +26,11 @@ namespace MWGui } } + bool PickpocketItemModel::allowedToUseItems() const + { + return false; + } + ItemStack PickpocketItemModel::getItem (ModelIndex index) { if (index < 0) diff --git a/apps/openmw/mwgui/pickpocketitemmodel.hpp b/apps/openmw/mwgui/pickpocketitemmodel.hpp index 61f0569b5..1b08ec485 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.hpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.hpp @@ -11,6 +11,8 @@ namespace MWGui { public: PickpocketItemModel (const MWWorld::Ptr& thief, ItemModel* sourceModel, bool hideItems=true); + + virtual bool allowedToUseItems() const; virtual ItemStack getItem (ModelIndex index); virtual size_t getItemCount(); virtual void update(); diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 45aa261df..e294ebe07 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -159,6 +159,11 @@ namespace MWGui mSourceModel = sourceModel; } + bool SortFilterItemModel::allowedToUseItems() const + { + return mSourceModel->allowedToUseItems(); + } + void SortFilterItemModel::addDragItem (const MWWorld::Ptr& dragItem, size_t count) { mDragItems.push_back(std::make_pair(dragItem, count)); diff --git a/apps/openmw/mwgui/sortfilteritemmodel.hpp b/apps/openmw/mwgui/sortfilteritemmodel.hpp index 4731cbb8a..6ddb019b0 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.hpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.hpp @@ -15,6 +15,7 @@ namespace MWGui bool filterAccepts (const ItemStack& item); + bool allowedToUseItems() const; virtual ItemStack getItem (ModelIndex index); virtual size_t getItemCount(); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index a9930db4f..af6bf4726 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -120,7 +120,7 @@ namespace MWGui if (info.caption.empty()) info.caption=mFocusObject.getCellRef().getRefId(); info.icon=""; - tooltipSize = createToolTip(info, true); + tooltipSize = createToolTip(info, checkOwned()); } else tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), true); @@ -186,22 +186,24 @@ namespace MWGui ToolTipInfo info; info.text = data.caption; info.notes = data.notes; - tooltipSize = createToolTip(info, false); + tooltipSize = createToolTip(info); } else if (type == "ItemPtr") { mFocusObject = *focus->getUserData(); - tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false); + bool isAllowedToUse = checkOwned(); + tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false, !isAllowedToUse); } else if (type == "ItemModelIndex") { std::pair pair = *focus->getUserData >(); mFocusObject = pair.second->getItem(pair.first).mBase; - tooltipSize = getToolTipViaPtr(pair.second->getItem(pair.first).mCount, false); + bool isAllowedToUse = pair.second->allowedToUseItems(); + tooltipSize = getToolTipViaPtr(pair.second->getItem(pair.first).mCount, false, !isAllowedToUse); } else if (type == "ToolTipInfo") { - tooltipSize = createToolTip(*focus->getUserData(), false); + tooltipSize = createToolTip(*focus->getUserData()); } else if (type == "AvatarItemSelection") { @@ -244,7 +246,7 @@ namespace MWGui info.text = "#{sSchool}: " + sSchoolNames[school]; } info.effects = effects; - tooltipSize = createToolTip(info, false); + tooltipSize = createToolTip(info); } else if (type == "Layout") { @@ -298,7 +300,7 @@ namespace MWGui { if (!mFocusObject.isEmpty()) { - MyGUI::IntSize tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount()); + MyGUI::IntSize tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), true, checkOwned()); setCoord(viewSize.width/2 - tooltipSize.width/2, std::max(0, int(mFocusToolTipY*viewSize.height - tooltipSize.height)), @@ -332,7 +334,7 @@ namespace MWGui update(mFrameDuration); } - MyGUI::IntSize ToolTips::getToolTipViaPtr (int count, bool image) + MyGUI::IntSize ToolTips::getToolTipViaPtr (int count, bool image, bool isOwned) { // this the maximum width of the tooltip before it starts word-wrapping setCoord(0, 0, 300, 300); @@ -351,7 +353,7 @@ namespace MWGui ToolTipInfo info = object.getToolTipInfo(mFocusObject, count); if (!image) info.icon = ""; - tooltipSize = createToolTip(info, true); + tooltipSize = createToolTip(info, isOwned); } return tooltipSize; @@ -359,27 +361,21 @@ namespace MWGui bool ToolTips::checkOwned() { - if(!mFocusObject.isEmpty()) - { - MWWorld::Ptr ptr = MWMechanics::getPlayer(); - MWWorld::Ptr victim; - - MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); - bool allowed = mm->isAllowedToUse(ptr, mFocusObject, victim); - - return !allowed; - } - else - { + if(mFocusObject.isEmpty()) return false; - } + + MWWorld::Ptr ptr = MWMechanics::getPlayer(); + MWWorld::Ptr victim; + + MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); + return !mm->isAllowedToUse(ptr, mFocusObject, victim); } - MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info, bool isFocusObject) + MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info, bool isOwned) { mDynamicToolTipBox->setVisible(true); - if((mShowOwned == 1 || mShowOwned == 3) && isFocusObject && checkOwned()) + if((mShowOwned == 1 || mShowOwned == 3) && isOwned) mDynamicToolTipBox->changeWidgetSkin(MWBase::Environment::get().getWindowManager()->isGuiMode() ? "HUD_Box_NoTransp_Owned" : "HUD_Box_Owned"); else mDynamicToolTipBox->changeWidgetSkin(MWBase::Environment::get().getWindowManager()->isGuiMode() ? "HUD_Box_NoTransp" : "HUD_Box"); diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 2793e6544..1ef473b5a 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -98,10 +98,10 @@ namespace MWGui MWWorld::Ptr mFocusObject; - MyGUI::IntSize getToolTipViaPtr (int count, bool image=true); + MyGUI::IntSize getToolTipViaPtr (int count, bool image = true, bool isOwned = false); ///< @return requested tooltip size - MyGUI::IntSize createToolTip(const ToolTipInfo& info, bool isFocusObject); + MyGUI::IntSize createToolTip(const ToolTipInfo& info, bool isOwned = false); ///< @return requested tooltip size /// @param isFocusObject Is the object this tooltips originates from mFocusObject? diff --git a/apps/openmw/mwgui/tradeitemmodel.cpp b/apps/openmw/mwgui/tradeitemmodel.cpp index ae3feb61c..a26294a0e 100644 --- a/apps/openmw/mwgui/tradeitemmodel.cpp +++ b/apps/openmw/mwgui/tradeitemmodel.cpp @@ -15,6 +15,11 @@ namespace MWGui mSourceModel = sourceModel; } + bool TradeItemModel::allowedToUseItems() const + { + return true; + } + ItemStack TradeItemModel::getItem (ModelIndex index) { if (index < 0) diff --git a/apps/openmw/mwgui/tradeitemmodel.hpp b/apps/openmw/mwgui/tradeitemmodel.hpp index 1bfee9b2a..cdb949c49 100644 --- a/apps/openmw/mwgui/tradeitemmodel.hpp +++ b/apps/openmw/mwgui/tradeitemmodel.hpp @@ -15,6 +15,8 @@ namespace MWGui public: TradeItemModel (ItemModel* sourceModel, const MWWorld::Ptr& merchant); + bool allowedToUseItems() const; + virtual ItemStack getItem (ModelIndex index); virtual size_t getItemCount(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index da98e7f5f..2c7b6a500 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -842,6 +842,9 @@ namespace MWMechanics bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) { + if (target.isEmpty()) + return true; + const MWWorld::CellRef& cellref = target.getCellRef(); // there is no harm to use unlocked doors if (target.getClass().isDoor() && cellref.getLockLevel() <= 0 && ptr.getCellRef().getTrap().empty()) From 13e7504348004d7dbf5645d3487787d57babcc13 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Wed, 4 Oct 2017 15:44:33 +0300 Subject: [PATCH 255/505] [Documentation] Update information --- README.md | 8 ++++---- tes3mp-credits.md | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6a9dec268..f56130aff 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ TES3MP [![Build Status](https://travis-ci.org/TES3MP/openmw-tes3mp.svg?branch=master)](https://travis-ci.org/TES3MP/openmw-tes3mp) -TES3MP is a project aiming to add multiplayer functionality to [OpenMW](https://github.com/OpenMW/openmw), a free and open source recreation of the popular Bethesda Softworks game "The Elder Scrolls III: Morrowind". +TES3MP is a project aiming to add multiplayer functionality to [OpenMW](https://github.com/OpenMW/openmw), a free and open source engine recreation of the popular Bethesda Softworks game "The Elder Scrolls III: Morrowind". * Version: 0.6.1 * License: GPLv3 (see docs/license/GPL3.txt for more information) @@ -25,17 +25,17 @@ Contributing Development has been relatively fast, but any contribution regarding [code](https://github.com/TES3MP/openmw-tes3mp/blob/master/CONTRIBUTING.md), documentation, bug hunting or video showcases is greatly appreciated. -Test sessions are often advertised in [our Steam group](https://steamcommunity.com/groups/mwmulti) or [our Discord server](https://discord.gg/H8zhhuk). +Test sessions are often advertised in [our Steam group](https://steamcommunity.com/groups/mwmulti) or [our Discord server](https://discord.gg/ECJk293). Feel free to contact the [team members](https://github.com/TES3MP/openmw-tes3mp/blob/master/tes3mp-credits.md) for any questions you might have. Getting Started --------------- +* [Quickstart guide](https://github.com/TES3MP/openmw-tes3mp/wiki/Quickstart-guide) +* [Steam group](https://steamcommunity.com/groups/mwmulti) and its [detailed FAQ](http://steamcommunity.com/groups/mwmulti/discussions/1/353916184342480541/) * [TES3MP section on OpenMW forums](https://forum.openmw.org/viewforum.php?f=44) -* [Steam group](https://steamcommunity.com/groups/mwmulti) * [Subreddit](https://www.reddit.com/r/tes3mp) -* [Installation and build instructions](https://github.com/TES3MP/openmw-tes3mp/wiki/Installation-and-build-instructions) * [Known issues and bug reports](https://github.com/TES3MP/openmw-tes3mp/issues) Donations diff --git a/tes3mp-credits.md b/tes3mp-credits.md index f474702a4..ad603c16f 100644 --- a/tes3mp-credits.md +++ b/tes3mp-credits.md @@ -26,7 +26,7 @@ Community administrators Art --- - Texafornian - tes3mp logo + Texafornian - TES3MP logo Special thanks (in alphabetical order) @@ -51,6 +51,7 @@ Special thanks (in alphabetical order) Rhiyo Scorcio Shnatsel + Simon Nemes Zaphida Zaric Zhakaron All the developers of OpenMW for creating an amazing open source project From 7c68ed04b2bb458d02fd6b57dd1f1b9a3187ab48 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:03:23 +0200 Subject: [PATCH 256/505] Don't require modal windows to be removed in the same order they were added --- apps/openmw/mwgui/windowmanagerimp.cpp | 24 ++++++++++++++---------- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index fdf4da8a7..a9ca9bd19 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -865,7 +865,7 @@ namespace MWGui window->onFrame(frameDuration); } if (!mCurrentModals.empty()) - mCurrentModals.top()->onFrame(frameDuration); + mCurrentModals.back()->onFrame(frameDuration); mKeyboardNavigation->onFrame(); @@ -1727,9 +1727,9 @@ namespace MWGui { if (!mCurrentModals.empty()) { - if (!mCurrentModals.top()->exit()) + if (!mCurrentModals.back()->exit()) return; - mCurrentModals.top()->setVisible(false); + mCurrentModals.back()->setVisible(false); } } @@ -1738,7 +1738,7 @@ namespace MWGui if (mCurrentModals.empty()) mKeyboardNavigation->saveFocus(getMode()); - mCurrentModals.push(input); + mCurrentModals.push_back(input); mKeyboardNavigation->restoreFocus(-1); mKeyboardNavigation->setModalWindow(input->mMainWidget); @@ -1747,17 +1747,21 @@ namespace MWGui void WindowManager::removeCurrentModal(WindowModal* input) { - // Only remove the top if it matches the current pointer. A lot of things hide their visibility before showing it, - //so just popping the top would cause massive issues. if(!mCurrentModals.empty()) { - if(input == mCurrentModals.top()) + if(input == mCurrentModals.back()) { - mCurrentModals.pop(); + mCurrentModals.pop_back(); mKeyboardNavigation->saveFocus(-1); } else - std::cout << " warning: modal widget " << input << " " << typeid(input).name() << " not found " << std::endl; + { + auto found = std::find(mCurrentModals.begin(), mCurrentModals.end(), input); + if (found != mCurrentModals.end()) + mCurrentModals.erase(found); + else + std::cerr << " warning: can't find modal window " << input << std::endl; + } } if (mCurrentModals.empty()) { @@ -1765,7 +1769,7 @@ namespace MWGui mKeyboardNavigation->restoreFocus(getMode()); } else - mKeyboardNavigation->setModalWindow(mCurrentModals.top()->mMainWidget); + mKeyboardNavigation->setModalWindow(mCurrentModals.back()->mMainWidget); } void WindowManager::onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 612470a7e..bdd2aa094 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -401,7 +401,7 @@ namespace MWGui MWWorld::Ptr mSelectedEnchantItem; MWWorld::Ptr mSelectedWeapon; - std::stack mCurrentModals; + std::vector mCurrentModals; // Markers placed manually by the player. Must be shared between both map views (the HUD map and the map window). CustomMarkerCollection mCustomMarkers; From 49a0922f1b4b26c5dd421ab326fb6529b55d79eb Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:08:09 +0200 Subject: [PATCH 257/505] Remove 'visibility mask' gui feature which did not end up being useful --- apps/openmw/mwgui/windowmanagerimp.cpp | 29 +++++++++++--------------- apps/openmw/mwgui/windowmanagerimp.hpp | 1 - 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a9ca9bd19..9a7a7437a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -613,18 +613,18 @@ namespace MWGui mInventoryWindow->setTrading(mode == GM_Barter); - // For the inventory mode, compute the effective set of windows to show. - // This is controlled both by what windows the - // user has opened/closed (the 'shown' variable) and by what - // windows we are allowed to show (the 'allowed' var.) - int eff = mShown & mAllowed & ~mForceHidden; - mGuiModeStates[GM_Inventory].mVisibilityMask.resize(4); - mGuiModeStates[GM_Inventory].mVisibilityMask[0] = eff & GW_Map; - mGuiModeStates[GM_Inventory].mVisibilityMask[1] = eff & GW_Inventory; - mGuiModeStates[GM_Inventory].mVisibilityMask[2] = eff & GW_Magic; - mGuiModeStates[GM_Inventory].mVisibilityMask[3] = eff & GW_Stats; if (getMode() == GM_Inventory) - mGuiModeStates[GM_Inventory].update(true); + { + // For the inventory mode, compute the effective set of windows to show. + // This is controlled both by what windows the + // user has opened/closed (the 'shown' variable) and by what + // windows we are allowed to show (the 'allowed' var.) + int eff = mShown & mAllowed & ~mForceHidden; + mMap->setVisible(eff & GW_Map); + mInventoryWindow->setVisible(eff & GW_Inventory); + mSpellWindow->setVisible(eff & GW_Magic); + mStatsWindow->setVisible(eff & GW_Stats); + } switch (mode) { @@ -2063,12 +2063,7 @@ namespace MWGui void WindowManager::GuiModeState::update(bool visible) { for (unsigned int i=0; isetVisible(visible && visibilityMask); - } + mWindows[i]->setVisible(visible); } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index bdd2aa094..c8bc8d21e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -477,7 +477,6 @@ namespace MWGui void update(bool visible); std::vector mWindows; - std::vector mVisibilityMask; // optional, may be used to temporarily exclude windows from this mode. std::string mCloseSound; std::string mOpenSound; From e4f0f7157a796ccf647b6e841b06604ce8f0bf69 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:08:52 +0200 Subject: [PATCH 258/505] Fix pinned windows not being updated --- apps/openmw/mwgui/windowmanagerimp.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9a7a7437a..eae706ec3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -864,6 +864,14 @@ namespace MWGui for (WindowBase* window : state.mWindows) window->onFrame(frameDuration); } + else + { + // update pinned windows if visible + for (WindowBase* window : mGuiModeStates[GM_Inventory].mWindows) + if (window->isVisible()) + window->onFrame(frameDuration); + } + if (!mCurrentModals.empty()) mCurrentModals.back()->onFrame(frameDuration); From a4737d84178e0f7ae58ed9364d648d1e9c4c687f Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:26:23 +0200 Subject: [PATCH 259/505] Use MyGUI frame events for ScreenFader --- apps/openmw/mwgui/screenfader.cpp | 10 +++++++++- apps/openmw/mwgui/screenfader.hpp | 3 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 6 ------ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index d1118848b..9a9a1ae01 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -2,6 +2,7 @@ #include #include +#include namespace MWGui { @@ -80,6 +81,8 @@ namespace MWGui , mFactor(1.f) , mRepeat(false) { + MyGUI::Gui::getInstance().eventFrameStart += MyGUI::newDelegate(this, &ScreenFader::onFrameStart); + mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize()); MyGUI::ImageBox* imageBox = mMainWidget->castType(false); @@ -94,7 +97,12 @@ namespace MWGui } } - void ScreenFader::update(float dt) + ScreenFader::~ScreenFader() + { + MyGUI::Gui::getInstance().eventFrameStart -= MyGUI::newDelegate(this, &ScreenFader::onFrameStart); + } + + void ScreenFader::onFrameStart(float dt) { if (!mQueue.empty()) { diff --git a/apps/openmw/mwgui/screenfader.hpp b/apps/openmw/mwgui/screenfader.hpp index 88dd0c57b..79bea30e5 100644 --- a/apps/openmw/mwgui/screenfader.hpp +++ b/apps/openmw/mwgui/screenfader.hpp @@ -36,8 +36,9 @@ namespace MWGui { public: ScreenFader(const std::string & texturePath, const std::string& layout = "openmw_screen_fader.layout", const MyGUI::FloatCoord& texCoordOverride = MyGUI::FloatCoord(0,0,1,1)); + ~ScreenFader(); - void update(float dt); + void onFrameStart(float dt); void fadeIn(const float time, float delay=0); void fadeOut(const float time, float delay=0); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index eae706ec3..504bef964 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -894,12 +894,6 @@ namespace MWGui mHud->onFrame(frameDuration); - if (mWerewolfFader) - mWerewolfFader->update(frameDuration); - mBlindnessFader->update(frameDuration); - mHitFader->update(frameDuration); - mScreenFader->update(frameDuration); - mDebugWindow->onFrame(frameDuration); if (mCharGen) From 12510efab7bd2e29f23e5054356718a8847bf763 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:39:19 +0200 Subject: [PATCH 260/505] Fade screen out during loading screen (when travelling) --- apps/openmw/mwgui/loadingscreen.cpp | 12 ++++++++++-- apps/openmw/mwgui/loadingscreen.hpp | 1 + apps/openmw/mwgui/travelwindow.cpp | 2 ++ files/mygui/openmw_layers.xml | 1 + 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index f22d825dd..4753c39f2 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -50,6 +50,8 @@ namespace MWGui mBackgroundImage = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, MyGUI::Align::Stretch, "Menu"); + mSceneImage = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, + MyGUI::Align::Stretch, "Scene"); findSplashScreens(); } @@ -110,6 +112,7 @@ namespace MWGui { WindowBase::setVisible(visible); mBackgroundImage->setVisible(visible); + mSceneImage->setVisible(visible); } double LoadingScreen::getTargetFrameRate() const @@ -214,8 +217,11 @@ namespace MWGui // TODO: add option (filename pattern?) to use image aspect ratio instead of 4:3 // we can't do this by default, because the Morrowind splash screens are 1024x1024, but should be displayed as 4:3 bool stretch = Settings::Manager::getBool("stretch menu background", "GUI"); + mBackgroundImage->setVisible(true); mBackgroundImage->setBackgroundImage(randomSplash, true, stretch); } + mSceneImage->setBackgroundImage(""); + mSceneImage->setVisible(false); } void LoadingScreen::setProgressRange (size_t range) @@ -292,9 +298,11 @@ namespace MWGui mViewer->getCamera()->setInitialDrawCallback(new CopyFramebufferToTextureCallback(mTexture)); mBackgroundImage->setBackgroundImage(""); + mBackgroundImage->setVisible(false); - mBackgroundImage->setRenderItemTexture(mGuiTexture.get()); - mBackgroundImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + mSceneImage->setRenderItemTexture(mGuiTexture.get()); + mSceneImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + mSceneImage->setVisible(true); } void LoadingScreen::draw() diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 2f8831fdc..8536972a3 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -72,6 +72,7 @@ namespace MWGui MyGUI::TextBox* mLoadingText; MyGUI::ScrollBar* mProgressBar; BackgroundImage* mBackgroundImage; + BackgroundImage* mSceneImage; std::vector mSplashScreens; diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 7c7cdb63e..7586bb66a 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -178,6 +178,8 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); + MWBase::Environment::get().getWindowManager()->fadeScreenOut(1); + // Teleports any followers, too. MWWorld::ActionTeleport action(interior ? cellname : "", pos, true); action.execute(player); diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index cd8a9f760..5e4a74978 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -1,6 +1,7 @@ + From d94235e3a727bcec1d800cd4184bd70da142d306 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:47:42 +0200 Subject: [PATCH 261/505] Update the saves list/preview image when character selection changes to make it more convenient to flip through characters with the keyboard --- apps/openmw/mwgui/savegamedialog.cpp | 13 ++++++++++--- apps/openmw/mwgui/savegamedialog.hpp | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 423dbb036..6a290bef1 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -50,7 +50,8 @@ namespace MWGui mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onOkButtonClicked); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onCancelButtonClicked); mDeleteButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteButtonClicked); - mCharacterSelection->eventComboAccept += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected); + mCharacterSelection->eventComboChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected); + mCharacterSelection->eventComboAccept += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterAccept); mSaveList->eventListChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onSlotSelected); mSaveList->eventListMouseItemActivate += MyGUI::newDelegate(this, &SaveGameDialog::onSlotMouseClick); mSaveList->eventListSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onSlotActivated); @@ -132,6 +133,8 @@ namespace MWGui mSaveNameEdit->setCaption (""); if (mSaving) MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveNameEdit); + else + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList); center(); @@ -322,6 +325,12 @@ namespace MWGui fillSaveList(); } + void SaveGameDialog::onCharacterAccept(MyGUI::ComboBox* sender, size_t pos) + { + // Give key focus to save list so we can confirm the selection with Enter + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList); + } + void SaveGameDialog::fillSaveList() { mSaveList->removeAllItems(); @@ -336,8 +345,6 @@ namespace MWGui { mSaveList->setIndexSelected(0); onSlotSelected(mSaveList, 0); - // Give key focus to save list so we can confirm the selection with Enter - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList); } else onSlotSelected(mSaveList, MyGUI::ITEM_NONE); diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index a51124705..0a87b6600 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -29,6 +29,7 @@ namespace MWGui void onOkButtonClicked (MyGUI::Widget* sender); void onDeleteButtonClicked (MyGUI::Widget* sender); void onCharacterSelected (MyGUI::ComboBox* sender, size_t pos); + void onCharacterAccept(MyGUI::ComboBox* sender, size_t pos); // Slot selected (mouse click or arrow keys) void onSlotSelected (MyGUI::ListBox* sender, size_t pos); // Slot activated (double click or enter key) From cd437f094d9fbeb77850dbaa0d84fb25ca749151 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 5 Oct 2017 18:35:09 +0200 Subject: [PATCH 262/505] Fix exiting savegamedialog with 'esc' when no game is running --- apps/openmw/mwgui/mainmenu.cpp | 5 +++++ apps/openmw/mwgui/mainmenu.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 4 ++-- apps/openmw/mwinput/inputmanagerimp.cpp | 4 +--- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 00e4e30a5..5017b8893 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -210,6 +210,11 @@ namespace MWGui } } + bool MainMenu::exit() + { + return MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_Running; + } + void MainMenu::updateMenu() { setCoord(0,0, mWidth, mHeight); diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index 1beb9ee16..82553d22e 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -38,6 +38,8 @@ namespace MWGui void onFrame(float dt); + bool exit(); + private: const VFS::Manager* mVFS; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 504bef964..a81c3a614 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -750,8 +750,8 @@ namespace MWGui if (!window->exit()) { // unable to exit window, but give access to main menu - if (!MyGUI::InputManager::getInstance().isModalAny()) - pushGuiMode (MWGui::GM_MainMenu); + if (!MyGUI::InputManager::getInstance().isModalAny() && getMode() != GM_MainMenu) + pushGuiMode (GM_MainMenu); return; } } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index e6acbbd52..06ebeb0b8 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -241,9 +241,7 @@ namespace MWInput switch (action) { case A_GameMenu: - if(!(MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running - && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_MainMenu)) - toggleMainMenu (); + toggleMainMenu (); break; case A_Screenshot: screenshot(); From 8c0790580a80431d9f31d7beed07f8e61beae121 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 5 Oct 2017 18:39:28 +0200 Subject: [PATCH 263/505] Add screen fading for exterior cell transitions --- apps/openmw/mwworld/scene.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c83165239..0a27cf257 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -580,10 +580,16 @@ namespace MWWorld MWBase::Environment::get().getWorld()->positionToIndex (position.pos[0], position.pos[1], x, y); + if (changeEvent) + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5); + changeCellGrid(x, y, changeEvent); CellStore* current = MWBase::Environment::get().getWorld()->getExterior(x, y); changePlayerCell(current, position, adjustPlayerPos); + + if (changeEvent) + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); } CellStore* Scene::getCurrentCell () From 842a42ee664b30dee6e9bd74c4a70de1bfca19ea Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 5 Oct 2017 18:39:58 +0200 Subject: [PATCH 264/505] Fix non-top level Windows accepting key focus --- apps/openmw/mwgui/keyboardnavigation.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index 2b06de295..d27185204 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -12,6 +12,11 @@ namespace MWGui { +bool shouldAcceptKeyFocus(MyGUI::Widget* w) +{ + return w && !w->castType(false) && w->getInheritedEnabled() && w->getInheritedVisible() && w->getVisible() && w->getEnabled(); +} + /// Recursively get all child widgets that accept keyboard input void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& results) { @@ -24,18 +29,13 @@ void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& resu MyGUI::Widget* w = enumerator.current(); if (!w->getVisible() || !w->getEnabled()) continue; - if (w->getNeedKeyFocus()) + if (w->getNeedKeyFocus() && shouldAcceptKeyFocus(w)) results.push_back(w); else getKeyFocusWidgets(w, results); } } -bool shouldAcceptKeyFocus(MyGUI::Widget* w) -{ - return w && !w->castType(false) && w->getInheritedEnabled() && w->getInheritedVisible() && w->getVisible() && w->getEnabled(); -} - KeyboardNavigation::KeyboardNavigation() : mCurrentFocus(nullptr) , mModalWindow(nullptr) From e2afd3690c0f2495a1efd12576e5ed91c3dab932 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 6 Oct 2017 10:54:25 +0400 Subject: [PATCH 265/505] Remove item by id from InventoryStore --- apps/openmw/mwmechanics/actors.cpp | 6 +----- apps/openmw/mwworld/inventorystore.cpp | 19 +++++++++++++++++++ apps/openmw/mwworld/inventorystore.hpp | 3 +++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 0715eb177..a144911c5 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -70,11 +70,7 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a } } else - { - MWWorld::Ptr itemPtr = actor.getClass().getInventoryStore(actor).search(item); - if (!itemPtr.isEmpty()) - actor.getClass().getInventoryStore(actor).remove(itemPtr, 1, actor, true); - } + actor.getClass().getInventoryStore(actor).remove(item, 1, actor, true); } class CheckActorCommanded : public MWMechanics::EffectSourceVisitor diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index b599b3583..77141f269 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -654,11 +654,30 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSelectedEnchantItem( return mSelectedEnchantItem; } +int MWWorld::InventoryStore::remove(const std::string& itemId, int count, const Ptr& actor) +{ + return remove(itemId, count, actor, false); +} + int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor) { return remove(item, count, actor, false); } +int MWWorld::InventoryStore::remove(const std::string& itemId, int count, const Ptr& actor, bool equipReplacement) +{ + int toRemove = count; + + for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter) + if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), itemId)) + toRemove -= remove(*iter, toRemove, actor, equipReplacement); + + flagAsModified(); + + // number of removed items + return count - toRemove; +} + int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement) { int retCount = ContainerStore::remove(item, count, actor); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 851abf408..49991c164 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -177,6 +177,9 @@ namespace MWWorld virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2) const; ///< @return true if the two specified objects can stack with each other + virtual int remove(const std::string& itemId, int count, const Ptr& actor); + virtual int remove(const std::string& itemId, int count, const Ptr& actor, bool equipReplacement); + virtual int remove(const Ptr& item, int count, const Ptr& actor); virtual int remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement); ///< Remove \a count item(s) designated by \a item from this inventory. From ad27e0f945ed2bafca11b4fdeff5cefd01e52863 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 6 Oct 2017 11:38:27 +0400 Subject: [PATCH 266/505] Fix owned tooltip in the spellwindow --- apps/openmw/mwgui/tooltips.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index af6bf4726..b2991a034 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -191,8 +191,7 @@ namespace MWGui else if (type == "ItemPtr") { mFocusObject = *focus->getUserData(); - bool isAllowedToUse = checkOwned(); - tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false, !isAllowedToUse); + tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false, checkOwned()); } else if (type == "ItemModelIndex") { From 280578154222556506c3c293c63e7ea5b7a0b4b7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 6 Oct 2017 16:18:57 +0000 Subject: [PATCH 267/505] Fix a crash when exit() already hides the window (Fixes #4148) --- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a81c3a614..ccdd6916c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1729,9 +1729,10 @@ namespace MWGui { if (!mCurrentModals.empty()) { - if (!mCurrentModals.back()->exit()) + WindowModal* window = mCurrentModals.back(); + if (!window->exit()) return; - mCurrentModals.back()->setVisible(false); + window->setVisible(false); } } From b14404e9cccbb3c8a91d7f5e6476b15d30be1850 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 6 Oct 2017 20:05:06 -0400 Subject: [PATCH 268/505] Fix region colors --- apps/opencs/model/world/columnimp.hpp | 17 ++++------------- apps/opencs/view/world/colordelegate.cpp | 15 +++++++++------ 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index e36e386c9..f1025acb9 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -692,32 +692,23 @@ namespace CSMWorld } }; - /// \todo QColor is a GUI class and should not be in model. Need to think of an alternative - /// solution. template struct MapColourColumn : public Column { - /// \todo Replace Display_Integer with something that displays the colour value more directly. MapColourColumn() : Column (Columns::ColumnId_MapColour, ColumnBase::Display_Colour) {} virtual QVariant get (const Record& record) const { - int colour = record.get().mMapColor; - - return QColor (colour & 0xff, (colour>>8) & 0xff, (colour>>16) & 0xff); + return record.get().mMapColor; } virtual void set (Record& record, const QVariant& data) { - ESXRecordT record2 = record.get(); - - QColor colour = data.value(); - - record2.mMapColor = (colour.blue() << 16) | (colour.green() << 8) | colour.red(); - - record.setModified (record2); + ESXRecordT copy = record.get(); + copy.mMapColor = data.toInt(); + record.setModified (copy); } virtual bool isEditable() const diff --git a/apps/opencs/view/world/colordelegate.cpp b/apps/opencs/view/world/colordelegate.cpp index 1a89fc675..15a07b42c 100644 --- a/apps/opencs/view/world/colordelegate.cpp +++ b/apps/opencs/view/world/colordelegate.cpp @@ -5,29 +5,32 @@ #include "../widget/coloreditor.hpp" -CSVWorld::ColorDelegate::ColorDelegate(CSMWorld::CommandDispatcher *dispatcher, - CSMDoc::Document& document, +CSVWorld::ColorDelegate::ColorDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, QObject *parent) : CommandDelegate(dispatcher, document, parent) {} -void CSVWorld::ColorDelegate::paint(QPainter *painter, +void CSVWorld::ColorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { + int colorInt = index.data().toInt(); + QColor color(colorInt & 0xff, (colorInt >> 8) & 0xff, (colorInt >> 16) & 0xff); + QRect coloredRect(option.rect.x() + qRound(option.rect.width() / 4.0), option.rect.y() + qRound(option.rect.height() / 4.0), option.rect.width() / 2, option.rect.height() / 2); painter->save(); - painter->fillRect(coloredRect, index.data().value()); + painter->fillRect(coloredRect, color); painter->setPen(Qt::black); painter->drawRect(coloredRect); painter->restore(); } -CSVWorld::CommandDelegate *CSVWorld::ColorDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher, - CSMDoc::Document &document, +CSVWorld::CommandDelegate *CSVWorld::ColorDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document &document, QObject *parent) const { return new ColorDelegate(dispatcher, document, parent); From 711c4d83daefd5c812596dbfdc2c8f013786cf58 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sat, 7 Oct 2017 23:33:36 +0300 Subject: [PATCH 269/505] [Client] Fix build after recent OpenMW changes to GUI --- apps/openmw/mwbase/dialoguemanager.hpp | 2 +- apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwmp/CellController.cpp | 8 ++++---- apps/openmw/mwmp/CellController.hpp | 2 +- apps/openmw/mwmp/GUI/GUIChat.cpp | 7 ++++--- apps/openmw/mwmp/GUI/GUIChat.hpp | 7 +++---- apps/openmw/mwmp/GUI/TextInputDialog.cpp | 4 ++-- apps/openmw/mwmp/GUI/TextInputDialog.hpp | 2 +- apps/openmw/mwmp/LocalPlayer.cpp | 5 ++--- apps/openmw/mwmp/LocalPlayer.hpp | 2 +- apps/openmw/mwmp/WorldEvent.cpp | 2 +- 11 files changed, 21 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index 386f73382..f777f838f 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -105,7 +105,7 @@ namespace MWBase Declare this method here so it can be used from outside of MWDialogue::DialogueManager */ - virtual void updateTopics() = 0; + virtual void updateActorKnownTopics() = 0; /* End of tes3mp addition */ diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 5663f5c5d..085404fcc 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -226,7 +226,7 @@ namespace MWGui Mark this container as open for multiplayer logic purposes */ - mwmp::Main::get().getCellController()->openContainer(container, loot); + mwmp::Main::get().getCellController()->openContainer(container); /* End of tes3mp addition */ diff --git a/apps/openmw/mwmp/CellController.cpp b/apps/openmw/mwmp/CellController.cpp index aac250775..466a63c58 100644 --- a/apps/openmw/mwmp/CellController.cpp +++ b/apps/openmw/mwmp/CellController.cpp @@ -338,14 +338,14 @@ bool CellController::isSameCell(const ESM::Cell& cell, const ESM::Cell& otherCel return false; } -void CellController::openContainer(const MWWorld::Ptr &container, bool loot) +void CellController::openContainer(const MWWorld::Ptr &container) { // Record this as the player's current open container - Main::get().getLocalPlayer()->storeCurrentContainer(container, loot); + Main::get().getLocalPlayer()->storeCurrentContainer(container); const auto &cellRef = container.getCellRef(); - LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Container \"%s\" (%d) is opened. Loot: %s", - cellRef.getRefId().c_str(), cellRef.getRefNum().mIndex, loot ? "true" : "false"); + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Container \"%s\" (%d) is opened", + cellRef.getRefId().c_str(), cellRef.getRefNum().mIndex); for (const auto &ptr : container.getClass().getContainerStore(container)) { diff --git a/apps/openmw/mwmp/CellController.hpp b/apps/openmw/mwmp/CellController.hpp index ae2de1862..4b28043d3 100644 --- a/apps/openmw/mwmp/CellController.hpp +++ b/apps/openmw/mwmp/CellController.hpp @@ -59,7 +59,7 @@ namespace mwmp bool isSameCell(const ESM::Cell& cell, const ESM::Cell& otherCell); - void openContainer(const MWWorld::Ptr& container, bool loot); + void openContainer(const MWWorld::Ptr& container); void closeContainer(const MWWorld::Ptr& container); int getCellSize() const; diff --git a/apps/openmw/mwmp/GUI/GUIChat.cpp b/apps/openmw/mwmp/GUI/GUIChat.cpp index 7e464ce47..414f40269 100644 --- a/apps/openmw/mwmp/GUI/GUIChat.cpp +++ b/apps/openmw/mwmp/GUI/GUIChat.cpp @@ -46,7 +46,7 @@ namespace mwmp delay = 3; // 3 sec. } - void GUIChat::open() + void GUIChat::onOpen() { // Give keyboard focus to the combo box whenever the console is // turned on @@ -54,7 +54,7 @@ namespace mwmp windowState = CHAT_ENABLED; } - void GUIChat::close() + void GUIChat::onClose() { // Apparently, hidden widgets can retain key focus // Remove for MyGUI 3.2.2 @@ -62,9 +62,10 @@ namespace mwmp SetEditState(0); } - void GUIChat::exit() + bool GUIChat::exit() { //WindowBase::exit(); + return true; } void GUIChat::acceptCommand(MyGUI::EditBox *_sender) diff --git a/apps/openmw/mwmp/GUI/GUIChat.hpp b/apps/openmw/mwmp/GUI/GUIChat.hpp index ca75ec21d..059882561 100644 --- a/apps/openmw/mwmp/GUI/GUIChat.hpp +++ b/apps/openmw/mwmp/GUI/GUIChat.hpp @@ -43,11 +43,10 @@ namespace mwmp void Update(float dt); + virtual void onOpen(); + virtual void onClose(); - virtual void open(); - virtual void close(); - - virtual void exit(); + virtual bool exit(); void setFont(const std::string &fntName); diff --git a/apps/openmw/mwmp/GUI/TextInputDialog.cpp b/apps/openmw/mwmp/GUI/TextInputDialog.cpp index 484bb64d0..38793a6eb 100644 --- a/apps/openmw/mwmp/GUI/TextInputDialog.cpp +++ b/apps/openmw/mwmp/GUI/TextInputDialog.cpp @@ -55,9 +55,9 @@ namespace mwmp setText("TextNote", note); } - void TextInputDialog::open() + void TextInputDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); // Make sure the edit box has focus MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); } diff --git a/apps/openmw/mwmp/GUI/TextInputDialog.hpp b/apps/openmw/mwmp/GUI/TextInputDialog.hpp index 1c755e12d..cf6b3a1ff 100644 --- a/apps/openmw/mwmp/GUI/TextInputDialog.hpp +++ b/apps/openmw/mwmp/GUI/TextInputDialog.hpp @@ -29,7 +29,7 @@ namespace mwmp void setEditPassword(bool value); - virtual void open(); + virtual void onOpen(); /** Event : Dialog finished, OK button clicked.\n signature : void method()\n diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 16a3d4441..691eab1f3 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -719,7 +719,7 @@ void LocalPlayer::addTopics() env.getDialogueManager()->addTopic(topicId); if (env.getWindowManager()->containsMode(MWGui::GM_Dialogue)) - env.getDialogueManager()->updateTopics(); + env.getDialogueManager()->updateActorKnownTopics(); } } @@ -1369,10 +1369,9 @@ void LocalPlayer::storeCellState(ESM::Cell cell, int stateType) cellStateChanges.cellStates.push_back(cellState); } -void LocalPlayer::storeCurrentContainer(const MWWorld::Ptr &container, bool loot) +void LocalPlayer::storeCurrentContainer(const MWWorld::Ptr &container) { currentContainer.refId = container.getCellRef().getRefId(); currentContainer.refNumIndex = container.getCellRef().getRefNum().mIndex; currentContainer.mpNum = container.getCellRef().getMpNum(); - currentContainer.loot = loot; } diff --git a/apps/openmw/mwmp/LocalPlayer.hpp b/apps/openmw/mwmp/LocalPlayer.hpp index 23308428c..7c0a06353 100644 --- a/apps/openmw/mwmp/LocalPlayer.hpp +++ b/apps/openmw/mwmp/LocalPlayer.hpp @@ -86,7 +86,7 @@ namespace mwmp void clearCurrentContainer(); void storeCellState(ESM::Cell cell, int stateType); - void storeCurrentContainer(const MWWorld::Ptr& container, bool loot); + void storeCurrentContainer(const MWWorld::Ptr& container); private: Networking *getNetworking(); diff --git a/apps/openmw/mwmp/WorldEvent.cpp b/apps/openmw/mwmp/WorldEvent.cpp index c7f304ec1..43f663447 100644 --- a/apps/openmw/mwmp/WorldEvent.cpp +++ b/apps/openmw/mwmp/WorldEvent.cpp @@ -142,7 +142,7 @@ void WorldEvent::editContainers(MWWorld::CellStore* cellStore) currentContainer->mpNum == ptrFound.getCellRef().getMpNum()) { MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); - MWBase::Environment::get().getWindowManager()->openContainer(ptrFound, currentContainer->loot); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container, ptrFound); } } } From 08f34e53560417354c3452f8fb7bcd9f530dda70 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sun, 8 Oct 2017 02:42:41 +0300 Subject: [PATCH 270/505] [Client] Fix recent problems with password window --- apps/openmw/mwmp/GUI/TextInputDialog.cpp | 5 +++++ apps/openmw/mwmp/GUI/TextInputDialog.hpp | 1 + apps/openmw/mwmp/GUIController.cpp | 3 ++- files/mygui/tes3mp_text_input.layout | 18 ++++++++++++++---- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmp/GUI/TextInputDialog.cpp b/apps/openmw/mwmp/GUI/TextInputDialog.cpp index 38793a6eb..eaa687f09 100644 --- a/apps/openmw/mwmp/GUI/TextInputDialog.cpp +++ b/apps/openmw/mwmp/GUI/TextInputDialog.cpp @@ -62,6 +62,11 @@ namespace mwmp MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); } + bool TextInputDialog::exit() + { + return false; + } + // widget controls void TextInputDialog::onOkClicked(MyGUI::Widget *_sender) diff --git a/apps/openmw/mwmp/GUI/TextInputDialog.hpp b/apps/openmw/mwmp/GUI/TextInputDialog.hpp index cf6b3a1ff..a79759ffd 100644 --- a/apps/openmw/mwmp/GUI/TextInputDialog.hpp +++ b/apps/openmw/mwmp/GUI/TextInputDialog.hpp @@ -30,6 +30,7 @@ namespace mwmp void setEditPassword(bool value); virtual void onOpen(); + virtual bool exit(); /** Event : Dialog finished, OK button clicked.\n signature : void method()\n diff --git a/apps/openmw/mwmp/GUIController.cpp b/apps/openmw/mwmp/GUIController.cpp index 9f4678819..9cd496887 100644 --- a/apps/openmw/mwmp/GUIController.cpp +++ b/apps/openmw/mwmp/GUIController.cpp @@ -158,12 +158,13 @@ void mwmp::GUIController::showInputBox(const BasePlayer::GUIMessageBox &guiMessa mInputBox->eventDone += MyGUI::newDelegate(this, &GUIController::onInputBoxDone); + mInputBox->setVisible(true); } void mwmp::GUIController::onInputBoxDone(MWGui::WindowBase *parWindow) { //MWBase::WindowManager *windowManager = MWBase::Environment::get().getWindowManager(); - LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "GUIController::OnInputBoxDone: %s.",mInputBox->getTextInput().c_str()); + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "GUIController::onInputBoxDone: %s.",mInputBox->getTextInput().c_str()); Main::get().getLocalPlayer()->guiMessageBox.data = mInputBox->getTextInput(); Main::get().getNetworking()->getPlayerPacket(ID_GUI_MESSAGEBOX)->setPlayer(Main::get().getLocalPlayer()); diff --git a/files/mygui/tes3mp_text_input.layout b/files/mygui/tes3mp_text_input.layout index fd73ab168..7898d3d96 100644 --- a/files/mygui/tes3mp_text_input.layout +++ b/files/mygui/tes3mp_text_input.layout @@ -24,10 +24,20 @@ - - - - + + + + + + + + + + + + + + From 61b1a59814a5632c5519cc32a6a67d584fee5f0a Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sun, 8 Oct 2017 04:16:30 +0300 Subject: [PATCH 271/505] [General] Move server's version printing method to Utils --- apps/openmw-mp/main.cpp | 39 +--------------------------------- components/openmw-mp/Utils.cpp | 36 +++++++++++++++++++++++++++++++ components/openmw-mp/Utils.hpp | 1 + 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/apps/openmw-mp/main.cpp b/apps/openmw-mp/main.cpp index 342c77eda..97f7e352f 100644 --- a/apps/openmw-mp/main.cpp +++ b/apps/openmw-mp/main.cpp @@ -29,41 +29,6 @@ using namespace std; using namespace mwmp; -void printVersion(string version, Version::Version ver, int protocol) -{ - cout << "TES3:MP dedicated server " << version; - cout << " ("; -#if defined(_WIN32) - cout << "Windows"; -#elif defined(__linux) - cout << "Linux"; -#elif defined(__APPLE__) - cout << "OS X"; -#else - cout << "Unknown OS"; -#endif - cout << " "; -#ifdef __x86_64__ - cout << "64-bit"; -#elif defined(__i386__) || defined(_M_I86) - cout << "32-bit"; -#elif defined(__ARM_ARCH) - cout << "ARMv" << __ARM_ARCH << " "; - #ifdef __aarch64__ - cout << "64-bit"; - #else - cout << "32-bit"; - #endif -#else - cout << "Unknown architecture"; -#endif - cout << ")" << endl; - cout << "Protocol version: " << protocol << endl; - cout << "Commit hash: " << ver.mCommitHash.substr(0, 10) << endl; - - cout << "------------------------------------------------------------" << endl; -} - #ifdef ENABLE_BREAKPAD google_breakpad::ExceptionHandler *pHandler = 0; #if defined(_WIN32) @@ -230,9 +195,7 @@ int main(int argc, char *argv[]) vector plugins (Utils::split(mgr.getString("plugins", "Plugins"), ',')); - - printVersion(TES3MP_VERSION, version, TES3MP_PROTO_VERSION); - + Utils::printVersion("TES3MP dedicated server", TES3MP_VERSION, version.mCommitHash, TES3MP_PROTO_VERSION); setenv("AMXFILE", moddir.c_str(), 1); setenv("MOD_DIR", moddir.c_str(), 1); // hack for lua diff --git a/components/openmw-mp/Utils.cpp b/components/openmw-mp/Utils.cpp index 14a194268..ea5161b0a 100644 --- a/components/openmw-mp/Utils.cpp +++ b/components/openmw-mp/Utils.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -149,6 +150,41 @@ unsigned int ::Utils::crc32Checksum(const std::string &file) return crc32.checksum(); } +void Utils::printVersion(std::string appName, std::string version, std::string commitHash, int protocol) +{ + cout << appName << " " << version; + cout << " ("; +#if defined(_WIN32) + cout << "Windows"; +#elif defined(__linux) + cout << "Linux"; +#elif defined(__APPLE__) + cout << "OS X"; +#else + cout << "Unknown OS"; +#endif + cout << " "; +#ifdef __x86_64__ + cout << "64-bit"; +#elif defined(__i386__) || defined(_M_I86) + cout << "32-bit"; +#elif defined(__ARM_ARCH) + cout << "ARMv" << __ARM_ARCH << " "; +#ifdef __aarch64__ + cout << "64-bit"; +#else + cout << "32-bit"; +#endif +#else + cout << "Unknown architecture"; +#endif + cout << ")" << endl; + cout << "Protocol version: " << protocol << endl; + cout << "Commit hash: " << commitHash.substr(0, 10) << endl; + + cout << "------------------------------------------------------------" << endl; +} + void Utils::printWithWidth(ostringstream &sstr, string str, size_t width) { sstr << left << setw(width) << setfill(' ') << str; diff --git a/components/openmw-mp/Utils.hpp b/components/openmw-mp/Utils.hpp index 00cbd8cab..448cb13d7 100644 --- a/components/openmw-mp/Utils.hpp +++ b/components/openmw-mp/Utils.hpp @@ -36,6 +36,7 @@ namespace Utils unsigned int crc32Checksum(const std::string &file); + void printVersion(std::string appName, std::string version, std::string commitHash, int protocol); void printWithWidth(std::ostringstream &sstr, std::string str, size_t width); std::string intToHexStr(unsigned val); From 3d38da0e85a635e78f5301416e22206dfd67b6c0 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sun, 8 Oct 2017 05:17:14 +0300 Subject: [PATCH 272/505] [Server] Put includes in a specific order --- apps/openmw-mp/main.cpp | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/apps/openmw-mp/main.cpp b/apps/openmw-mp/main.cpp index 97f7e352f..f9c490a08 100644 --- a/apps/openmw-mp/main.cpp +++ b/apps/openmw-mp/main.cpp @@ -1,26 +1,29 @@ -#include -#include -#include "Player.hpp" -#include "Networking.hpp" -#include "MasterClient.hpp" -#include -#include -#include -#include -#include #include -#include -#include + +#include #include #include -#include + +#include +#include +#include +#include + +#include +#include #include -#include "Utils.hpp" +#include +#include +#include +#include + +#include "Player.hpp" +#include "Networking.hpp" #include "MasterClient.hpp" +#include "Utils.hpp" -#include -#include +#include #ifdef ENABLE_BREAKPAD #include From 182f8c1f06cb9acee49b262e58c58b8d590796b7 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sun, 8 Oct 2017 06:17:53 +0300 Subject: [PATCH 273/505] [General] Print client version on startup --- apps/openmw/main.cpp | 25 +++++++++++++++++++++++-- components/openmw-mp/Utils.cpp | 2 +- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 1421930e2..65a706c95 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -49,9 +49,11 @@ extern int is_debugger_attached(void); /* Start of tes3mp addition - Include the header of the logger added for multiplayer + Include additional headers for multiplayer purposes */ #include +#include +#include /* End of tes3mp addition */ @@ -207,7 +209,26 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat cfgMgr.readConfiguration(variables, desc); Version::Version v = Version::getOpenmwVersion(variables["resources"].as().toStdString()); - std::cout << v.describe() << std::endl; + + /* + Start of tes3mp addition + + Print the multiplayer version first + */ + Utils::printVersion("TES3MP client", TES3MP_VERSION, v.mCommitHash, TES3MP_PROTO_VERSION); + /* + End of tes3mp addition + */ + + /* + Start of tes3mp change (minor) + + Because there is no need to print the commit hash again, only print OpenMW's version + */ + std::cout << "OpenMW version " << v.mVersion << std::endl; + /* + End of tes3mp change (minor) + */ engine.setGrabMouse(!variables["no-grab"].as()); diff --git a/components/openmw-mp/Utils.cpp b/components/openmw-mp/Utils.cpp index ea5161b0a..a4a4b6e7b 100644 --- a/components/openmw-mp/Utils.cpp +++ b/components/openmw-mp/Utils.cpp @@ -164,7 +164,7 @@ void Utils::printVersion(std::string appName, std::string version, std::string c cout << "Unknown OS"; #endif cout << " "; -#ifdef __x86_64__ +#if defined(__x86_64__) || defined(_M_X64) cout << "64-bit"; #elif defined(__i386__) || defined(_M_I86) cout << "32-bit"; From ea3729790f113120d98fae5940e62f6d852a4e5c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 8 Oct 2017 09:20:07 +0400 Subject: [PATCH 274/505] Add showsInInventory() check to the ContainerItemModel --- apps/openmw/mwgui/containeritemmodel.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index 479638672..9f7a9965c 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -142,6 +142,9 @@ void ContainerItemModel::update() for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { + if (!(*it).getClass().showsInInventory(*it)) + continue; + std::vector::iterator itemStack = mItems.begin(); for (; itemStack != mItems.end(); ++itemStack) { From dc127fbb93316865f8023977ccb29b91b8f3ad5b Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 8 Oct 2017 11:58:38 +0200 Subject: [PATCH 275/505] Add a launch checkbox to the OpenMW installer --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0050104cf..50c0d5455 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -497,6 +497,7 @@ if(WIN32) SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_INSTALLED_ICON_NAME "openmw-launcher.exe") + SET(CPACK_NSIS_MUI_FINISHPAGE_RUN "openmw-launcher.exe") SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico") SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico") SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp") From 479f9535b43fdc528539a632413e35e415007924 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 8 Oct 2017 20:38:20 +0000 Subject: [PATCH 276/505] Allow training window exit() --- apps/openmw/mwgui/trainingwindow.cpp | 6 ++++++ apps/openmw/mwgui/trainingwindow.hpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index b6504d223..04b051e16 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -203,4 +203,10 @@ namespace MWGui checkReferenceAvailable(); mTimeAdvancer.onFrame(dt); } + + bool TrainingWindow::exit() + { + return !mTimeAdvancer.isRunning(); + } + } diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index 69a013059..2edad1f27 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -16,7 +16,7 @@ namespace MWGui virtual void onOpen(); - bool exit() { return false; } + bool exit(); void setPtr(const MWWorld::Ptr& actor); From 4f112ba3d76c02b9a91f5aee20631912d819fe44 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Tue, 10 Oct 2017 04:05:36 +0300 Subject: [PATCH 277/505] [Client] Use regular message boxes where expected to do so This helps us move towards using the same terminology as OpenMW for GUI elements, leading to less confusion. --- apps/openmw/mwmp/GUIController.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwmp/GUIController.cpp b/apps/openmw/mwmp/GUIController.cpp index 9cd496887..e06b4248b 100644 --- a/apps/openmw/mwmp/GUIController.cpp +++ b/apps/openmw/mwmp/GUIController.cpp @@ -118,9 +118,7 @@ void mwmp::GUIController::showDialogList(const mwmp::BasePlayer::GUIMessageBox & void mwmp::GUIController::showMessageBox(const BasePlayer::GUIMessageBox &guiMessageBox) { MWBase::WindowManager *windowManager = MWBase::Environment::get().getWindowManager(); - std::vector buttons; - buttons.push_back("Ok"); - windowManager->interactiveMessageBox(guiMessageBox.label, buttons); + windowManager->messageBox(guiMessageBox.label); calledMessageBox = true; } From c35101cc3636400a44022215bba15e95213562e7 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Tue, 10 Oct 2017 04:11:36 +0300 Subject: [PATCH 278/505] [Client] Don't use message box call boolean for regular message boxes --- apps/openmw/mwmp/GUIController.cpp | 9 ++++----- apps/openmw/mwmp/GUIController.hpp | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmp/GUIController.cpp b/apps/openmw/mwmp/GUIController.cpp index e06b4248b..cff86664a 100644 --- a/apps/openmw/mwmp/GUIController.cpp +++ b/apps/openmw/mwmp/GUIController.cpp @@ -43,7 +43,7 @@ mwmp::GUIController::GUIController(): mInputBox(0), mListBox(0) mChat = nullptr; keySay = SDL_SCANCODE_Y; keyChatMode = SDL_SCANCODE_F2; - calledMessageBox = false; + calledInteractiveMessage = false; } mwmp::GUIController::~GUIController() @@ -119,7 +119,6 @@ void mwmp::GUIController::showMessageBox(const BasePlayer::GUIMessageBox &guiMes { MWBase::WindowManager *windowManager = MWBase::Environment::get().getWindowManager(); windowManager->messageBox(guiMessageBox.label); - calledMessageBox = true; } std::vector splitString(const std::string &str, char delim = ';') @@ -137,7 +136,7 @@ void mwmp::GUIController::showCustomMessageBox(const BasePlayer::GUIMessageBox & MWBase::WindowManager *windowManager = MWBase::Environment::get().getWindowManager(); std::vector buttons = splitString(guiMessageBox.buttons); windowManager->interactiveMessageBox(guiMessageBox.label, buttons); - calledMessageBox = true; + calledInteractiveMessage = true; } void mwmp::GUIController::showInputBox(const BasePlayer::GUIMessageBox &guiMessageBox) @@ -205,10 +204,10 @@ void mwmp::GUIController::update(float dt) // checked somewhere else int pressedButton = MWBase::Environment::get().getWindowManager()->readPressedButton(false); - if (pressedButton != -1 && calledMessageBox) + if (pressedButton != -1 && calledInteractiveMessage) { LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Pressed: %d", pressedButton); - calledMessageBox = false; + calledInteractiveMessage = false; Main::get().getLocalPlayer()->guiMessageBox.data = MyGUI::utility::toString(pressedButton); Main::get().getNetworking()->getPlayerPacket(ID_GUI_MESSAGEBOX)->setPlayer(Main::get().getLocalPlayer()); Main::get().getNetworking()->getPlayerPacket(ID_GUI_MESSAGEBOX)->Send(); diff --git a/apps/openmw/mwmp/GUIController.hpp b/apps/openmw/mwmp/GUIController.hpp index 8e6efba15..db42d692f 100644 --- a/apps/openmw/mwmp/GUIController.hpp +++ b/apps/openmw/mwmp/GUIController.hpp @@ -69,7 +69,7 @@ namespace mwmp int keyChatMode; long id; - bool calledMessageBox; + bool calledInteractiveMessage; TextInputDialog *mInputBox; GUIDialogList *mListBox; void onInputBoxDone(MWGui::WindowBase* parWindow); From f8fe992dc0bdc393f847812bd321daf0eed32451 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 11 Oct 2017 21:58:55 +0100 Subject: [PATCH 279/505] Adjust CMake's run-time resource handling such that the Windows CI script does not have to copy these files --- CI/before_script.msvc.sh | 15 --------------- CMakeLists.txt | 24 ++++++++++++------------ cmake/GitVersion.cmake | 18 +++++++++++++++++- cmake/OpenMWMacros.cmake | 29 +++++++++++++++++++++++++++++ components/CMakeLists.txt | 9 ++++++--- files/mygui/CMakeLists.txt | 4 ++-- files/shaders/CMakeLists.txt | 4 ++-- 7 files changed, 68 insertions(+), 35 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 14998a3c6..a7f30d7ed 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -750,19 +750,4 @@ if [ -z $VERBOSE ]; then fi fi -if [ -z $CI ]; then - echo "- Copying Runtime Resources/Config Files" - echo " gamecontrollerdb.txt" - cp gamecontrollerdb.txt $BUILD_CONFIG/gamecontrollerdb.txt - echo " openmw.cfg" - cp openmw.cfg.install $BUILD_CONFIG/openmw.cfg - echo " openmw-cs.cfg" - cp openmw-cs.cfg $BUILD_CONFIG/openmw-cs.cfg - echo " settings-default.cfg" - cp settings-default.cfg $BUILD_CONFIG/settings-default.cfg - echo " resources/" - cp -r resources $BUILD_CONFIG/resources - echo -fi - exit $RET diff --git a/CMakeLists.txt b/CMakeLists.txt index 50c0d5455..2bf2896da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -313,27 +313,27 @@ endif (APPLE) # Other files -configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg - "${OpenMW_BINARY_DIR}/settings-default.cfg") +configure_resource_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg + "${OpenMW_BINARY_DIR}" "settings-default.cfg") if (NOT APPLE) - configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local - "${OpenMW_BINARY_DIR}/openmw.cfg") - configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg - "${OpenMW_BINARY_DIR}/openmw.cfg.install") + configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local + "${OpenMW_BINARY_DIR}" "openmw.cfg") + configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg + "${OpenMW_BINARY_DIR}" "openmw.cfg.install") else () configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg "${OpenMW_BINARY_DIR}/openmw.cfg") endif () -configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg - "${OpenMW_BINARY_DIR}/openmw-cs.cfg") +configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg + "${OpenMW_BINARY_DIR}" "openmw-cs.cfg") -configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters - "${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY) +configure_resource_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters + "${OpenMW_BINARY_DIR}" "resources/defaultfilters" COPYONLY) -configure_file(${OpenMW_SOURCE_DIR}/files/gamecontrollerdb.txt - "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt") +configure_resource_file(${OpenMW_SOURCE_DIR}/files/gamecontrollerdb.txt + "${OpenMW_BINARY_DIR}" "gamecontrollerdb.txt") if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop diff --git a/cmake/GitVersion.cmake b/cmake/GitVersion.cmake index 32abbbfbf..0eefe01e6 100644 --- a/cmake/GitVersion.cmake +++ b/cmake/GitVersion.cmake @@ -26,4 +26,20 @@ else () message(WARNING "Failed to get valid version information from Git") endif () -configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) +# duplicated from OpenMWMacros.cmake +macro (configure_resource_file source_path destination_dir_base dest_path_relative) + if (MSVC) + configure_file(${source_path} "${destination_dir_base}/Debug/${dest_path_relative}") + configure_file(${source_path} "${destination_dir_base}/Release/${dest_path_relative}") + configure_file(${source_path} "${destination_dir_base}/RelWithDebInfo/${dest_path_relative}") + configure_file(${source_path} "${destination_dir_base}/MinSizeRel/${dest_path_relative}") + else (MSVC) + configure_file(${source_path} "${destination_dir_base}/${dest_path_relative}") + endif (MSVC) +endmacro (configure_resource_file) + +message(STATUS ${VERSION_IN_FILE}) +message(STATUS ${VERSION_FILE_PATH_BASE}) +message(STATUS ${VERSION_FILE_PATH_RELATIVE}) + +configure_resource_file(${VERSION_IN_FILE} ${VERSION_FILE_PATH_BASE} ${VERSION_FILE_PATH_RELATIVE}) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 6573265bd..08b36017b 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -171,3 +171,32 @@ macro (openmw_add_executable target) endif (CMAKE_VERSION VERSION_GREATER 3.8 OR CMAKE_VERSION VERSION_EQUAL 3.8) endif (MSVC) endmacro (openmw_add_executable) + +macro (copy_resource_file source_path destination_dir_base dest_path_relative) + if (MSVC) + configure_file(${source_path} "${destination_dir_base}/Debug/${dest_path_relative}" COPYONLY) + configure_file(${source_path} "${destination_dir_base}/Release/${dest_path_relative}" COPYONLY) + configure_file(${source_path} "${destination_dir_base}/RelWithDebInfo/${dest_path_relative}" COPYONLY) + configure_file(${source_path} "${destination_dir_base}/MinSizeRel/${dest_path_relative}" COPYONLY) + else (MSVC) + configure_file(${source_path} "${destination_dir_base}/${dest_path_relative}" COPYONLY) + endif (MSVC) +endmacro (copy_resource_file) + +macro (configure_resource_file source_path destination_dir_base dest_path_relative) + if (MSVC) + configure_file(${source_path} "${destination_dir_base}/Debug/${dest_path_relative}") + configure_file(${source_path} "${destination_dir_base}/Release/${dest_path_relative}") + configure_file(${source_path} "${destination_dir_base}/RelWithDebInfo/${dest_path_relative}") + configure_file(${source_path} "${destination_dir_base}/MinSizeRel/${dest_path_relative}") + else (MSVC) + configure_file(${source_path} "${destination_dir_base}/${dest_path_relative}") + endif (MSVC) +endmacro (configure_resource_file) + +macro (copy_all_resource_files source_dir destination_dir_base destination_dir_relative files) + foreach (f ${files}) + get_filename_component(filename ${f} NAME) + copy_resource_file("${source_dir}/${f}" "${destination_dir_base}" "${destination_dir_relative}/${filename}") + endforeach (f) +endmacro (copy_all_files) \ No newline at end of file diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 88de17903..bb22e047c 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -2,22 +2,25 @@ project (Components) # Version file set (VERSION_IN_FILE "${OpenMW_SOURCE_DIR}/files/version.in") -set (VERSION_FILE "${OpenMW_BINARY_DIR}/resources/version") +set (VERSION_FILE_PATH_BASE "${OpenMW_BINARY_DIR}") +set (VERSION_FILE_PATH_RELATIVE resources/version) if (GIT_CHECKOUT) add_custom_target (git-version COMMAND ${CMAKE_COMMAND} -DGIT_EXECUTABLE=${GIT_EXECUTABLE} -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} -DVERSION_IN_FILE=${VERSION_IN_FILE} - -DVERSION_FILE=${VERSION_FILE} + -DVERSION_FILE_PATH_BASE=${VERSION_FILE_PATH_BASE} + -DVERSION_FILE_PATH_RELATIVE=${VERSION_FILE_PATH_RELATIVE} -DOPENMW_VERSION_MAJOR=${OPENMW_VERSION_MAJOR} -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} -DOPENMW_VERSION=${OPENMW_VERSION} + -DMSVC=${MSVC} -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake VERBATIM) else (GIT_CHECKOUT) - configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) + configure_resource_file(${VERSION_IN_FILE} ${VERSION_FILE_PATH_BASE} ${VERSION_FILE_PATH_RELATIVE}) endif (GIT_CHECKOUT) if (OPENGL_ES) diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index ed673c5d6..49b833e38 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -4,7 +4,7 @@ endif() # Copy resource files into the build directory set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(DDIR ${OPENMW_MYGUI_FILES_ROOT}/resources/mygui) +set(DDIRRELATIVE resources/mygui) set(MYGUI_FILES core.skin @@ -97,4 +97,4 @@ set(MYGUI_FILES ) -copy_all_files(${CMAKE_CURRENT_SOURCE_DIR} ${DDIR} "${MYGUI_FILES}") +copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_MYGUI_FILES_ROOT} ${DDIRRELATIVE} "${MYGUI_FILES}") diff --git a/files/shaders/CMakeLists.txt b/files/shaders/CMakeLists.txt index 5ca0d1e83..5833a592f 100644 --- a/files/shaders/CMakeLists.txt +++ b/files/shaders/CMakeLists.txt @@ -4,7 +4,7 @@ endif() # Copy resource files into the build directory set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(DDIR ${OPENMW_SHADERS_ROOT}/resources/shaders) +set(DDIRRELATIVE resources/shaders) set(SHADER_FILES water_vertex.glsl @@ -18,4 +18,4 @@ set(SHADER_FILES parallax.glsl ) -copy_all_files(${CMAKE_CURRENT_SOURCE_DIR} ${DDIR} "${SHADER_FILES}") +copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_SHADERS_ROOT} ${DDIRRELATIVE} "${SHADER_FILES}") From 5ceaaabeb2c8a448cd220e06c6f39c121fbc381e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 11 Oct 2017 22:08:49 +0100 Subject: [PATCH 280/505] Remove MESSAGE calls I accidentally left in --- cmake/GitVersion.cmake | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cmake/GitVersion.cmake b/cmake/GitVersion.cmake index 0eefe01e6..786ac23ed 100644 --- a/cmake/GitVersion.cmake +++ b/cmake/GitVersion.cmake @@ -38,8 +38,4 @@ macro (configure_resource_file source_path destination_dir_base dest_path_relati endif (MSVC) endmacro (configure_resource_file) -message(STATUS ${VERSION_IN_FILE}) -message(STATUS ${VERSION_FILE_PATH_BASE}) -message(STATUS ${VERSION_FILE_PATH_RELATIVE}) - configure_resource_file(${VERSION_IN_FILE} ${VERSION_FILE_PATH_BASE} ${VERSION_FILE_PATH_RELATIVE}) From 2652a89df4425017b7d1a62a4bf9ce493a8d7282 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 11 Oct 2017 22:10:52 +0100 Subject: [PATCH 281/505] Fix mismatched indentation that apparently the .editorconfig file doesn't handle automatically --- components/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index bb22e047c..a8b7f1fd2 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -16,7 +16,7 @@ if (GIT_CHECKOUT) -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} -DOPENMW_VERSION=${OPENMW_VERSION} - -DMSVC=${MSVC} + -DMSVC=${MSVC} -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake VERBATIM) else (GIT_CHECKOUT) From f9a3562ccdec731e560d59e4a9f8844b0ed7584a Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Oct 2017 02:45:50 +0100 Subject: [PATCH 282/505] Remove duplicate macro definition and fix warning --- cmake/GitVersion.cmake | 12 +----------- cmake/OpenMWMacros.cmake | 2 +- components/CMakeLists.txt | 1 + 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/cmake/GitVersion.cmake b/cmake/GitVersion.cmake index 786ac23ed..ff719d72a 100644 --- a/cmake/GitVersion.cmake +++ b/cmake/GitVersion.cmake @@ -26,16 +26,6 @@ else () message(WARNING "Failed to get valid version information from Git") endif () -# duplicated from OpenMWMacros.cmake -macro (configure_resource_file source_path destination_dir_base dest_path_relative) - if (MSVC) - configure_file(${source_path} "${destination_dir_base}/Debug/${dest_path_relative}") - configure_file(${source_path} "${destination_dir_base}/Release/${dest_path_relative}") - configure_file(${source_path} "${destination_dir_base}/RelWithDebInfo/${dest_path_relative}") - configure_file(${source_path} "${destination_dir_base}/MinSizeRel/${dest_path_relative}") - else (MSVC) - configure_file(${source_path} "${destination_dir_base}/${dest_path_relative}") - endif (MSVC) -endmacro (configure_resource_file) +include(${MACROSFILE}) configure_resource_file(${VERSION_IN_FILE} ${VERSION_FILE_PATH_BASE} ${VERSION_FILE_PATH_RELATIVE}) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 08b36017b..aac38a7f6 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -199,4 +199,4 @@ macro (copy_all_resource_files source_dir destination_dir_base destination_dir_r get_filename_component(filename ${f} NAME) copy_resource_file("${source_dir}/${f}" "${destination_dir_base}" "${destination_dir_relative}/${filename}") endforeach (f) -endmacro (copy_all_files) \ No newline at end of file +endmacro (copy_all_resource_files) \ No newline at end of file diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a8b7f1fd2..b8ade0a67 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -17,6 +17,7 @@ if (GIT_CHECKOUT) -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} -DOPENMW_VERSION=${OPENMW_VERSION} -DMSVC=${MSVC} + -DMACROSFILE=${CMAKE_SOURCE_DIR}/cmake/OpenMWMacros.cmake -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake VERBATIM) else (GIT_CHECKOUT) From b00b94f0dbefa99d42f861bf691125c4255f62fd Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Oct 2017 15:40:37 +0100 Subject: [PATCH 283/505] Use CMAKE_CONFIGURATION_TYPES instead of manually listing the possible configuration types. --- cmake/OpenMWMacros.cmake | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index aac38a7f6..ed1023c5d 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -173,25 +173,15 @@ macro (openmw_add_executable target) endmacro (openmw_add_executable) macro (copy_resource_file source_path destination_dir_base dest_path_relative) - if (MSVC) - configure_file(${source_path} "${destination_dir_base}/Debug/${dest_path_relative}" COPYONLY) - configure_file(${source_path} "${destination_dir_base}/Release/${dest_path_relative}" COPYONLY) - configure_file(${source_path} "${destination_dir_base}/RelWithDebInfo/${dest_path_relative}" COPYONLY) - configure_file(${source_path} "${destination_dir_base}/MinSizeRel/${dest_path_relative}" COPYONLY) - else (MSVC) - configure_file(${source_path} "${destination_dir_base}/${dest_path_relative}" COPYONLY) - endif (MSVC) + foreach(cfgtype ${CMAKE_CONFIGURATION_TYPES}) + configure_file(${source_path} "${destination_dir_base}/${cfgtype}/${dest_path_relative}" COPYONLY) + endforeach(cfgtype) endmacro (copy_resource_file) macro (configure_resource_file source_path destination_dir_base dest_path_relative) - if (MSVC) - configure_file(${source_path} "${destination_dir_base}/Debug/${dest_path_relative}") - configure_file(${source_path} "${destination_dir_base}/Release/${dest_path_relative}") - configure_file(${source_path} "${destination_dir_base}/RelWithDebInfo/${dest_path_relative}") - configure_file(${source_path} "${destination_dir_base}/MinSizeRel/${dest_path_relative}") - else (MSVC) - configure_file(${source_path} "${destination_dir_base}/${dest_path_relative}") - endif (MSVC) + foreach(cfgtype ${CMAKE_CONFIGURATION_TYPES}) + configure_file(${source_path} "${destination_dir_base}/${cfgtype}/${dest_path_relative}") + endforeach(cfgtype) endmacro (configure_resource_file) macro (copy_all_resource_files source_dir destination_dir_base destination_dir_relative files) From 1f86fa3c3183255833cb81bcd95f7e7a3e3e4967 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Oct 2017 17:09:01 +0100 Subject: [PATCH 284/505] Fix resource copying on non-MSVC targets --- cmake/OpenMWMacros.cmake | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index ed1023c5d..5e6efaa0f 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -172,16 +172,34 @@ macro (openmw_add_executable target) endif (MSVC) endmacro (openmw_add_executable) +macro (get_generator_is_multi_config VALUE) + if (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) + set(${VALUE} ${GENERATOR_IS_MULTI_CONFIG}) + else (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) + list(LENGTH ${CMAKE_CONFIGURATION_TYPES} ${VALUE}) + endif ((CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9)) +endmacro (get_generator_is_multi_config) + macro (copy_resource_file source_path destination_dir_base dest_path_relative) - foreach(cfgtype ${CMAKE_CONFIGURATION_TYPES}) - configure_file(${source_path} "${destination_dir_base}/${cfgtype}/${dest_path_relative}" COPYONLY) - endforeach(cfgtype) + get_generator_is_multi_config(multi_config) + if (multi_config) + foreach(cfgtype ${CMAKE_CONFIGURATION_TYPES}) + configure_file(${source_path} "${destination_dir_base}/${cfgtype}/${dest_path_relative}" COPYONLY) + endforeach(cfgtype) + else (multi_config) + configure_file(${source_path} "${destination_dir_base}/${dest_path_relative}" COPYONLY) + endif (multi_config) endmacro (copy_resource_file) macro (configure_resource_file source_path destination_dir_base dest_path_relative) - foreach(cfgtype ${CMAKE_CONFIGURATION_TYPES}) - configure_file(${source_path} "${destination_dir_base}/${cfgtype}/${dest_path_relative}") - endforeach(cfgtype) + get_generator_is_multi_config(multi_config) + if (multi_config) + foreach(cfgtype ${CMAKE_CONFIGURATION_TYPES}) + configure_file(${source_path} "${destination_dir_base}/${cfgtype}/${dest_path_relative}") + endforeach(cfgtype) + else (multi_config) + configure_file(${source_path} "${destination_dir_base}/${dest_path_relative}") + endif (multi_config) endmacro (configure_resource_file) macro (copy_all_resource_files source_dir destination_dir_base destination_dir_relative files) From 76c4ff983af0d043845719f5d333c92584d295cf Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Oct 2017 17:17:25 +0100 Subject: [PATCH 285/505] Fix getting cmake property as variable --- cmake/OpenMWMacros.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 5e6efaa0f..18b410d3e 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -174,10 +174,10 @@ endmacro (openmw_add_executable) macro (get_generator_is_multi_config VALUE) if (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) - set(${VALUE} ${GENERATOR_IS_MULTI_CONFIG}) + get_cmake_property(${VALUE} GENERATOR_IS_MULTI_CONFIG) else (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) list(LENGTH ${CMAKE_CONFIGURATION_TYPES} ${VALUE}) - endif ((CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9)) + endif (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) endmacro (get_generator_is_multi_config) macro (copy_resource_file source_path destination_dir_base dest_path_relative) From 6af8ad70a53629c88ce7046cb6dc5e124091b3a0 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Oct 2017 17:50:20 +0100 Subject: [PATCH 286/505] Remove superfluous copy_all_files macro --- cmake/OpenMWMacros.cmake | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 18b410d3e..c3ba197e4 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -88,13 +88,6 @@ endforeach (u) source_group ("components\\${dir}" FILES ${files}) endmacro (add_component_qt_dir) -macro (copy_all_files source_dir destination_dir files) -foreach (f ${files}) -get_filename_component(filename ${f} NAME) -configure_file(${source_dir}/${f} ${destination_dir}/${filename} COPYONLY) -endforeach (f) -endmacro (copy_all_files) - macro (add_file project type file) list (APPEND ${project}${type} ${file}) endmacro (add_file) From a52c485090998af0f669f717ffe7b470d5ba9f6c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Oct 2017 18:16:10 +0100 Subject: [PATCH 287/505] Fix list length error --- cmake/OpenMWMacros.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index c3ba197e4..5f66705e7 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -169,7 +169,7 @@ macro (get_generator_is_multi_config VALUE) if (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) get_cmake_property(${VALUE} GENERATOR_IS_MULTI_CONFIG) else (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) - list(LENGTH ${CMAKE_CONFIGURATION_TYPES} ${VALUE}) + list(LENGTH "${CMAKE_CONFIGURATION_TYPES}" ${VALUE}) endif (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) endmacro (get_generator_is_multi_config) From c9e86a8ebc5bed5492ec0df46e1940c4821a28c9 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Oct 2017 18:16:44 +0100 Subject: [PATCH 288/505] Remove superfluous argument --- components/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index b8ade0a67..e9b992e02 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -16,7 +16,6 @@ if (GIT_CHECKOUT) -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} -DOPENMW_VERSION=${OPENMW_VERSION} - -DMSVC=${MSVC} -DMACROSFILE=${CMAKE_SOURCE_DIR}/cmake/OpenMWMacros.cmake -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake VERBATIM) From a25903b075a567b9c6eef47874b42433a5312150 Mon Sep 17 00:00:00 2001 From: glbwsk Date: Fri, 13 Oct 2017 14:39:44 +0200 Subject: [PATCH 289/505] fixed autoequiping rings by npc - now checks if right hand is free --- .gitignore | 1 + apps/openmw/mwworld/inventorystore.cpp | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/.gitignore b/.gitignore index 9fbb82dba..e9e518c7d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ Makefile makefile build* prebuilt +cmake-build-debug/ ##windows build process /deps diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 77141f269..7c3271cc2 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -315,6 +315,14 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) } else if (iter.getType() == ContainerStore::Type_Clothing) { + if (*iter2 == MWWorld::InventoryStore::Slot_LeftRing) + { + if (slots_.at(MWWorld::InventoryStore::Slot_RightRing) == end()) + { + continue; + } + } + if (old.getTypeName() == typeid(ESM::Clothing).name()) { // check value From e6e482ea9890ef8d4b5a2d89d6b00f9d80f99670 Mon Sep 17 00:00:00 2001 From: glbwsk Date: Fri, 13 Oct 2017 14:47:26 +0200 Subject: [PATCH 290/505] added some comments for autoEquip --- apps/openmw/mwworld/inventorystore.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 7c3271cc2..c28e6a109 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -266,6 +266,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) // Autoequip clothing, armor and weapons. // Equipping lights is handled in Actors::updateEquippedLight based on environment light. + // the main loop iterating through all items in inventory for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter) { Ptr test = *iter; @@ -290,9 +291,13 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) std::pair, bool> itemsSlots = iter->getClass().getEquipmentSlots (*iter); + // nested loop for iterating through avialable NPC slots for equipped items + // and checking if current item poited by iter can be placed there for (std::vector::const_iterator iter2 (itemsSlots.first.begin()); iter2!=itemsSlots.first.end(); ++iter2) { + // if true then it means slot is equipped already + // check if slot may require swapping if current item is more valueable if (slots_.at (*iter2)!=end()) { Ptr old = *slots_.at (*iter2); @@ -315,8 +320,10 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) } else if (iter.getType() == ContainerStore::Type_Clothing) { + // if left ring is equipped if (*iter2 == MWWorld::InventoryStore::Slot_LeftRing) { + // if there is a place for right ring dont swap left leaving right hand empty if (slots_.at(MWWorld::InventoryStore::Slot_RightRing) == end()) { continue; @@ -345,6 +352,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) } } + // if we are here it means item can be equipped or swapped slots_[*iter2] = iter; break; } From ff9cb22a58fc9dbb233b223a15e93b3914ed428e Mon Sep 17 00:00:00 2001 From: glbwsk Date: Fri, 13 Oct 2017 15:16:07 +0200 Subject: [PATCH 291/505] npc swap cheaper ring during auto equip --- apps/openmw/mwworld/inventorystore.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index c28e6a109..40f9c741a 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -321,13 +321,23 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) else if (iter.getType() == ContainerStore::Type_Clothing) { // if left ring is equipped - if (*iter2 == MWWorld::InventoryStore::Slot_LeftRing) + if (*iter2 == Slot_LeftRing) { // if there is a place for right ring dont swap left leaving right hand empty - if (slots_.at(MWWorld::InventoryStore::Slot_RightRing) == end()) + if (slots_.at(Slot_RightRing) == end()) { continue; } + else // if right ring is equipped too + { + Ptr rightRing = *slots_.at(Slot_RightRing); + + // we want to swap cheaper ring only if both are equipped + if (rightRing.getClass().getValue(rightRing) < old.getClass().getValue(old)) + { + continue; + } + } } if (old.getTypeName() == typeid(ESM::Clothing).name()) From 548e90a7bc493fe032a1858550a0a648e58976bb Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 13 Oct 2017 16:22:44 +0000 Subject: [PATCH 292/505] Set cursor active when moving by controller --- apps/openmw/mwinput/inputmanagerimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 06ebeb0b8..a5bb93b6c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -430,6 +430,7 @@ namespace MWInput MyGUI::InputManager::getInstance().injectMouseMove(static_cast(mGuiCursorX), static_cast(mGuiCursorY), mMouseWheel); mInputManager->warpMouse(static_cast(mGuiCursorX/mInvUiScalingFactor), static_cast(mGuiCursorY/mInvUiScalingFactor)); + MWBase::Environment::get().getWindowManager()->setCursorActive(true); } } if (mMouseLookEnabled) From 83a5c7c3d87f4e5740b67f271c6007ad16f73d8f Mon Sep 17 00:00:00 2001 From: glbwsk Date: Fri, 13 Oct 2017 20:32:52 +0200 Subject: [PATCH 293/505] removed unnecessary comments, added gitignore for clion cmake --- .gitignore | 2 +- apps/openmw/mwworld/inventorystore.cpp | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index e9e518c7d..672c3ec18 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,6 @@ Makefile makefile build* prebuilt -cmake-build-debug/ ##windows build process /deps @@ -27,6 +26,7 @@ Doxygen .settings .directory .idea +cmake-build-* files/windows/*.aps ## qt-creator CMakeLists.txt.user* diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 40f9c741a..50ee97d1c 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -265,8 +265,6 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) // Autoequip clothing, armor and weapons. // Equipping lights is handled in Actors::updateEquippedLight based on environment light. - - // the main loop iterating through all items in inventory for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter) { Ptr test = *iter; @@ -291,8 +289,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) std::pair, bool> itemsSlots = iter->getClass().getEquipmentSlots (*iter); - // nested loop for iterating through avialable NPC slots for equipped items - // and checking if current item poited by iter can be placed there + // checking if current item poited by iter can be equipped for (std::vector::const_iterator iter2 (itemsSlots.first.begin()); iter2!=itemsSlots.first.end(); ++iter2) { @@ -323,7 +320,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) // if left ring is equipped if (*iter2 == Slot_LeftRing) { - // if there is a place for right ring dont swap left leaving right hand empty + // if there is a place for right ring dont swap it if (slots_.at(Slot_RightRing) == end()) { continue; From a5b39e0842305372ac4cbb100cb1cb0cd4d955cb Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 13 Oct 2017 19:35:49 +0000 Subject: [PATCH 294/505] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 02eb30da0..839a04e42 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -88,6 +88,7 @@ Programmers lazydev Leon Krieg (lkrieg) Leon Saunders (emoose) + Łukasz Gołębiewski (lukago) logzero lohikaarme Lukasz Gromanowski (lgro) From 30b05b557bc70cf6d20b989507499b96018a01be Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 14 Oct 2017 10:23:59 +0400 Subject: [PATCH 295/505] ExtraSpell magic effect: a basic implementation --- apps/openmw/mwmechanics/spellcasting.cpp | 7 +++++++ components/esm/loadmgef.cpp | 1 + 2 files changed, 8 insertions(+) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index a808b8285..a09436d14 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -536,6 +536,13 @@ namespace MWMechanics appliedLastingEffects.push_back(effect); + // Unequip all items, if a spell with the ExtraSpell effect was casted + if (effectIt->mEffectID == ESM::MagicEffect::ExtraSpell && target.getClass().hasInventoryStore(target)) + { + MWWorld::InventoryStore& store = target.getClass().getInventoryStore(target); + store.unequipAll(target); + } + // Command spells should have their effect, including taking the target out of combat, each time the spell successfully affects the target if (((effectIt->mEffectID == ESM::MagicEffect::CommandHumanoid && target.getClass().isNpc()) || (effectIt->mEffectID == ESM::MagicEffect::CommandCreature && target.getTypeName() == typeid(ESM::Creature).name())) diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index 3a918cf19..9f8ad94e1 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -380,6 +380,7 @@ static std::map genNameMap() names[131] ="sEffectBoundGloves"; names[128] ="sEffectBoundHelm"; names[125] ="sEffectBoundLongbow"; + names[126] ="sEffectExtraSpell"; names[121] ="sEffectBoundLongsword"; names[122] ="sEffectBoundMace"; names[130] ="sEffectBoundShield"; From 548af6dbfbdd265c94796fa79f6c87cedabc5135 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 14 Oct 2017 14:02:20 +0000 Subject: [PATCH 296/505] Fix jail screen fading --- apps/openmw/mwgui/jailscreen.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 11d7466a8..9fa5927ac 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -58,6 +58,7 @@ namespace MWGui { MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getWorld()->teleportToClosestMarker(player, "prisonmarker"); + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.f); // override fade-in caused by cell transition setVisible(true); mTimeAdvancer.run(100); From 6d9d98c02cc663d67372a65c1aaea58b35dacc23 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 14 Oct 2017 11:32:42 -0400 Subject: [PATCH 297/505] Merge Land/LandTextures --- apps/opencs/model/tools/mergeoperation.cpp | 4 +- apps/opencs/model/tools/mergestages.cpp | 147 ++++++--------------- apps/opencs/model/tools/mergestages.hpp | 15 ++- 3 files changed, 47 insertions(+), 119 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 9b595046a..cbd2abe0d 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -38,9 +38,9 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeRefIdsStage (mState)); appendStage (new MergeReferencesStage (mState)); appendStage (new MergeReferencesStage (mState)); - appendStage (new ListLandTexturesMergeStage (mState)); - appendStage (new MergeLandTexturesStage (mState)); + appendStage (new PopulateLandTexturesMergeStage (mState)); appendStage (new MergeLandStage (mState)); + appendStage (new FixLandsAndLandTexturesMergeStage (mState)); appendStage (new FinishMergedDocumentStage (mState, encoding)); } diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 176d35914..eea0656b7 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -8,7 +8,9 @@ #include "mergestate.hpp" #include "../doc/document.hpp" +#include "../world/commands.hpp" #include "../world/data.hpp" +#include "../world/idtable.hpp" CSMTools::StartMergeStage::StartMergeStage (MergeState& state) @@ -109,102 +111,32 @@ void CSMTools::MergeReferencesStage::perform (int stage, CSMDoc::Messages& messa } -CSMTools::ListLandTexturesMergeStage::ListLandTexturesMergeStage (MergeState& state) -: mState (state) -{} - -int CSMTools::ListLandTexturesMergeStage::setup() +CSMTools::PopulateLandTexturesMergeStage::PopulateLandTexturesMergeStage (MergeState& state) + : mState (state) { - return mState.mSource.getData().getLand().getSize(); -} - -void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages) -{ - const CSMWorld::Record& record = - mState.mSource.getData().getLand().getRecord (stage); - - if (!record.isDeleted()) - { - const CSMWorld::Land& land = record.get(); - - // make sure record is loaded - land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | - ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX); - - if (const ESM::Land::LandData *data = land.getLandData (ESM::Land::DATA_VTEX)) - { - // list texture indices - std::pair key; - key.second = land.mPlugin; - - for (int i=0; imTextures[i]; - - mState.mTextureIndices[key] = -1; - } - } - } } - -CSMTools::MergeLandTexturesStage::MergeLandTexturesStage (MergeState& state) -: mState (state), mNext (mState.mTextureIndices.end()) -{} - -int CSMTools::MergeLandTexturesStage::setup() +int CSMTools::PopulateLandTexturesMergeStage::setup() { - // Should use the size of mState.mTextureIndices instead, but that is not available at this - // point. Unless there are any errors in the land and land texture records this will not - // make a difference. return mState.mSource.getData().getLandTextures().getSize(); } -void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& messages) +void CSMTools::PopulateLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages) { - if (stage==0) - mNext = mState.mTextureIndices.begin(); + const CSMWorld::Record& record = + mState.mSource.getData().getLandTextures().getRecord (stage); - bool found = false; - - do + if (!record.isDeleted()) { - if (mNext==mState.mTextureIndices.end()) - return; - - mNext->second = stage+1; - - std::ostringstream stream; - stream << mNext->first.first-1 << "_" << mNext->first.second; - - int index = mState.mSource.getData().getLandTextures().searchId (stream.str()); - - if (index!=-1) - { - CSMWorld::LandTexture texture = - mState.mSource.getData().getLandTextures().getRecord (index).get(); - - stream.clear(); - stream << mNext->second-1 << "_0"; - - texture.mIndex = mNext->second-1; - texture.mId = stream.str(); - - CSMWorld::Record newRecord ( - CSMWorld::RecordBase::State_ModifiedOnly, 0, &texture); - - mState.mTarget->getData().getLandTextures().appendRecord (newRecord); - - found = true; - } - - ++mNext; + mState.mTarget->getData().getLandTextures().appendRecord(record); } - while (!found); } -CSMTools::MergeLandStage::MergeLandStage (MergeState& state) : mState (state) {} +CSMTools::MergeLandStage::MergeLandStage (MergeState& state) + : mState (state) +{ +} int CSMTools::MergeLandStage::setup() { @@ -218,40 +150,35 @@ void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages) if (!record.isDeleted()) { - const CSMWorld::Land& land = record.get(); - - land.loadData (ESM::Land::DATA_VCLR | ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | - ESM::Land::DATA_VTEX); + mState.mTarget->getData().getLand().appendRecord (record); + } +} - CSMWorld::Land newLand (land); - newLand.mPlugin = 0; +CSMTools::FixLandsAndLandTexturesMergeStage::FixLandsAndLandTexturesMergeStage (MergeState& state) + : mState (state) +{ +} - if (land.mDataTypes & ESM::Land::DATA_VTEX) - { - // adjust land texture references - if (ESM::Land::LandData *data = newLand.getLandData()) - { - std::pair key; - key.second = land.mPlugin; +int CSMTools::FixLandsAndLandTexturesMergeStage::setup() +{ + // We will have no more than the source + return mState.mSource.getData().getLand().getSize(); +} - for (int i=0; imTextures[i]; - std::map, int>::const_iterator iter = - mState.mTextureIndices.find (key); +void CSMTools::FixLandsAndLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages) +{ + if (stage < mState.mTarget->getData().getLand().getSize()) + { + CSMWorld::IdTable& landTable = dynamic_cast( + *mState.mTarget->getData().getTableModel(CSMWorld::UniversalId::Type_Lands)); - if (iter!=mState.mTextureIndices.end()) - data->mTextures[i] = iter->second; - else - data->mTextures[i] = 0; - } - } - } + CSMWorld::IdTable& ltexTable = dynamic_cast( + *mState.mTarget->getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures)); - CSMWorld::Record newRecord ( - CSMWorld::RecordBase::State_ModifiedOnly, 0, &newLand); + std::string id = mState.mTarget->getData().getLand().getId(stage); - mState.mTarget->getData().getLand().appendRecord (newRecord); + CSMWorld::TouchLandCommand cmd(landTable, ltexTable, id); + cmd.redo(); } } diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index f88f5be9f..96339ed4c 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -116,13 +116,14 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - class ListLandTexturesMergeStage : public CSMDoc::Stage + /// Adds all land texture records that could potentially be referenced when merging + class PopulateLandTexturesMergeStage : public CSMDoc::Stage { MergeState& mState; public: - ListLandTexturesMergeStage (MergeState& state); + PopulateLandTexturesMergeStage (MergeState& state); virtual int setup(); ///< \return number of steps @@ -131,14 +132,13 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - class MergeLandTexturesStage : public CSMDoc::Stage + class MergeLandStage : public CSMDoc::Stage { MergeState& mState; - std::map, int>::iterator mNext; public: - MergeLandTexturesStage (MergeState& state); + MergeLandStage (MergeState& state); virtual int setup(); ///< \return number of steps @@ -147,13 +147,14 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - class MergeLandStage : public CSMDoc::Stage + /// Flattens the added land and land texture records. + class FixLandsAndLandTexturesMergeStage : public CSMDoc::Stage { MergeState& mState; public: - MergeLandStage (MergeState& state); + FixLandsAndLandTexturesMergeStage (MergeState& state); virtual int setup(); ///< \return number of steps From 98c38ad7d1201fe951d8c94ffcff4175f7c90875 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 14 Oct 2017 13:18:31 -0400 Subject: [PATCH 298/505] Merge cleanup. --- apps/opencs/model/tools/mergeoperation.cpp | 1 + apps/opencs/model/tools/mergestages.cpp | 31 ++++++++++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 16 +++++++++++ 3 files changed, 48 insertions(+) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index cbd2abe0d..b15b4b83f 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -41,6 +41,7 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new PopulateLandTexturesMergeStage (mState)); appendStage (new MergeLandStage (mState)); appendStage (new FixLandsAndLandTexturesMergeStage (mState)); + appendStage (new CleanupLandTexturesMergeStage (mState)); appendStage (new FinishMergedDocumentStage (mState, encoding)); } diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index eea0656b7..897c3329c 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -180,5 +180,36 @@ void CSMTools::FixLandsAndLandTexturesMergeStage::perform (int stage, CSMDoc::Me CSMWorld::TouchLandCommand cmd(landTable, ltexTable, id); cmd.redo(); + + // Get rid of base data + const CSMWorld::Record& oldRecord = + mState.mTarget->getData().getLand().getRecord (stage); + + CSMWorld::Record newRecord(CSMWorld::RecordBase::State_ModifiedOnly, + nullptr, &oldRecord.get()); + + mState.mTarget->getData().getLand().setRecord(stage, newRecord); + } +} + +CSMTools::CleanupLandTexturesMergeStage::CleanupLandTexturesMergeStage (MergeState& state) + : mState (state) +{ +} + +int CSMTools::CleanupLandTexturesMergeStage::setup() +{ + return 1; +} + +void CSMTools::CleanupLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages) +{ + auto& landTextures = mState.mTarget->getData().getLandTextures(); + for (int i = 0; i < landTextures.getSize(); ) + { + if (!landTextures.getRecord(i).isModified()) + landTextures.removeRows(i, 1); + else + ++i; } } diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 96339ed4c..9a16e03ab 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -162,6 +162,22 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. }; + + // Removes base LandTexture records. + class CleanupLandTexturesMergeStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + CleanupLandTexturesMergeStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; } #endif From d27071f06a1276e1b5450bb8a02a565516b8b575 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 14 Oct 2017 13:18:54 -0400 Subject: [PATCH 299/505] Fix LTEX import bug. --- apps/opencs/model/world/idtable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index fcfc8577e..3e503a80c 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -336,7 +336,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import int oldRow = idCollection()->searchId(id); // If it does not exist or it is in the current plugin, it can be skipped. - if (oldRow <= 0 || plugin == 0) + if (oldRow < 0 || plugin == 0) { results.recordMapping.push_back(std::make_pair(id, id)); continue; From 5fbdb64bb913717a81ccbf919dea2789b227df74 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 14 Oct 2017 18:28:46 +0000 Subject: [PATCH 300/505] Add OPENMW_DECOMPRESS_TEXTURES environment variable to decompress textures in software if not supported by graphics hardware Disabled by default due to requiring new functionality that was just added to OSG 3.6 or OpenMW/OSG. --- components/resource/imagemanager.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/components/resource/imagemanager.cpp b/components/resource/imagemanager.cpp index 441fd8212..000a833cf 100644 --- a/components/resource/imagemanager.cpp +++ b/components/resource/imagemanager.cpp @@ -69,7 +69,6 @@ namespace Resource // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. && !osg::isGLExtensionSupported(0, "GL_S3_s3tc")) { - std::cerr << "Error loading " << filename << ": no S3TC texture compression support installed" << std::endl; return false; } break; @@ -123,12 +122,31 @@ namespace Resource return mWarningImage; } - osg::Image* image = result.getImage(); + osg::ref_ptr image = result.getImage(); + image->setFileName(normalized); if (!checkSupported(image, filename)) { - mCache->addEntryToObjectCache(normalized, mWarningImage); - return mWarningImage; + static bool uncompress = (getenv("OPENMW_DECOMPRESS_TEXTURES") != 0); + if (!uncompress) + { + std::cerr << "Error loading " << filename << ": no S3TC texture compression support installed" << std::endl; + mCache->addEntryToObjectCache(normalized, mWarningImage); + return mWarningImage; + } + else + { + // decompress texture in software if not supported by GPU + // requires update to getColor() to be released with OSG 3.6 + osg::ref_ptr newImage = new osg::Image; + newImage->setFileName(image->getFileName()); + newImage->allocateImage(image->s(), image->t(), image->r(), image->isImageTranslucent() ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE); + for (int s=0; ss(); ++s) + for (int t=0; tt(); ++t) + for (int r=0; rr(); ++r) + newImage->setColor(image->getColor(s,t,r), s,t,r); + image = newImage; + } } mCache->addEntryToObjectCache(normalized, image); From 11eae166458440c99908e8a38c4b512a3e361062 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 14 Oct 2017 15:09:12 -0400 Subject: [PATCH 301/505] Get rid of duplicate function, fix flag checking --- apps/opencs/model/world/columnimp.cpp | 10 +++++----- components/esm/loadland.cpp | 11 +---------- components/esm/loadland.hpp | 1 - 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index 18da81b53..49e4bebe6 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -108,7 +108,7 @@ namespace CSMWorld throw std::runtime_error("invalid land map LOD data"); Land copy = record.get(); - copy.setDataLoaded(Land::DATA_WNAM); + copy.add(Land::DATA_WNAM); for (int i = 0; i < values.size(); ++i) { @@ -155,7 +155,7 @@ namespace CSMWorld throw std::runtime_error("invalid land normals data"); Land copy = record.get(); - copy.setDataLoaded(Land::DATA_VNML); + copy.add(Land::DATA_VNML); for (int i = 0; i < values.size(); ++i) { @@ -202,7 +202,7 @@ namespace CSMWorld throw std::runtime_error("invalid land heights data"); Land copy = record.get(); - copy.setDataLoaded(Land::DATA_VHGT); + copy.add(Land::DATA_VHGT); for (int i = 0; i < values.size(); ++i) { @@ -249,7 +249,7 @@ namespace CSMWorld throw std::runtime_error("invalid land colours data"); Land copy = record.get(); - copy.setDataLoaded(Land::DATA_VCLR); + copy.add(Land::DATA_VCLR); for (int i = 0; i < values.size(); ++i) { @@ -296,7 +296,7 @@ namespace CSMWorld throw std::runtime_error("invalid land textures data"); Land copy = record.get(); - copy.setDataLoaded(Land::DATA_VTEX); + copy.add(Land::DATA_VTEX); for (int i = 0; i < values.size(); ++i) { diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index f3f72e88a..a91dfe3d3 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -315,16 +315,7 @@ namespace ESM bool Land::isDataLoaded(int flags) const { - return mLandData && (mLandData->mDataLoaded & flags) == (flags & mDataTypes); - } - - void Land::setDataLoaded(int flags) - { - if (!mLandData) - mLandData = new LandData; - - mDataTypes |= flags; - mLandData->mDataLoaded |= flags; + return mLandData && (mLandData->mDataLoaded & flags) == flags; } Land::Land (const Land& land) diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 7be954b3e..2163c30fc 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -132,7 +132,6 @@ struct Land void unloadData() const; /// Check if given data type is loaded - /// @note We only check data types that *can* be loaded (present in mDataTypes) bool isDataLoaded(int flags) const; /// Sets the flags and creates a LandData if needed From b95c9ba483c54362bc94d935704978c5b6f88ed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Wed, 4 Oct 2017 16:41:55 +0200 Subject: [PATCH 302/505] rain independent from camera plus wrap-around --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwrender/sky.cpp | 55 +++++++++++++++++++++-- apps/openmw/mwrender/sky.hpp | 5 ++- 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3826fd5f6..37abb1ec3 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -255,7 +255,7 @@ namespace MWRender mRootNode->getOrCreateStateSet()->addUniform(mUniformRainIntensity); - mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager())); + mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager(), this)); source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 178c753c6..0603c18a1 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -46,6 +47,8 @@ #include "vismask.hpp" #include "renderbin.hpp" +#define PARTICLE_WIDTH 600.0 + namespace { @@ -1091,8 +1094,9 @@ private: } }; -SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) +SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager, MWRender::RenderingManager *renderingManager) : mSceneManager(sceneManager) + , mRendering(renderingManager) , mAtmosphereNightRoll(0.f) , mCreated(false) , mIsStorm(false) @@ -1337,6 +1341,43 @@ protected: osg::Uniform* mRainIntensityUniform; }; +class WeatherParticleDrawCallback : public osg::Drawable::DrawCallback +{ +public: + WeatherParticleDrawCallback(MWRender::RenderingManager *renderingManager) : osg::Drawable::DrawCallback() + { + mRendering = renderingManager; + } + + virtual void drawImplementation(osg::RenderInfo& renderInfo, const osg::Drawable *drawable) const + { + osg::Vec3 cameraPos = mRendering->getCameraPosition(); + osg::Vec3 cameraOffset = osg::Vec3( + PARTICLE_WIDTH - fmod(cameraPos.x(), PARTICLE_WIDTH / 2), + PARTICLE_WIDTH - fmod(cameraPos.y(), PARTICLE_WIDTH / 2), + 0); + + osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) drawable; + + for (int xOff = 0; xOff < 3; xOff++) + for (int yOff = 0; yOff < 3; yOff++) + { + osg::Vec3 offset = cameraOffset + osg::Vec3(-1 * xOff * PARTICLE_WIDTH, -1 * yOff * PARTICLE_WIDTH,0); + + for(int i = 0; i < ps->numParticles(); i++) + ps->getParticle(i)->setPosition(ps->getParticle(i)->getPosition() + offset); + + ps->drawImplementation(renderInfo); + + for(int i = 0; i < ps->numParticles(); i++) + ps->getParticle(i)->setPosition(ps->getParticle(i)->getPosition() - offset); + } + } + +protected: + MWRender::RenderingManager *mRendering; +}; + void SkyManager::createRain() { if (mRainNode) @@ -1345,6 +1386,8 @@ void SkyManager::createRain() mRainNode = new osg::Group; mRainParticleSystem = new osgParticle::ParticleSystem; + mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(mRendering)); + mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0)); mRainParticleSystem->setAlignVectorY(osg::Vec3f(0,0,1)); @@ -1370,8 +1413,8 @@ void SkyManager::createRain() emitter->setParticleSystem(mRainParticleSystem); osg::ref_ptr placer (new osgParticle::BoxPlacer); - placer->setXRange(-300, 300); // Rain_Diameter - placer->setYRange(-300, 300); + placer->setXRange(-PARTICLE_WIDTH / 2, PARTICLE_WIDTH / 2); // Rain_Diameter + placer->setYRange(-PARTICLE_WIDTH / 2, PARTICLE_WIDTH / 2); placer->setZRange(300, 300); emitter->setPlacer(placer); @@ -1559,6 +1602,12 @@ void SkyManager::setWeather(const WeatherResult& weather) SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; mParticleEffect->accept(disableFreezeOnCullVisitor); + + osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) + (mParticleEffect->asGroup()->getChild(1)->asGroup()->getChild(0) + ->asGroup()->getChild(2)); + + ps->setDrawCallback(new WeatherParticleDrawCallback(mRendering)); } } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 59a8ddc4e..37c999563 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -9,6 +9,8 @@ #include #include +#include + namespace osg { class Group; @@ -108,7 +110,7 @@ namespace MWRender class SkyManager { public: - SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager); + SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager, MWRender::RenderingManager *renderingManager); ~SkyManager(); void update(float duration); @@ -170,6 +172,7 @@ namespace MWRender void updateRainParameters(); Resource::SceneManager* mSceneManager; + MWRender::RenderingManager *mRendering; osg::ref_ptr mRootNode; osg::ref_ptr mEarlyRenderBinRoot; From 33a1459b11b3efca1ed566f8d58f3f3c16871648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Wed, 4 Oct 2017 22:29:59 +0200 Subject: [PATCH 303/505] search for particle system by class name --- apps/openmw/mwrender/sky.cpp | 49 ++++++++++++++++++++++---------- apps/openmw/mwrender/sky.hpp | 2 +- components/nifosg/particle.cpp | 5 ++++ components/nifosg/particle.hpp | 1 + components/sceneutil/visitor.cpp | 8 ++++++ components/sceneutil/visitor.hpp | 17 ++++++++++- 6 files changed, 65 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0603c18a1..cce2e1b1d 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -47,7 +47,7 @@ #include "vismask.hpp" #include "renderbin.hpp" -#define PARTICLE_WIDTH 600.0 +#define RAIN_WIDTH 600.0 namespace { @@ -1344,17 +1344,19 @@ protected: class WeatherParticleDrawCallback : public osg::Drawable::DrawCallback { public: - WeatherParticleDrawCallback(MWRender::RenderingManager *renderingManager) : osg::Drawable::DrawCallback() + WeatherParticleDrawCallback(MWRender::RenderingManager *renderingManager, float rangeX, float rangeY) : osg::Drawable::DrawCallback() { mRendering = renderingManager; + mRangeX = rangeX; + mRangeY = rangeY; } virtual void drawImplementation(osg::RenderInfo& renderInfo, const osg::Drawable *drawable) const { osg::Vec3 cameraPos = mRendering->getCameraPosition(); osg::Vec3 cameraOffset = osg::Vec3( - PARTICLE_WIDTH - fmod(cameraPos.x(), PARTICLE_WIDTH / 2), - PARTICLE_WIDTH - fmod(cameraPos.y(), PARTICLE_WIDTH / 2), + mRangeX - fmod(cameraPos.x(), mRangeX / 2), + mRangeY - fmod(cameraPos.y(), mRangeY / 2), 0); osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) drawable; @@ -1362,7 +1364,7 @@ public: for (int xOff = 0; xOff < 3; xOff++) for (int yOff = 0; yOff < 3; yOff++) { - osg::Vec3 offset = cameraOffset + osg::Vec3(-1 * xOff * PARTICLE_WIDTH, -1 * yOff * PARTICLE_WIDTH,0); + osg::Vec3 offset = cameraOffset + osg::Vec3(-1 * xOff * mRangeX, -1 * yOff * mRangeY,0); for(int i = 0; i < ps->numParticles(); i++) ps->getParticle(i)->setPosition(ps->getParticle(i)->getPosition() + offset); @@ -1376,6 +1378,7 @@ public: protected: MWRender::RenderingManager *mRendering; + float mRangeX, mRangeY; }; void SkyManager::createRain() @@ -1386,7 +1389,7 @@ void SkyManager::createRain() mRainNode = new osg::Group; mRainParticleSystem = new osgParticle::ParticleSystem; - mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(mRendering)); + mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(mRendering,RAIN_WIDTH,RAIN_WIDTH)); mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0)); @@ -1413,8 +1416,8 @@ void SkyManager::createRain() emitter->setParticleSystem(mRainParticleSystem); osg::ref_ptr placer (new osgParticle::BoxPlacer); - placer->setXRange(-PARTICLE_WIDTH / 2, PARTICLE_WIDTH / 2); // Rain_Diameter - placer->setYRange(-PARTICLE_WIDTH / 2, PARTICLE_WIDTH / 2); + placer->setXRange(-RAIN_WIDTH / 2, RAIN_WIDTH / 2); // Rain_Diameter + placer->setYRange(-RAIN_WIDTH / 2, RAIN_WIDTH / 2); placer->setZRange(300, 300); emitter->setPlacer(placer); @@ -1493,8 +1496,6 @@ void SkyManager::update(float duration) osg::Quat quat; quat.makeRotate(osg::Vec3f(0,1,0), mStormDirection); - if (mParticleNode) - mParticleNode->setAttitude(quat); mCloudNode->setAttitude(quat); } else @@ -1586,7 +1587,7 @@ void SkyManager::setWeather(const WeatherResult& weather) { if (!mParticleNode) { - mParticleNode = new osg::PositionAttitudeTransform; + mParticleNode = new osg::Group; mParticleNode->addCullCallback(mUnderwaterSwitch); mParticleNode->setNodeMask(Mask_WeatherParticles); mRootNode->addChild(mParticleNode); @@ -1603,11 +1604,29 @@ void SkyManager::setWeather(const WeatherResult& weather) SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; mParticleEffect->accept(disableFreezeOnCullVisitor); - osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) - (mParticleEffect->asGroup()->getChild(1)->asGroup()->getChild(0) - ->asGroup()->getChild(2)); + SceneUtil::FindByClassVisitor findEmitterVisitor(std::string("Emitter")); + mParticleEffect->accept(findEmitterVisitor); - ps->setDrawCallback(new WeatherParticleDrawCallback(mRendering)); + float rangeX = RAIN_WIDTH; + float rangeY = RAIN_WIDTH; + + if (findEmitterVisitor.mFoundNode) + { + osgParticle::Placer *placer = ((NifOsg::Emitter *) findEmitterVisitor.mFoundNode)->getPlacer(); + + if (placer && strcmp(placer->className(),"BoxPlacer") == 0) + { + rangeX = ((osgParticle::BoxPlacer *) placer)->getXRange().maximum; + rangeY = ((osgParticle::BoxPlacer *) placer)->getYRange().maximum; + } + } + + + SceneUtil::FindByClassVisitor findPSVisitor(std::string("ParticleSystem")); + mParticleEffect->accept(findPSVisitor); + + if (findPSVisitor.mFoundNode) + ((osgParticle::ParticleSystem *) findPSVisitor.mFoundNode)->setDrawCallback(new WeatherParticleDrawCallback(mRendering,rangeX,rangeY)); } } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 37c999563..fdcd27e5a 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -177,7 +177,7 @@ namespace MWRender osg::ref_ptr mRootNode; osg::ref_ptr mEarlyRenderBinRoot; - osg::ref_ptr mParticleNode; + osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; std::vector > mParticleFaders; osg::ref_ptr mUnderwaterSwitch; diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 62360b9d6..547b71034 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -250,6 +250,11 @@ void Emitter::setPlacer(osgParticle::Placer *placer) mPlacer = placer; } +osgParticle::Placer *Emitter::getPlacer() +{ + return mPlacer; +} + void Emitter::setCounter(osgParticle::Counter *counter) { mCounter = counter; diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 7a2377f9d..df93d5ced 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -225,6 +225,7 @@ namespace NifOsg void setShooter(osgParticle::Shooter* shooter); void setPlacer(osgParticle::Placer* placer); + osgParticle::Placer *getPlacer(); void setCounter(osgParticle::Counter* counter); private: diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index 74b9be63d..202e6373e 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -19,6 +19,14 @@ namespace SceneUtil return false; } + void FindByClassVisitor::apply(osg::Node &node) + { + if (Misc::StringUtils::ciEqual(node.className(), mNameToFind)) + mFoundNode = &node; + else + traverse(node); + } + void FindByNameVisitor::apply(osg::Group &group) { if (!checkGroup(group)) diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index 209f2d9bd..973f44646 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -20,7 +20,6 @@ namespace SceneUtil } virtual void apply(osg::Group& group); - virtual void apply(osg::MatrixTransform& node); virtual void apply(osg::Geometry& node); @@ -30,6 +29,22 @@ namespace SceneUtil osg::Group* mFoundNode; }; + class FindByClassVisitor : public osg::NodeVisitor + { + public: + FindByClassVisitor(const std::string& nameToFind) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mNameToFind(nameToFind) + , mFoundNode(NULL) + { + } + + virtual void apply(osg::Node &node); + + std::string mNameToFind; + osg::Node* mFoundNode; + }; + // Disable freezeOnCull for all visited particlesystems class DisableFreezeOnCullVisitor : public osg::NodeVisitor { From 8114126a62ecd4904f3c92fd0d5667d874700a2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 5 Oct 2017 12:58:56 +0200 Subject: [PATCH 304/505] make use of renderinfo --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwrender/sky.cpp | 63 ++++++++++++++--------- apps/openmw/mwrender/sky.hpp | 7 +-- 3 files changed, 41 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 37abb1ec3..3826fd5f6 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -255,7 +255,7 @@ namespace MWRender mRootNode->getOrCreateStateSet()->addUniform(mUniformRainIntensity); - mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager(), this)); + mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager())); source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index cce2e1b1d..81494d8e2 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1094,9 +1094,8 @@ private: } }; -SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager, MWRender::RenderingManager *renderingManager) +SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) : mSceneManager(sceneManager) - , mRendering(renderingManager) , mAtmosphereNightRoll(0.f) , mCreated(false) , mIsStorm(false) @@ -1344,40 +1343,50 @@ protected: class WeatherParticleDrawCallback : public osg::Drawable::DrawCallback { public: - WeatherParticleDrawCallback(MWRender::RenderingManager *renderingManager, float rangeX, float rangeY) : osg::Drawable::DrawCallback() + WeatherParticleDrawCallback(float rangeX, float rangeY) : osg::Drawable::DrawCallback() { - mRendering = renderingManager; mRangeX = rangeX; mRangeY = rangeY; } virtual void drawImplementation(osg::RenderInfo& renderInfo, const osg::Drawable *drawable) const { - osg::Vec3 cameraPos = mRendering->getCameraPosition(); + osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) drawable; + osg::Vec3 cameraPos = renderInfo.getCurrentCamera()->getInverseViewMatrix().getTrans(); + osg::Vec3 cameraOffset = osg::Vec3( - mRangeX - fmod(cameraPos.x(), mRangeX / 2), - mRangeY - fmod(cameraPos.y(), mRangeY / 2), - 0); + fmod(cameraPos.x(), mRangeX), + fmod(cameraPos.y(), mRangeY), + 0.0); - osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) drawable; + std::vector positionBackups; - for (int xOff = 0; xOff < 3; xOff++) - for (int yOff = 0; yOff < 3; yOff++) - { - osg::Vec3 offset = cameraOffset + osg::Vec3(-1 * xOff * mRangeX, -1 * yOff * mRangeY,0); + for (int i = 0; i < ps->numParticles(); i++) + { + osgParticle::Particle *particle = ps->getParticle(i); - for(int i = 0; i < ps->numParticles(); i++) - ps->getParticle(i)->setPosition(ps->getParticle(i)->getPosition() + offset); + positionBackups.push_back(particle->getPosition()); - ps->drawImplementation(renderInfo); + particle->setPosition(particle->getPosition() - cameraOffset); - for(int i = 0; i < ps->numParticles(); i++) - ps->getParticle(i)->setPosition(ps->getParticle(i)->getPosition() - offset); - } + if (particle->getPosition().x() > mRangeX / 2.0) // wrap-around effect + particle->setPosition(particle->getPosition() - osg::Vec3(mRangeX,0,0)); + else if (particle->getPosition().x() < -mRangeX / 2.0) + particle->setPosition(particle->getPosition() + osg::Vec3(mRangeX,0,0)); + + if (particle->getPosition().y() > mRangeY / 2.0) + particle->setPosition(particle->getPosition() - osg::Vec3(0,mRangeY,0)); + else if (particle->getPosition().y() < -mRangeY / 2.0) + particle->setPosition(particle->getPosition() + osg::Vec3(0,mRangeY,0)); + } + + ps->drawImplementation(renderInfo); + + for (int i = 0; i < ps->numParticles(); i++) // restore positions + ps->getParticle(i)->setPosition(positionBackups[i]); } protected: - MWRender::RenderingManager *mRendering; float mRangeX, mRangeY; }; @@ -1389,11 +1398,12 @@ void SkyManager::createRain() mRainNode = new osg::Group; mRainParticleSystem = new osgParticle::ParticleSystem; - mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(mRendering,RAIN_WIDTH,RAIN_WIDTH)); + mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(RAIN_WIDTH,RAIN_WIDTH)); mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0)); mRainParticleSystem->setAlignVectorY(osg::Vec3f(0,0,1)); + mRainParticleSystem->setCullingActive(false); osg::ref_ptr stateset (mRainParticleSystem->getOrCreateStateSet()); @@ -1422,7 +1432,8 @@ void SkyManager::createRain() emitter->setPlacer(placer); osg::ref_ptr counter (new osgParticle::ConstantRateCounter); - counter->setNumberOfParticlesPerSecondToCreate(600.0); +// counter->setNumberOfParticlesPerSecondToCreate(600.0); + counter->setNumberOfParticlesPerSecondToCreate(2000); emitter->setCounter(counter); osg::ref_ptr shooter (new RainShooter); @@ -1496,6 +1507,9 @@ void SkyManager::update(float duration) osg::Quat quat; quat.makeRotate(osg::Vec3f(0,1,0), mStormDirection); + if (mParticleNode) + mParticleNode->setAttitude(quat); + mCloudNode->setAttitude(quat); } else @@ -1587,7 +1601,7 @@ void SkyManager::setWeather(const WeatherResult& weather) { if (!mParticleNode) { - mParticleNode = new osg::Group; + mParticleNode = new osg::PositionAttitudeTransform; mParticleNode->addCullCallback(mUnderwaterSwitch); mParticleNode->setNodeMask(Mask_WeatherParticles); mRootNode->addChild(mParticleNode); @@ -1621,12 +1635,11 @@ void SkyManager::setWeather(const WeatherResult& weather) } } - SceneUtil::FindByClassVisitor findPSVisitor(std::string("ParticleSystem")); mParticleEffect->accept(findPSVisitor); if (findPSVisitor.mFoundNode) - ((osgParticle::ParticleSystem *) findPSVisitor.mFoundNode)->setDrawCallback(new WeatherParticleDrawCallback(mRendering,rangeX,rangeY)); + ((osgParticle::ParticleSystem *) findPSVisitor.mFoundNode)->setDrawCallback(new WeatherParticleDrawCallback(rangeX,rangeY)); } } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index fdcd27e5a..59a8ddc4e 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -9,8 +9,6 @@ #include #include -#include - namespace osg { class Group; @@ -110,7 +108,7 @@ namespace MWRender class SkyManager { public: - SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager, MWRender::RenderingManager *renderingManager); + SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager); ~SkyManager(); void update(float duration); @@ -172,12 +170,11 @@ namespace MWRender void updateRainParameters(); Resource::SceneManager* mSceneManager; - MWRender::RenderingManager *mRendering; osg::ref_ptr mRootNode; osg::ref_ptr mEarlyRenderBinRoot; - osg::ref_ptr mParticleNode; + osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; std::vector > mParticleFaders; osg::ref_ptr mUnderwaterSwitch; From 38bfa64100414a4ab76c71805a569185c6cd8485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sun, 8 Oct 2017 20:56:36 +0200 Subject: [PATCH 305/505] transform weather particles to world space --- apps/openmw/mwrender/sky.cpp | 50 +++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 81494d8e2..de1fb780c 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1361,24 +1361,38 @@ public: std::vector positionBackups; - for (int i = 0; i < ps->numParticles(); i++) - { - osgParticle::Particle *particle = ps->getParticle(i); + osg::Matrix toWorld, toLocal; - positionBackups.push_back(particle->getPosition()); + toWorld.makeIdentity(); + toLocal.makeIdentity(); - particle->setPosition(particle->getPosition() - cameraOffset); + std::vector worldMatrices = drawable->getWorldMatrices(); - if (particle->getPosition().x() > mRangeX / 2.0) // wrap-around effect - particle->setPosition(particle->getPosition() - osg::Vec3(mRangeX,0,0)); - else if (particle->getPosition().x() < -mRangeX / 2.0) - particle->setPosition(particle->getPosition() + osg::Vec3(mRangeX,0,0)); + if (!worldMatrices.empty()) + { + toWorld = worldMatrices[0]; + toLocal.invert(toWorld); + } - if (particle->getPosition().y() > mRangeY / 2.0) - particle->setPosition(particle->getPosition() - osg::Vec3(0,mRangeY,0)); - else if (particle->getPosition().y() < -mRangeY / 2.0) - particle->setPosition(particle->getPosition() + osg::Vec3(0,mRangeY,0)); - } + for (int i = 0; i < ps->numParticles(); i++) + { + osgParticle::Particle *particle = ps->getParticle(i); + positionBackups.push_back(particle->getPosition()); + particle->setPosition(toWorld.preMult(particle->getPosition())); + particle->setPosition(particle->getPosition() - cameraOffset); + + if (particle->getPosition().x() > mRangeX / 2.0) // wrap-around effect + particle->setPosition(particle->getPosition() - osg::Vec3(mRangeX,0,0)); + else if (particle->getPosition().x() < -mRangeX / 2.0) + particle->setPosition(particle->getPosition() + osg::Vec3(mRangeX,0,0)); + + if (particle->getPosition().y() > mRangeY / 2.0) + particle->setPosition(particle->getPosition() - osg::Vec3(0,mRangeY,0)); + else if (particle->getPosition().y() < -mRangeY / 2.0) + particle->setPosition(particle->getPosition() + osg::Vec3(0,mRangeY,0)); + + particle->setPosition(toLocal.preMult(particle->getPosition())); + } ps->drawImplementation(renderInfo); @@ -1388,6 +1402,7 @@ public: protected: float mRangeX, mRangeY; + }; void SkyManager::createRain() @@ -1432,8 +1447,7 @@ void SkyManager::createRain() emitter->setPlacer(placer); osg::ref_ptr counter (new osgParticle::ConstantRateCounter); -// counter->setNumberOfParticlesPerSecondToCreate(600.0); - counter->setNumberOfParticlesPerSecondToCreate(2000); + counter->setNumberOfParticlesPerSecondToCreate(600.0); emitter->setCounter(counter); osg::ref_ptr shooter (new RainShooter); @@ -1507,8 +1521,8 @@ void SkyManager::update(float duration) osg::Quat quat; quat.makeRotate(osg::Vec3f(0,1,0), mStormDirection); - if (mParticleNode) - mParticleNode->setAttitude(quat); + if (mParticleNode) + mParticleNode->setAttitude(quat); mCloudNode->setAttitude(quat); } From 380a5799dd0afdefe92af185ca63209685068d7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 12 Oct 2017 12:56:03 +0200 Subject: [PATCH 306/505] use bbox as wrap range & apply to all particle systems --- apps/openmw/mwrender/sky.cpp | 55 +++++++++++++------------------- components/sceneutil/visitor.cpp | 6 ++-- components/sceneutil/visitor.hpp | 3 +- 3 files changed, 27 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index de1fb780c..fb3e477bb 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -48,6 +48,7 @@ #include "renderbin.hpp" #define RAIN_WIDTH 600.0 +#define RAIN_HEIGHT 600.0 namespace { @@ -1343,10 +1344,9 @@ protected: class WeatherParticleDrawCallback : public osg::Drawable::DrawCallback { public: - WeatherParticleDrawCallback(float rangeX, float rangeY) : osg::Drawable::DrawCallback() + WeatherParticleDrawCallback(osg::Vec3 wrapRange) : osg::Drawable::DrawCallback() { - mRangeX = rangeX; - mRangeY = rangeY; + mWrapRange = wrapRange; } virtual void drawImplementation(osg::RenderInfo& renderInfo, const osg::Drawable *drawable) const @@ -1355,8 +1355,8 @@ public: osg::Vec3 cameraPos = renderInfo.getCurrentCamera()->getInverseViewMatrix().getTrans(); osg::Vec3 cameraOffset = osg::Vec3( - fmod(cameraPos.x(), mRangeX), - fmod(cameraPos.y(), mRangeY), + fmod(cameraPos.x(), mWrapRange.x()), + fmod(cameraPos.y(), mWrapRange.y()), 0.0); std::vector positionBackups; @@ -1381,15 +1381,15 @@ public: particle->setPosition(toWorld.preMult(particle->getPosition())); particle->setPosition(particle->getPosition() - cameraOffset); - if (particle->getPosition().x() > mRangeX / 2.0) // wrap-around effect - particle->setPosition(particle->getPosition() - osg::Vec3(mRangeX,0,0)); - else if (particle->getPosition().x() < -mRangeX / 2.0) - particle->setPosition(particle->getPosition() + osg::Vec3(mRangeX,0,0)); + if (particle->getPosition().x() > mWrapRange.x() / 2.0) // wrap-around effect + particle->setPosition(particle->getPosition() - osg::Vec3(mWrapRange.x(),0,0)); + else if (particle->getPosition().x() < -mWrapRange.x() / 2.0) + particle->setPosition(particle->getPosition() + osg::Vec3(mWrapRange.x(),0,0)); - if (particle->getPosition().y() > mRangeY / 2.0) - particle->setPosition(particle->getPosition() - osg::Vec3(0,mRangeY,0)); - else if (particle->getPosition().y() < -mRangeY / 2.0) - particle->setPosition(particle->getPosition() + osg::Vec3(0,mRangeY,0)); + if (particle->getPosition().y() > mWrapRange.y() / 2.0) + particle->setPosition(particle->getPosition() - osg::Vec3(0,mWrapRange.y(),0)); + else if (particle->getPosition().y() < -mWrapRange.y() / 2.0) + particle->setPosition(particle->getPosition() + osg::Vec3(0,mWrapRange.y(),0)); particle->setPosition(toLocal.preMult(particle->getPosition())); } @@ -1401,8 +1401,7 @@ public: } protected: - float mRangeX, mRangeY; - + osg::Vec3 mWrapRange; }; void SkyManager::createRain() @@ -1413,7 +1412,7 @@ void SkyManager::createRain() mRainNode = new osg::Group; mRainParticleSystem = new osgParticle::ParticleSystem; - mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(RAIN_WIDTH,RAIN_WIDTH)); + mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(osg::Vec3(RAIN_WIDTH,RAIN_WIDTH,RAIN_HEIGHT))); mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0)); @@ -1635,25 +1634,17 @@ void SkyManager::setWeather(const WeatherResult& weather) SceneUtil::FindByClassVisitor findEmitterVisitor(std::string("Emitter")); mParticleEffect->accept(findEmitterVisitor); - float rangeX = RAIN_WIDTH; - float rangeY = RAIN_WIDTH; + for (unsigned int i = 0; i < findEmitterVisitor.mFoundNodes.size(); i++) + { + NifOsg::Emitter *emitter = (NifOsg::Emitter *) findEmitterVisitor.mFoundNodes[i]; + NifOsg::ParticleSystem *ps = (NifOsg::ParticleSystem *) emitter->getParticleSystem(); - if (findEmitterVisitor.mFoundNode) - { - osgParticle::Placer *placer = ((NifOsg::Emitter *) findEmitterVisitor.mFoundNode)->getPlacer(); + osg::BoundingBox box = ps->getBoundingBox(); - if (placer && strcmp(placer->className(),"BoxPlacer") == 0) - { - rangeX = ((osgParticle::BoxPlacer *) placer)->getXRange().maximum; - rangeY = ((osgParticle::BoxPlacer *) placer)->getYRange().maximum; - } - } + osg::Vec3 wrapRange = osg::Vec3(box.xMax() - box.xMin(),box.yMax() - box.yMin(),box.zMax() - box.zMin()); - SceneUtil::FindByClassVisitor findPSVisitor(std::string("ParticleSystem")); - mParticleEffect->accept(findPSVisitor); - - if (findPSVisitor.mFoundNode) - ((osgParticle::ParticleSystem *) findPSVisitor.mFoundNode)->setDrawCallback(new WeatherParticleDrawCallback(rangeX,rangeY)); + ps->setDrawCallback(new WeatherParticleDrawCallback(wrapRange)); + } } } diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index 202e6373e..2f6123e34 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -22,9 +22,9 @@ namespace SceneUtil void FindByClassVisitor::apply(osg::Node &node) { if (Misc::StringUtils::ciEqual(node.className(), mNameToFind)) - mFoundNode = &node; - else - traverse(node); + mFoundNodes.push_back(&node); + + traverse(node); } void FindByNameVisitor::apply(osg::Group &group) diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index 973f44646..265fd6d02 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -35,14 +35,13 @@ namespace SceneUtil FindByClassVisitor(const std::string& nameToFind) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) , mNameToFind(nameToFind) - , mFoundNode(NULL) { } virtual void apply(osg::Node &node); std::string mNameToFind; - osg::Node* mFoundNode; + std::vector mFoundNodes; }; // Disable freezeOnCull for all visited particlesystems From 65977b910e017bbe4007fc1c71d47201c3bb02f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 12 Oct 2017 15:28:54 +0200 Subject: [PATCH 307/505] wrap weather around in all directions --- apps/openmw/mwrender/sky.cpp | 92 +++++++++++++++++----------------- components/nifosg/particle.cpp | 5 -- components/nifosg/particle.hpp | 1 - 3 files changed, 47 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index fb3e477bb..eaa93ab88 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -39,7 +41,6 @@ #include #include #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -47,12 +48,8 @@ #include "vismask.hpp" #include "renderbin.hpp" -#define RAIN_WIDTH 600.0 -#define RAIN_HEIGHT 600.0 - namespace { - osg::ref_ptr createAlphaTrackingUnlitMaterial() { osg::ref_ptr mat = new osg::Material; @@ -1344,60 +1341,69 @@ protected: class WeatherParticleDrawCallback : public osg::Drawable::DrawCallback { public: - WeatherParticleDrawCallback(osg::Vec3 wrapRange) : osg::Drawable::DrawCallback() + WeatherParticleDrawCallback(osg::Vec3 &wrapRange) : osg::Drawable::DrawCallback() { mWrapRange = wrapRange; } virtual void drawImplementation(osg::RenderInfo& renderInfo, const osg::Drawable *drawable) const { + osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) drawable; + + osgParticle::ParticleSystem::ScopedReadLock *lock = new osgParticle::ParticleSystem::ScopedReadLock(*ps->getReadWriteMutex()); + osg::Vec3 cameraPos = renderInfo.getCurrentCamera()->getInverseViewMatrix().getTrans(); osg::Vec3 cameraOffset = osg::Vec3( fmod(cameraPos.x(), mWrapRange.x()), fmod(cameraPos.y(), mWrapRange.y()), - 0.0); + fmod(cameraPos.z(), mWrapRange.z())); std::vector positionBackups; osg::Matrix toWorld, toLocal; - toWorld.makeIdentity(); - toLocal.makeIdentity(); - std::vector worldMatrices = drawable->getWorldMatrices(); if (!worldMatrices.empty()) - { - toWorld = worldMatrices[0]; - toLocal.invert(toWorld); - } + { + toWorld = worldMatrices[0]; + toLocal.invert(toWorld); + } for (int i = 0; i < ps->numParticles(); i++) - { - osgParticle::Particle *particle = ps->getParticle(i); - positionBackups.push_back(particle->getPosition()); - particle->setPosition(toWorld.preMult(particle->getPosition())); - particle->setPosition(particle->getPosition() - cameraOffset); - - if (particle->getPosition().x() > mWrapRange.x() / 2.0) // wrap-around effect - particle->setPosition(particle->getPosition() - osg::Vec3(mWrapRange.x(),0,0)); - else if (particle->getPosition().x() < -mWrapRange.x() / 2.0) - particle->setPosition(particle->getPosition() + osg::Vec3(mWrapRange.x(),0,0)); - - if (particle->getPosition().y() > mWrapRange.y() / 2.0) - particle->setPosition(particle->getPosition() - osg::Vec3(0,mWrapRange.y(),0)); - else if (particle->getPosition().y() < -mWrapRange.y() / 2.0) - particle->setPosition(particle->getPosition() + osg::Vec3(0,mWrapRange.y(),0)); - - particle->setPosition(toLocal.preMult(particle->getPosition())); + { + osgParticle::Particle *particle = ps->getParticle(i); + positionBackups.push_back(particle->getPosition()); + particle->setPosition(toWorld.preMult(particle->getPosition())); + particle->setPosition(particle->getPosition() - cameraOffset); + + for (int j = 0; j < 3; j++) // wrap-around effect in all 3 directions + { + osg::Vec3 newPosition = particle->getPosition(); + + if (particle->getPosition()[j] > mWrapRange[j] / 2.0) + newPosition[j] -= mWrapRange[j]; + else if (particle->getPosition()[j] < -mWrapRange[j] / 2.0) + newPosition[j] += mWrapRange[j]; + + particle->setPosition(newPosition); } + particle->setPosition(toLocal.preMult(particle->getPosition())); + } + + delete lock; // unlock the mutex as ps will try to lock it in the following command + ps->drawImplementation(renderInfo); + lock = new osgParticle::ParticleSystem::ScopedReadLock(*ps->getReadWriteMutex()); + for (int i = 0; i < ps->numParticles(); i++) // restore positions ps->getParticle(i)->setPosition(positionBackups[i]); + + delete lock; } protected: @@ -1412,7 +1418,8 @@ void SkyManager::createRain() mRainNode = new osg::Group; mRainParticleSystem = new osgParticle::ParticleSystem; - mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(osg::Vec3(RAIN_WIDTH,RAIN_WIDTH,RAIN_HEIGHT))); + osg::Vec3 rainRange = osg::Vec3(600,600,600); + mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(rainRange)); mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0)); @@ -1440,8 +1447,8 @@ void SkyManager::createRain() emitter->setParticleSystem(mRainParticleSystem); osg::ref_ptr placer (new osgParticle::BoxPlacer); - placer->setXRange(-RAIN_WIDTH / 2, RAIN_WIDTH / 2); // Rain_Diameter - placer->setYRange(-RAIN_WIDTH / 2, RAIN_WIDTH / 2); + placer->setXRange(-rainRange.x() / 2, rainRange.x() / 2); // Rain_Diameter + placer->setYRange(-rainRange.y() / 2, rainRange.y() / 2); placer->setZRange(300, 300); emitter->setPlacer(placer); @@ -1631,19 +1638,14 @@ void SkyManager::setWeather(const WeatherResult& weather) SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; mParticleEffect->accept(disableFreezeOnCullVisitor); - SceneUtil::FindByClassVisitor findEmitterVisitor(std::string("Emitter")); - mParticleEffect->accept(findEmitterVisitor); + SceneUtil::FindByClassVisitor findPSVisitor(std::string("ParticleSystem")); + mParticleEffect->accept(findPSVisitor); - for (unsigned int i = 0; i < findEmitterVisitor.mFoundNodes.size(); i++) + for (unsigned int i = 0; i < findPSVisitor.mFoundNodes.size(); i++) { - NifOsg::Emitter *emitter = (NifOsg::Emitter *) findEmitterVisitor.mFoundNodes[i]; - NifOsg::ParticleSystem *ps = (NifOsg::ParticleSystem *) emitter->getParticleSystem(); - - osg::BoundingBox box = ps->getBoundingBox(); - - osg::Vec3 wrapRange = osg::Vec3(box.xMax() - box.xMin(),box.yMax() - box.yMin(),box.zMax() - box.zMin()); - - ps->setDrawCallback(new WeatherParticleDrawCallback(wrapRange)); + osgParticle::ParticleSystem *ps = static_cast(findPSVisitor.mFoundNodes[i]); + osg::Vec3 weatherRange = osg::Vec3(1024,1024,800); + ps->setDrawCallback(new WeatherParticleDrawCallback(weatherRange)); } } } diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 547b71034..62360b9d6 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -250,11 +250,6 @@ void Emitter::setPlacer(osgParticle::Placer *placer) mPlacer = placer; } -osgParticle::Placer *Emitter::getPlacer() -{ - return mPlacer; -} - void Emitter::setCounter(osgParticle::Counter *counter) { mCounter = counter; diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index df93d5ced..7a2377f9d 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -225,7 +225,6 @@ namespace NifOsg void setShooter(osgParticle::Shooter* shooter); void setPlacer(osgParticle::Placer* placer); - osgParticle::Placer *getPlacer(); void setCounter(osgParticle::Counter* counter); private: From af6eeddbe551ac8ba7eb58f2be5085900908bc1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sat, 14 Oct 2017 18:45:29 +0200 Subject: [PATCH 308/505] use operator instead of drawcallback --- apps/openmw/mwrender/renderingmanager.cpp | 1 + apps/openmw/mwrender/sky.cpp | 122 +++++++++++++--------- apps/openmw/mwrender/sky.hpp | 9 ++ 3 files changed, 81 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3826fd5f6..aa7b35b44 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -256,6 +256,7 @@ namespace MWRender mRootNode->getOrCreateStateSet()->addUniform(mUniformRainIntensity); mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager())); + mSky->setCamera(mViewer->getCamera()); source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index eaa93ab88..1338a127c 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -18,8 +18,6 @@ #include #include -#include - #include #include #include @@ -27,6 +25,9 @@ #include #include +#include +#include + #include #include @@ -1094,6 +1095,7 @@ private: SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) : mSceneManager(sceneManager) + , mCamera(NULL) , mAtmosphereNightRoll(0.f) , mCreated(false) , mIsStorm(false) @@ -1338,76 +1340,85 @@ protected: osg::Uniform* mRainIntensityUniform; }; -class WeatherParticleDrawCallback : public osg::Drawable::DrawCallback +void SkyManager::setCamera(osg::Camera *camera) +{ + mCamera = camera; +} + +class WrapAroundOperator : public osgParticle::Operator { public: - WeatherParticleDrawCallback(osg::Vec3 &wrapRange) : osg::Drawable::DrawCallback() + WrapAroundOperator(osg::Camera *camera, const osg::Vec3 &wrapRange): osgParticle::Operator() { + mCamera = camera; mWrapRange = wrapRange; + mHalfWrapRange = mWrapRange / 2.0; + mPreviousCameraPosition = getCameraPosition(); } - virtual void drawImplementation(osg::RenderInfo& renderInfo, const osg::Drawable *drawable) const + virtual osg::Object *cloneType() const override { + return NULL; + } - osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) drawable; - - osgParticle::ParticleSystem::ScopedReadLock *lock = new osgParticle::ParticleSystem::ScopedReadLock(*ps->getReadWriteMutex()); - - osg::Vec3 cameraPos = renderInfo.getCurrentCamera()->getInverseViewMatrix().getTrans(); + virtual osg::Object *clone(const osg::CopyOp &op) const override + { + return NULL; + } - osg::Vec3 cameraOffset = osg::Vec3( - fmod(cameraPos.x(), mWrapRange.x()), - fmod(cameraPos.y(), mWrapRange.y()), - fmod(cameraPos.z(), mWrapRange.z())); + virtual void operate(osgParticle::Particle *P, double dt) override + { + } - std::vector positionBackups; + virtual void operateParticles(osgParticle::ParticleSystem *ps, double dt) override + { + osg::Vec3 position = getCameraPosition(); + osg::Vec3 positionDifference = position - mPreviousCameraPosition; osg::Matrix toWorld, toLocal; - std::vector worldMatrices = drawable->getWorldMatrices(); - + std::vector worldMatrices = ps->getWorldMatrices(); + if (!worldMatrices.empty()) { toWorld = worldMatrices[0]; toLocal.invert(toWorld); } - for (int i = 0; i < ps->numParticles(); i++) + for (int i = 0; i < ps->numParticles(); ++i) { - osgParticle::Particle *particle = ps->getParticle(i); - positionBackups.push_back(particle->getPosition()); - particle->setPosition(toWorld.preMult(particle->getPosition())); - particle->setPosition(particle->getPosition() - cameraOffset); + osgParticle::Particle *p = ps->getParticle(i); + p->setPosition(toWorld.preMult(p->getPosition())); + p->setPosition(p->getPosition() - positionDifference); - for (int j = 0; j < 3; j++) // wrap-around effect in all 3 directions - { - osg::Vec3 newPosition = particle->getPosition(); + for (int j = 0; j < 3; ++j) // wrap-around in all 3 dimensions + { + osg::Vec3 pos = p->getPosition(); - if (particle->getPosition()[j] > mWrapRange[j] / 2.0) - newPosition[j] -= mWrapRange[j]; - else if (particle->getPosition()[j] < -mWrapRange[j] / 2.0) - newPosition[j] += mWrapRange[j]; + if (pos[j] < -mHalfWrapRange[j]) + pos[j] = mHalfWrapRange[j] + fmod(pos[j] - mHalfWrapRange[j],mWrapRange[j]); + else if (pos[j] > mHalfWrapRange[j]) + pos[j] = fmod(pos[j] + mHalfWrapRange[j],mWrapRange[j]) - mHalfWrapRange[j]; - particle->setPosition(newPosition); - } + p->setPosition(pos); + } - particle->setPosition(toLocal.preMult(particle->getPosition())); + p->setPosition(toLocal.preMult(p->getPosition())); } - delete lock; // unlock the mutex as ps will try to lock it in the following command - - ps->drawImplementation(renderInfo); - - lock = new osgParticle::ParticleSystem::ScopedReadLock(*ps->getReadWriteMutex()); - - for (int i = 0; i < ps->numParticles(); i++) // restore positions - ps->getParticle(i)->setPosition(positionBackups[i]); - - delete lock; + mPreviousCameraPosition = position; } protected: + osg::Camera *mCamera; + osg::Vec3 mPreviousCameraPosition; osg::Vec3 mWrapRange; + osg::Vec3 mHalfWrapRange; + + osg::Vec3 getCameraPosition() + { + return mCamera->getInverseViewMatrix().getTrans(); + } }; void SkyManager::createRain() @@ -1419,12 +1430,10 @@ void SkyManager::createRain() mRainParticleSystem = new osgParticle::ParticleSystem; osg::Vec3 rainRange = osg::Vec3(600,600,600); - mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(rainRange)); mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0)); mRainParticleSystem->setAlignVectorY(osg::Vec3f(0,0,1)); - mRainParticleSystem->setCullingActive(false); osg::ref_ptr stateset (mRainParticleSystem->getOrCreateStateSet()); @@ -1463,6 +1472,11 @@ void SkyManager::createRain() osg::ref_ptr updater (new osgParticle::ParticleSystemUpdater); updater->addParticleSystem(mRainParticleSystem); + osg::ref_ptr program (new osgParticle::ModularProgram); + program->addOperator(new WrapAroundOperator(mCamera,rainRange)); + program->setParticleSystem(mRainParticleSystem); + mRainNode->addChild(program); + mRainNode->addChild(emitter); mRainNode->addChild(mRainParticleSystem); mRainNode->addChild(updater); @@ -1638,14 +1652,20 @@ void SkyManager::setWeather(const WeatherResult& weather) SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; mParticleEffect->accept(disableFreezeOnCullVisitor); - SceneUtil::FindByClassVisitor findPSVisitor(std::string("ParticleSystem")); - mParticleEffect->accept(findPSVisitor); - - for (unsigned int i = 0; i < findPSVisitor.mFoundNodes.size(); i++) + if (!weather.mIsStorm) { - osgParticle::ParticleSystem *ps = static_cast(findPSVisitor.mFoundNodes[i]); - osg::Vec3 weatherRange = osg::Vec3(1024,1024,800); - ps->setDrawCallback(new WeatherParticleDrawCallback(weatherRange)); + SceneUtil::FindByClassVisitor findPSVisitor(std::string("ParticleSystem")); + mParticleEffect->accept(findPSVisitor); + + for (unsigned int i = 0; i < findPSVisitor.mFoundNodes.size(); ++i) + { + osgParticle::ParticleSystem *ps = static_cast(findPSVisitor.mFoundNodes[i]); + + osg::ref_ptr program (new osgParticle::ModularProgram); + program->addOperator(new WrapAroundOperator(mCamera,osg::Vec3(1024,1024,800))); + program->setParticleSystem(ps); + mParticleNode->addChild(program); + } } } } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 59a8ddc4e..097405b24 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -9,6 +9,11 @@ #include #include +namespace osg +{ + class Camera; +} + namespace osg { class Group; @@ -161,6 +166,8 @@ namespace MWRender void listAssetsToPreload(std::vector& models, std::vector& textures); + void setCamera(osg::Camera *camera); + private: void create(); ///< no need to call this, automatically done on first enable() @@ -171,6 +178,8 @@ namespace MWRender Resource::SceneManager* mSceneManager; + osg::Camera* mCamera; + osg::ref_ptr mRootNode; osg::ref_ptr mEarlyRenderBinRoot; From 28ff677337f9e6231a6be62cc4ec79aca6d3dd73 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 15 Oct 2017 00:07:46 +0100 Subject: [PATCH 309/505] Save 'data=...' lines correctly when exiting the wizard --- components/config/gamesettings.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index a897806c2..a1b5cc99e 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -152,9 +152,31 @@ bool Config::GameSettings::writeFile(QTextStream &stream) while (i.hasPrevious()) { i.previous(); + // 'data=...' lines need quotes and ampersands escaping to match how boost::filesystem::path uses boost::io::quoted + if (i.key() == QLatin1String("data")) + { + stream << i.key() << "="; + + // The following is based on boost::io::detail::quoted_manip.hpp, but calling this function did not work as there are too may QStrings involved + QChar delim = '\"'; + QChar escape = '&'; + QString string = i.value(); + + stream << delim; + for (QString::const_iterator it = string.begin(); it != string.end(); ++it) + { + if (*it == delim || *it == escape) + stream << escape; + stream << *it; + } + stream << delim; + + stream << '\n'; + continue; + } + // Quote paths with spaces - if (i.key() == QLatin1String("data") - || i.key() == QLatin1String("data-local") + if (i.key() == QLatin1String("data-local") || i.key() == QLatin1String("resources")) { if (i.value().contains(QChar(' '))) From 7329e6a9ef528c086f5169e570d46ed5567224f7 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 15 Oct 2017 01:59:21 +0100 Subject: [PATCH 310/505] Load 'data=...' lines correctly when starting the wizard or launcher, and save them correctly when exiting the launcher. --- components/config/gamesettings.cpp | 51 ++++++++++++++++++++--- components/files/configurationmanager.cpp | 2 - 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index a1b5cc99e..62aa034ee 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -55,7 +55,6 @@ void Config::GameSettings::validatePaths() for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { QString path = QString::fromUtf8(it->string().c_str()); - path.remove(QChar('\"')); QDir dir(path); if (dir.exists()) @@ -64,6 +63,11 @@ void Config::GameSettings::validatePaths() // Do the same for data-local QString local = mSettings.value(QString("data-local")); + if (local.at(0) == QChar('\"')) + { + local.remove(0, 1); + local.chop(1); + } if (local.isEmpty()) return; @@ -76,7 +80,6 @@ void Config::GameSettings::validatePaths() if (!dataDirs.empty()) { QString path = QString::fromUtf8(dataDirs.front().string().c_str()); - path.remove(QChar('\"')); QDir dir(path); if (dir.exists()) @@ -120,6 +123,27 @@ bool Config::GameSettings::readFile(QTextStream &stream, QMap // Don't remove existing data entries if (key != QLatin1String("data")) settings.remove(key); + else + { + // 'data=...' line, so needs processing to deal with ampersands and quotes + QChar delim = '\"'; + QChar escape = '&'; + + if (value.at(0) == delim) + { + QString valueOriginal = value; + value = ""; + + for (QString::const_iterator it = valueOriginal.begin() + 1; it != valueOriginal.end(); ++it) + { + if (*it == escape) + ++it; + else if (*it == delim) + break; + value += *it; + } + } + } QStringList values = cache.values(key); values.append(settings.values(key)); @@ -157,7 +181,7 @@ bool Config::GameSettings::writeFile(QTextStream &stream) { stream << i.key() << "="; - // The following is based on boost::io::detail::quoted_manip.hpp, but calling this function did not work as there are too may QStrings involved + // The following is based on boost::io::detail::quoted_manip.hpp, but calling those functions did not work as there are too may QStrings involved QChar delim = '\"'; QChar escape = '&'; QString string = i.value(); @@ -380,9 +404,26 @@ bool Config::GameSettings::writeFileWithComments(QFile &file) { it.previous(); + if (it.key() == QLatin1String("data")) + { + settingLine = it.key() + "="; + + // The following is based on boost::io::detail::quoted_manip.hpp, but calling those functions did not work as there are too may QStrings involved + QChar delim = '\"'; + QChar escape = '&'; + QString string = it.value(); + + settingLine += delim; + for (QString::const_iterator iter = string.begin(); iter != string.end(); ++iter) + { + if (*iter == delim || *iter == escape) + settingLine += escape; + settingLine += *iter; + } + settingLine += delim; + } // Quote paths with spaces - if ((it.key() == QLatin1String("data") - || it.key() == QLatin1String("data-local") + else if ((it.key() == QLatin1String("data-local") || it.key() == QLatin1String("resources")) && it.value().contains(QChar(' '))) { QString stripped = it.value(); diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 5316255ad..7c3956a29 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -75,8 +75,6 @@ void ConfigurationManager::processPaths(Files::PathContainer& dataDirs, bool cre for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { path = it->string(); - boost::erase_all(path, "\""); - *it = boost::filesystem::path(path); // Check if path contains a token if (!path.empty() && *path.begin() == '?') From 49dbb4a9ca16ebb3d9f6d585b6a3d975d8608313 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 15 Oct 2017 02:05:22 +0100 Subject: [PATCH 311/505] Add a third copy of a comment where I felt clarification was missing --- components/config/gamesettings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 62aa034ee..0ea28dceb 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -126,6 +126,7 @@ bool Config::GameSettings::readFile(QTextStream &stream, QMap else { // 'data=...' line, so needs processing to deal with ampersands and quotes + // The following is based on boost::io::detail::quoted_manip.hpp, but calling those functions did not work as there are too may QStrings involved QChar delim = '\"'; QChar escape = '&'; From 8f255a6b726cc92c45690c313e0065df7723ec9d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 15 Oct 2017 11:03:02 +0400 Subject: [PATCH 312/505] Handle Trespassing crime differently from Theft (bug #4158) --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 2c7b6a500..dfbcf0ea2 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1123,6 +1123,10 @@ namespace MWMechanics if (playerFollowers.find(*it) != playerFollowers.end()) continue; + // NPC will complain about theft even if he will do nothing about it + if (type == OT_Theft || type == OT_Pickpocket) + MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); + crimeSeen = true; } } @@ -1243,9 +1247,7 @@ namespace MWMechanics { reported = true; - if (type == OT_Theft || type == OT_Pickpocket) - MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); - else if (type == OT_Trespassing) + if (type == OT_Trespassing) MWBase::Environment::get().getDialogueManager()->say(*it, "intruder"); } From 4c174ecd12b98ec3d31fb00ee28434385f2a679b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 15 Oct 2017 17:06:34 +0200 Subject: [PATCH 313/505] Merge changes to coverity scan script --- .travis.yml | 4 ++-- extern/osg-ffmpeg-videoplayer/License.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6606b0290..d173ef6f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,8 +41,8 @@ addons: project: name: "OpenMW/openmw" description: "" - notification_email: scrawl@baseoftrash.de - build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE" + notification_email: 720642+scrawl@users.noreply.github.com + build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_OPENCS=FALSE -DBUILD_BSATOOL=FALSE -DBUILD_ESMTOOL=FALSE -DBUILD_MWINIIMPORTER=FALSE -DBUILD_LAUNCHER=FALSE" build_command: "make -j3" branch_pattern: coverity_scan matrix: diff --git a/extern/osg-ffmpeg-videoplayer/License.txt b/extern/osg-ffmpeg-videoplayer/License.txt index 49f534065..bb70d7d37 100644 --- a/extern/osg-ffmpeg-videoplayer/License.txt +++ b/extern/osg-ffmpeg-videoplayer/License.txt @@ -1,4 +1,4 @@ -Copyright (c) 2014 Jannik Heller , Chris Robinson +Copyright (c) 2014 scrawl, Chris Robinson 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: From 50d7eb8e5470d02bec3224ec9b8df2ab1a35f29c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 15 Oct 2017 17:01:18 +0200 Subject: [PATCH 314/505] Fix crash when adding a NULL object to the cache --- components/resource/bulletshapemanager.cpp | 6 ++---- components/resource/multiobjectcache.cpp | 5 +++++ components/resource/objectcache.cpp | 5 +++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index c1a7eb8f3..53b08b8be 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -141,10 +141,7 @@ osg::ref_ptr BulletShapeManager::getShape(const std::string & node->accept(visitor); shape = visitor.getShape(); if (!shape) - { - mCache->addEntryToObjectCache(normalized, NULL); return osg::ref_ptr(); - } } mCache->addEntryToObjectCache(normalized, shape); @@ -158,7 +155,8 @@ osg::ref_ptr BulletShapeManager::cacheInstance(const std::s mVFS->normalizeFilename(normalized); osg::ref_ptr instance = createInstance(normalized); - mInstanceCache->addEntryToObjectCache(normalized, instance.get()); + if (instance) + mInstanceCache->addEntryToObjectCache(normalized, instance.get()); return instance; } diff --git a/components/resource/multiobjectcache.cpp b/components/resource/multiobjectcache.cpp index 266139f3c..d6639d3ae 100644 --- a/components/resource/multiobjectcache.cpp +++ b/components/resource/multiobjectcache.cpp @@ -51,6 +51,11 @@ namespace Resource void MultiObjectCache::addEntryToObjectCache(const std::string &filename, osg::Object *object) { + if (!object) + { + OSG_ALWAYS << " trying to add NULL object to cache for " << filename << std::endl; + return; + } OpenThreads::ScopedLock lock(_objectCacheMutex); _objectCache.insert(std::make_pair(filename, object)); } diff --git a/components/resource/objectcache.cpp b/components/resource/objectcache.cpp index de0fa7a40..e8c082f91 100644 --- a/components/resource/objectcache.cpp +++ b/components/resource/objectcache.cpp @@ -34,6 +34,11 @@ ObjectCache::~ObjectCache() void ObjectCache::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp) { + if (!object) + { + OSG_ALWAYS << " trying to add NULL object to cache for " << filename << std::endl; + return; + } OpenThreads::ScopedLock lock(_objectCacheMutex); _objectCache[filename]=ObjectTimeStampPair(object,timestamp); } From 624046c5581ba21c0da55e582e9b92cc8730a175 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 15 Oct 2017 17:01:57 +0200 Subject: [PATCH 315/505] Fix unused event handler --- apps/openmw/mwgui/savegamedialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 6a290bef1..43e511144 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -84,6 +84,7 @@ namespace MWGui dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteSlotConfirmed); dialog->eventCancelClicked.clear(); + dialog->eventCancelClicked += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteSlotCancel); } void SaveGameDialog::onDeleteSlotConfirmed() From 64d02f577e83f9bc3405c9a4ba25bf9d6d016d64 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 15 Oct 2017 17:02:36 +0200 Subject: [PATCH 316/505] Fix missing null check --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 887189a85..7f880d716 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1046,7 +1046,7 @@ namespace MWPhysics bool PhysicsSystem::isOnGround(const MWWorld::Ptr &actor) { Actor* physactor = getActor(actor); - return physactor->getOnGround(); + return physactor && physactor->getOnGround(); } bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel) From 03554b2f4bfedd27b9dca83c2147f299098a081b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 15 Oct 2017 17:03:11 +0200 Subject: [PATCH 317/505] Fix some style issues flagged by cppcheck --- apps/openmw/mwgui/dialogue.hpp | 2 -- apps/openmw/mwgui/hud.cpp | 1 - apps/openmw/mwgui/hud.hpp | 1 - apps/openmw/mwgui/spellbuyingwindow.hpp | 2 +- apps/openmw/mwgui/statswindow.cpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 6 ++---- apps/openmw/mwmechanics/combat.cpp | 20 -------------------- apps/openmw/mwmechanics/combat.hpp | 4 ---- apps/openmw/mwphysics/physicssystem.cpp | 2 -- components/nifbullet/bulletnifloader.cpp | 2 +- components/nifbullet/bulletnifloader.hpp | 2 +- components/nifosg/nifloader.cpp | 4 ++-- components/resource/bulletshapemanager.cpp | 12 +++++------- components/sceneutil/util.cpp | 9 --------- components/sceneutil/util.hpp | 2 -- components/sceneutil/workqueue.cpp | 1 + 16 files changed, 14 insertions(+), 58 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 97a0e8b37..5e362e9b5 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -155,8 +155,6 @@ namespace MWGui void restock(); void deleteLater(); - bool mEnabled; - bool mIsCompanion; std::list mKeywords; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 1db2691f4..23eb499de 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -80,7 +80,6 @@ namespace MWGui , mSpellStatus(NULL) , mEffectBox(NULL) , mMinimap(NULL) - , mCompass(NULL) , mCrosshair(NULL) , mCellNameBox(NULL) , mDrowningFrame(NULL) diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 3542f3ebf..73428c034 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -69,7 +69,6 @@ namespace MWGui MyGUI::Widget *mEffectBox, *mMinimapBox; MyGUI::Button* mMinimapButton; MyGUI::ScrollView* mMinimap; - MyGUI::ImageBox* mCompass; MyGUI::ImageBox* mCrosshair; MyGUI::TextBox* mCellNameBox; MyGUI::TextBox* mWeaponSpellBox; diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 649aab3f2..3414c1b94 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -46,7 +46,7 @@ namespace MWGui void onMouseWheel(MyGUI::Widget* _sender, int _rel); void addSpell(const ESM::Spell& spell); void clearSpells(); - int mLastPos,mCurrentY; + int mCurrentY; static const int sLineHeight; diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index bf505b00f..d3d487579 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -105,7 +105,7 @@ namespace MWGui std::stringstream out; out << val << "/" << max; - setText(tname, out.str().c_str()); + setText(tname, out.str()); pt->setProgressRange(std::max(0, max)); pt->setProgressPosition(std::max(0, val)); diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 7f412b4d2..255874d88 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -451,11 +451,10 @@ namespace MWMechanics // Check if an idle actor is too close to a door - if so start walking storage.mDoorCheckDuration += duration; - static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); - if (storage.mDoorCheckDuration >= DOOR_CHECK_INTERVAL) { storage.mDoorCheckDuration = 0; // restart timer + static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); if (mDistance && // actor is not intended to be stationary proximityToDoor(actor, distance*1.6f)) { @@ -531,11 +530,10 @@ namespace MWMechanics void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos) { - static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); - if (mObstacleCheck.isEvading()) { // first check if we're walking into a door + static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); if (proximityToDoor(actor, distance)) { // remove allowed points then select another random destination diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 54ad75135..13cd4232d 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -424,26 +424,6 @@ namespace MWMechanics } } - bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim) - { - const MWWorld::Class& attackerClass = attacker.getClass(); - MWBase::World* world = MWBase::Environment::get().getWorld(); - - // If attacker is fish, victim must be in water - if (attackerClass.isPureWaterCreature(attacker)) - { - return world->isWading(victim); - } - - // If attacker can't swim, victim must not be in water - if (!attackerClass.canSwim(attacker)) - { - return !world->isSwimming(victim); - } - - return true; - } - float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2) { osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3()); diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index 12961dc4b..8b93ca204 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -39,10 +39,6 @@ void getHandToHandDamage (const MWWorld::Ptr& attacker, const MWWorld::Ptr& vict /// Apply the fatigue loss incurred by attacking with the given weapon (weapon may be empty = hand-to-hand) void applyFatigueLoss(const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float attackStrength); -/// Can attacker operate in victim's environment? -/// e.g. If attacker is a fish, is victim in water? Or, if attacker can't swim, is victim on land? -bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim); - float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2); } diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 7f880d716..34932e360 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -702,8 +702,6 @@ namespace MWPhysics const char* env = getenv("OPENMW_PHYSICS_FPS"); if (env) { - std::string str(env); - float physFramerate = std::atof(env); if (physFramerate > 0) { diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 3865b17a5..9e9fe3759 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -49,7 +49,7 @@ BulletNifLoader::~BulletNifLoader() { } -osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) +osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr& nif) { mShape = new Resource::BulletShape; diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index a30bf8fdf..fff51933f 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -50,7 +50,7 @@ public: abort(); } - osg::ref_ptr load(const Nif::NIFFilePtr file); + osg::ref_ptr load(const Nif::NIFFilePtr& file); private: bool findBoundingBox(const Nif::Node* node, int flags = 0); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 8810f171a..a3b81338e 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1191,8 +1191,8 @@ namespace NifOsg if (pixelData->mipmaps.empty()) return NULL; - unsigned int width = 0; - unsigned int height = 0; + int width = 0; + int height = 0; std::vector mipmapVector; for (unsigned int i=0; imipmaps.size()-3; ++i) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index 53b08b8be..a3d09311a 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -63,7 +63,7 @@ class NodeToShapeVisitor : public osg::NodeVisitor public: NodeToShapeVisitor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mTriangleMesh(NULL) + , mTriangleMesh(nullptr) { } @@ -71,11 +71,11 @@ public: virtual void apply(osg::Drawable &drawable) { if (!mTriangleMesh) - mTriangleMesh = new btTriangleMesh; + mTriangleMesh.reset(new btTriangleMesh); osg::Matrixf worldMat = osg::computeLocalToWorld(getNodePath()); osg::TriangleFunctor functor; - functor.setTriMesh(mTriangleMesh); + functor.setTriMesh(mTriangleMesh.get()); functor.setMatrix(worldMat); drawable.accept(functor); } @@ -86,14 +86,12 @@ public: return osg::ref_ptr(); osg::ref_ptr shape (new BulletShape); - TriangleMeshShape* meshShape = new TriangleMeshShape(mTriangleMesh, true); - shape->mCollisionShape = meshShape; - mTriangleMesh = NULL; + shape->mCollisionShape = new TriangleMeshShape(mTriangleMesh.release(), true); return shape; } private: - btTriangleMesh* mTriangleMesh; + std::unique_ptr mTriangleMesh; }; BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr, NifFileManager* nifFileManager) diff --git a/components/sceneutil/util.cpp b/components/sceneutil/util.cpp index 3add3bb23..eec302965 100644 --- a/components/sceneutil/util.cpp +++ b/components/sceneutil/util.cpp @@ -42,13 +42,4 @@ osg::Vec4f colourFromRGB(unsigned int clr) return colour; } -osg::Vec4f colourFromRGBA(unsigned int clr) -{ - osg::Vec4f colour(((clr >> 0) & 0xFF) / 255.0f, - ((clr >> 8) & 0xFF) / 255.0f, - ((clr >> 16) & 0xFF) / 255.0f, - ((clr >> 24) & 0xFF) / 255.0f); - return colour; -} - } diff --git a/components/sceneutil/util.hpp b/components/sceneutil/util.hpp index d8fefdb29..109099740 100644 --- a/components/sceneutil/util.hpp +++ b/components/sceneutil/util.hpp @@ -15,8 +15,6 @@ namespace SceneUtil osg::Vec4f colourFromRGB (unsigned int clr); - osg::Vec4f colourFromRGBA (unsigned int clr); - } #endif diff --git a/components/sceneutil/workqueue.cpp b/components/sceneutil/workqueue.cpp index cc40506f0..2cd1ec806 100644 --- a/components/sceneutil/workqueue.cpp +++ b/components/sceneutil/workqueue.cpp @@ -119,6 +119,7 @@ unsigned int WorkQueue::getNumActiveThreads() const WorkThread::WorkThread(WorkQueue *workQueue) : mWorkQueue(workQueue) + , mActive(false) { } From 136ef1f738b84db1be424be412e45532fdeecf8b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 15 Oct 2017 17:24:23 +0200 Subject: [PATCH 318/505] Fix incomplete settings in recreateShaders() --- components/resource/scenemanager.cpp | 35 +++++++++++++++------------- components/resource/scenemanager.hpp | 3 +++ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index ab801ab82..9c5a2a14e 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -244,12 +244,9 @@ namespace Resource void SceneManager::recreateShaders(osg::ref_ptr node) { - Shader::ShaderVisitor shaderVisitor(*mShaderManager.get(), *mImageManager, "objects_vertex.glsl", "objects_fragment.glsl"); - shaderVisitor.setForceShaders(mForceShaders); - shaderVisitor.setClampLighting(mClampLighting); - shaderVisitor.setForcePerPixelLighting(mForcePerPixelLighting); - shaderVisitor.setAllowedToModifyStateSets(false); - node->accept(shaderVisitor); + osg::ref_ptr shaderVisitor(createShaderVisitor()); + shaderVisitor->setAllowedToModifyStateSets(false); + node->accept(*shaderVisitor); } void SceneManager::setClampLighting(bool clamp) @@ -516,16 +513,8 @@ namespace Resource SetFilterSettingsControllerVisitor setFilterSettingsControllerVisitor(mMinFilter, mMagFilter, mMaxAnisotropy); loaded->accept(setFilterSettingsControllerVisitor); - Shader::ShaderVisitor shaderVisitor(*mShaderManager.get(), *mImageManager, "objects_vertex.glsl", "objects_fragment.glsl"); - shaderVisitor.setForceShaders(mForceShaders); - shaderVisitor.setClampLighting(mClampLighting); - shaderVisitor.setForcePerPixelLighting(mForcePerPixelLighting); - shaderVisitor.setAutoUseNormalMaps(mAutoUseNormalMaps); - shaderVisitor.setNormalMapPattern(mNormalMapPattern); - shaderVisitor.setNormalHeightMapPattern(mNormalHeightMapPattern); - shaderVisitor.setAutoUseSpecularMaps(mAutoUseSpecularMaps); - shaderVisitor.setSpecularMapPattern(mSpecularMapPattern); - loaded->accept(shaderVisitor); + osg::ref_ptr shaderVisitor (createShaderVisitor()); + loaded->accept(*shaderVisitor); // share state // do this before optimizing so the optimizer will be able to combine nodes more aggressively @@ -748,4 +737,18 @@ namespace Resource stats->setAttribute(frameNumber, "Node Instance", mInstanceCache->getCacheSize()); } + Shader::ShaderVisitor *SceneManager::createShaderVisitor() + { + Shader::ShaderVisitor* shaderVisitor = new Shader::ShaderVisitor(*mShaderManager.get(), *mImageManager, "objects_vertex.glsl", "objects_fragment.glsl"); + shaderVisitor->setForceShaders(mForceShaders); + shaderVisitor->setClampLighting(mClampLighting); + shaderVisitor->setForcePerPixelLighting(mForcePerPixelLighting); + shaderVisitor->setAutoUseNormalMaps(mAutoUseNormalMaps); + shaderVisitor->setNormalMapPattern(mNormalMapPattern); + shaderVisitor->setNormalHeightMapPattern(mNormalHeightMapPattern); + shaderVisitor->setAutoUseSpecularMaps(mAutoUseSpecularMaps); + shaderVisitor->setSpecularMapPattern(mSpecularMapPattern); + return shaderVisitor; + } + } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index b223353c2..4f1523ece 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -31,6 +31,7 @@ namespace osgDB namespace Shader { class ShaderManager; + class ShaderVisitor; } namespace Resource @@ -149,6 +150,8 @@ namespace Resource private: + Shader::ShaderVisitor* createShaderVisitor(); + std::unique_ptr mShaderManager; bool mForceShaders; bool mClampLighting; From 654bd401fb9e005fef5bc2c243386616e2dc2123 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 16 Oct 2017 15:38:17 +0100 Subject: [PATCH 319/505] Switch openmw-cs to the escape versions of option types --- apps/opencs/editor.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 86c87962d..334674aa7 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -90,16 +90,16 @@ std::pair > CS::Editor::readConfi 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()) - ("data-local", boost::program_options::value()->default_value("")) + ("data", boost::program_options::value()->default_value(Files::EscapePathContainer(), "data")->multitoken()->composing()) + ("data-local", boost::program_options::value()->default_value("")) ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) - ("encoding", boost::program_options::value()->default_value("win1252")) - ("resources", boost::program_options::value()->default_value("resources")) - ("fallback-archive", boost::program_options::value >()-> - default_value(std::vector(), "fallback-archive")->multitoken()) + ("encoding", boost::program_options::value()->default_value("win1252")) + ("resources", boost::program_options::value()->default_value("resources")) + ("fallback-archive", boost::program_options::value()-> + default_value(Files::EscapeStringVector(), "fallback-archive")->multitoken()) ("fallback", boost::program_options::value()->default_value(FallbackMap(), "") ->multitoken()->composing(), "fallback values") - ("script-blacklist", boost::program_options::value >()->default_value(std::vector(), "") + ("script-blacklist", boost::program_options::value()->default_value(Files::EscapeStringVector(), "") ->multitoken(), "exclude specified script from the verifier (if the use of the blacklist is enabled)") ("script-blacklist-use", boost::program_options::value()->implicit_value(true) ->default_value(true), "enable script blacklisting"); @@ -109,24 +109,24 @@ std::pair > CS::Editor::readConfi mCfgMgr.readConfiguration(variables, desc, quiet); mDocumentManager.setEncoding ( - ToUTF8::calculateEncoding (variables["encoding"].as())); + ToUTF8::calculateEncoding (variables["encoding"].as().toStdString())); - mDocumentManager.setResourceDir (mResources = variables["resources"].as()); + mDocumentManager.setResourceDir (mResources = variables["resources"].as().toStdString()); mDocumentManager.setFallbackMap (variables["fallback"].as().mMap); if (variables["script-blacklist-use"].as()) mDocumentManager.setBlacklistedScripts ( - variables["script-blacklist"].as >()); + variables["script-blacklist"].as().toStdStringVector()); mFsStrict = variables["fs-strict"].as(); Files::PathContainer dataDirs, dataLocal; if (!variables["data"].empty()) { - dataDirs = Files::PathContainer(variables["data"].as()); + dataDirs = Files::PathContainer(Files::EscapePath::toPathContainer(variables["data"].as())); } - std::string local = variables["data-local"].as(); + std::string local = variables["data-local"].as().toStdString(); if (!local.empty()) { dataLocal.push_back(Files::PathContainer::value_type(local)); } @@ -157,7 +157,7 @@ std::pair > CS::Editor::readConfi mFileDialog.addFiles(path); } - return std::make_pair (dataDirs, variables["fallback-archive"].as >()); + return std::make_pair (dataDirs, variables["fallback-archive"].as().toStdStringVector()); } void CS::Editor::createGame() From 6d7a24224b489c6fee804fc3d05350e615c77046 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 16 Oct 2017 12:52:13 -0400 Subject: [PATCH 320/505] Add documentation. --- apps/opencs/model/tools/mergestages.hpp | 6 ++++-- apps/opencs/model/world/commands.hpp | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 9a16e03ab..4b41c5a04 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -147,7 +147,8 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - /// Flattens the added land and land texture records. + /// During this stage, the complex process of combining LandTextures from + /// potentially multiple plugins is undertaken. class FixLandsAndLandTexturesMergeStage : public CSMDoc::Stage { MergeState& mState; @@ -163,7 +164,8 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - // Removes base LandTexture records. + /// Removes base LandTexture records. This gets rid of the base records previously + /// needed in FixLandsAndLandTexturesMergeStage. class CleanupLandTexturesMergeStage : public CSMDoc::Stage { MergeState& mState; diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index be86dd508..58a1b1d1c 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -44,6 +44,15 @@ namespace CSMWorld bool mChanged; }; + /// \brief Adds LandTexture records and modifies texture indices as needed. + /// + /// LandTexture records are different from other types of records, because + /// they only effect the current plugin. Thus, when modifying or copying + /// a Land record, all of the LandTexture records referenced need to be + /// added to the current plugin. Since these newly added LandTextures could + /// have indices that conflict with pre-existing LandTextures in the current + /// plugin, the indices might have to be changed, both for the newly added + /// LandRecord and within the Land record. class ImportLandTexturesCommand : public QUndoCommand { public: @@ -71,6 +80,9 @@ namespace CSMWorld std::vector mCreatedTextures; }; + /// \brief This command is used to fix LandTexture records and texture + /// indices after cloning a Land. See ImportLandTexturesCommand for + /// details. class CopyLandTexturesCommand : public ImportLandTexturesCommand { public: @@ -90,6 +102,9 @@ namespace CSMWorld std::string mDestId; }; + /// \brief This command brings a land record into the current plugin, adding + /// LandTexture records and modifying texture indices as needed. + /// \note See ImportLandTextures for more details. class TouchLandCommand : public ImportLandTexturesCommand { public: From da4765362593c80bed5c39b9333e6eec48e1500c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Mon, 16 Oct 2017 19:47:08 +0200 Subject: [PATCH 321/505] move rain intensity uniform to water node --- apps/openmw/mwrender/renderingmanager.cpp | 9 +++------ apps/openmw/mwrender/renderingmanager.hpp | 1 - apps/openmw/mwrender/sky.cpp | 13 ++++++++++--- apps/openmw/mwrender/sky.hpp | 6 +++++- apps/openmw/mwrender/water.cpp | 11 ++++++++++- apps/openmw/mwrender/water.hpp | 5 +++++ 6 files changed, 33 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index aa7b35b44..7585ee32a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -251,12 +251,9 @@ namespace MWRender sceneRoot->setNodeMask(Mask_Scene); sceneRoot->setName("Scene Root"); - mUniformRainIntensity = new osg::Uniform("rainIntensity",(float) 0.0); - - mRootNode->getOrCreateStateSet()->addUniform(mUniformRainIntensity); - mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager())); mSky->setCamera(mViewer->getCamera()); + mSky->setRainIntensityUniform(mWater->getRainIntensityUniform()); source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); @@ -506,7 +503,7 @@ namespace MWRender } if (!mSky->isEnabled() || !mSky->hasRain()) - clearRainRipples(); + clearRainRipples(); mCamera->update(dt, paused); @@ -811,7 +808,7 @@ namespace MWRender void RenderingManager::clearRainRipples() { - mUniformRainIntensity->set((float) 0.0); + mWater->getRainIntensityUniform()->set((float) 0.0); } void RenderingManager::clear() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 43059ab6d..f9e98b269 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -85,7 +85,6 @@ namespace MWRender osg::Uniform* mUniformNear; osg::Uniform* mUniformFar; - osg::Uniform* mUniformRainIntensity; void preloadCommonAssets(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 1338a127c..cffa9909a 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1096,6 +1096,7 @@ private: SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) : mSceneManager(sceneManager) , mCamera(NULL) + , mRainIntensityUniform(NULL) , mAtmosphereNightRoll(0.f) , mCreated(false) , mIsStorm(false) @@ -1138,6 +1139,11 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana mUnderwaterSwitch = new UnderwaterSwitchCallback(skyroot); } +void SkyManager::setRainIntensityUniform(osg::Uniform *uniform) +{ + mRainIntensityUniform = uniform; +} + void SkyManager::create() { assert(!mCreated); @@ -1315,7 +1321,6 @@ protected: class RainFader : public AlphaFader { public: - RainFader(osg::Uniform *rainIntensityUniform): AlphaFader() { mRainIntensityUniform = rainIntensityUniform; @@ -1481,7 +1486,7 @@ void SkyManager::createRain() mRainNode->addChild(mRainParticleSystem); mRainNode->addChild(updater); - mRainFader = new RainFader(mRootNode->getParent(0)->getParent(0)->getStateSet()->getUniform("rainIntensity")); + mRainFader = new RainFader(mRainIntensityUniform); mRainNode->addUpdateCallback(mRainFader); mRainNode->addCullCallback(mUnderwaterSwitch); mRainNode->setNodeMask(Mask_WeatherParticles); @@ -1742,7 +1747,8 @@ void SkyManager::setWeather(const WeatherResult& weather) mSun->adjustTransparency(weather.mGlareView * weather.mSunDiscColor.a()); float nextStarsOpacity = weather.mNightFade * weather.mGlareView; - if(weather.mNight && mStarsOpacity != nextStarsOpacity) + + if (weather.mNight && mStarsOpacity != nextStarsOpacity) { mStarsOpacity = nextStarsOpacity; @@ -1753,6 +1759,7 @@ void SkyManager::setWeather(const WeatherResult& weather) if (mRainFader) mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold? + for (std::vector >::const_iterator it = mParticleFaders.begin(); it != mParticleFaders.end(); ++it) (*it)->setAlpha(weather.mEffectFade); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 097405b24..816dbf798 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -8,6 +8,7 @@ #include #include +#include namespace osg { @@ -168,6 +169,8 @@ namespace MWRender void setCamera(osg::Camera *camera); + void setRainIntensityUniform(osg::Uniform *uniform); + private: void create(); ///< no need to call this, automatically done on first enable() @@ -178,7 +181,8 @@ namespace MWRender Resource::SceneManager* mSceneManager; - osg::Camera* mCamera; + osg::Camera *mCamera; + osg::Uniform *mRainIntensityUniform; osg::ref_ptr mRootNode; osg::ref_ptr mEarlyRenderBinRoot; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 68c07c1ab..8935eb37a 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -411,14 +411,20 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem createSimpleWaterStateSet(geom2, mFallback->getFallbackFloat("Water_Map_Alpha")); geom2->setNodeMask(Mask_SimpleWater); mWaterNode->addChild(geom2); - + mSceneRoot->addChild(mWaterNode); setHeight(mTop); + mRainIntensityUniform = NULL; updateWaterMaterial(); } +osg::Uniform *Water::getRainIntensityUniform() +{ + return mRainIntensityUniform; +} + void Water::updateWaterMaterial() { if (mReflection) @@ -550,6 +556,9 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R program->addShader(fragmentShader); shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); + mRainIntensityUniform = new osg::Uniform("rainIntensity",(float) 0.0); + shaderStateset->addUniform(mRainIntensityUniform); + node->setStateSet(shaderStateset); node->setUpdateCallback(NULL); } diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 33b314c51..6c7adac37 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -6,6 +6,7 @@ #include #include +#include #include @@ -50,6 +51,8 @@ namespace MWRender { static const int CELL_SIZE = 8192; + osg::Uniform* mRainIntensityUniform; + osg::ref_ptr mParent; osg::ref_ptr mSceneRoot; osg::ref_ptr mWaterNode; @@ -110,6 +113,8 @@ namespace MWRender void update(float dt); void processChangedSettings(const Settings::CategorySettingVector& settings); + + osg::Uniform *getRainIntensityUniform(); }; } From 797e407269b2e4aef6cba8e521f07a7f7819276f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Mon, 16 Oct 2017 20:23:56 +0200 Subject: [PATCH 322/505] make snow create water ripples --- apps/openmw/mwrender/sky.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index cffa9909a..05937742f 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1245,9 +1245,11 @@ private: class AlphaFader : public SceneUtil::StateSetUpdater { public: - AlphaFader() + /// @param rainIntensityUniform rain uniform to update along with alpha, can be NULL + AlphaFader(osg::Uniform *rainIntensityUniform=NULL) : mAlpha(1.f) { + mRainIntensityUniform = rainIntensityUniform; } void setAlpha(float alpha) @@ -1266,15 +1268,19 @@ public: { osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mAlpha)); + + if (mRainIntensityUniform) + mRainIntensityUniform->set((float) mAlpha); } // Helper for adding AlphaFaders to a subgraph class SetupVisitor : public osg::NodeVisitor { public: - SetupVisitor() + SetupVisitor(osg::Uniform *rainIntensityUniform) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) { + mRainIntensityUniform = rainIntensityUniform; } virtual void apply(osg::Node &node) @@ -1285,14 +1291,16 @@ public: { SceneUtil::CompositeStateSetUpdater* composite = NULL; osg::Callback* callback = node.getUpdateCallback(); + while (callback) { if ((composite = dynamic_cast(callback))) break; + callback = callback->getNestedCallback(); } - osg::ref_ptr alphaFader (new AlphaFader); + osg::ref_ptr alphaFader (new AlphaFader(mRainIntensityUniform)); if (composite) composite->addController(alphaFader); @@ -1312,10 +1320,12 @@ public: private: std::vector > mAlphaFaders; + osg::Uniform *mRainIntensityUniform; }; protected: float mAlpha; + osg::Uniform *mRainIntensityUniform; }; class RainFader : public AlphaFader @@ -1645,12 +1655,16 @@ void SkyManager::setWeather(const WeatherResult& weather) mParticleNode->setNodeMask(Mask_WeatherParticles); mRootNode->addChild(mParticleNode); } + mParticleEffect = mSceneManager->getInstance(mCurrentParticleEffect, mParticleNode); SceneUtil::AssignControllerSourcesVisitor assignVisitor(std::shared_ptr(new SceneUtil::FrameTimeSource)); mParticleEffect->accept(assignVisitor); - AlphaFader::SetupVisitor alphaFaderSetupVisitor; + osg::Uniform *rainUniform = weather.mIsStorm ? NULL : mRainIntensityUniform; + + AlphaFader::SetupVisitor alphaFaderSetupVisitor(rainUniform); + mParticleEffect->accept(alphaFaderSetupVisitor); mParticleFaders = alphaFaderSetupVisitor.getAlphaFaders(); From 8a1e0e74fd7f35ee4be220ab3796995fed0fbc2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Mon, 16 Oct 2017 23:56:03 +0200 Subject: [PATCH 323/505] update uniform from one place --- apps/openmw/mwrender/renderingmanager.cpp | 9 ----- apps/openmw/mwrender/renderingmanager.hpp | 2 - apps/openmw/mwrender/sky.cpp | 46 ++++++++++++----------- apps/openmw/mwrender/sky.hpp | 2 + 4 files changed, 27 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7585ee32a..6c4cc802b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -502,9 +502,6 @@ namespace MWRender mWater->update(dt); } - if (!mSky->isEnabled() || !mSky->hasRain()) - clearRainRipples(); - mCamera->update(dt, paused); osg::Vec3f focal, cameraPos; @@ -803,12 +800,6 @@ namespace MWRender void RenderingManager::notifyWorldSpaceChanged() { mEffectManager->clear(); - mWater->clearRipples(); - } - - void RenderingManager::clearRainRipples() - { - mWater->getRainIntensityUniform()->set((float) 0.0); } void RenderingManager::clear() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index f9e98b269..f0087e43d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -159,8 +159,6 @@ namespace MWRender /// Clear all worldspace-specific data void notifyWorldSpaceChanged(); - void clearRainRipples(); - void update(float dt, bool paused); Animation* getAnimation(const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 05937742f..97633a6b9 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1245,11 +1245,11 @@ private: class AlphaFader : public SceneUtil::StateSetUpdater { public: - /// @param rainIntensityUniform rain uniform to update along with alpha, can be NULL - AlphaFader(osg::Uniform *rainIntensityUniform=NULL) + /// @param alphaUpdate variable which to update with alpha value + AlphaFader(float *alphaUpdate) : mAlpha(1.f) { - mRainIntensityUniform = rainIntensityUniform; + mAlphaUpdate = alphaUpdate; } void setAlpha(float alpha) @@ -1269,18 +1269,18 @@ public: osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mAlpha)); - if (mRainIntensityUniform) - mRainIntensityUniform->set((float) mAlpha); + if (mAlphaUpdate) + *mAlphaUpdate = mAlpha; } // Helper for adding AlphaFaders to a subgraph class SetupVisitor : public osg::NodeVisitor { public: - SetupVisitor(osg::Uniform *rainIntensityUniform) + SetupVisitor(float *alphaUpdate) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) { - mRainIntensityUniform = rainIntensityUniform; + mAlphaUpdate = alphaUpdate; } virtual void apply(osg::Node &node) @@ -1300,7 +1300,7 @@ public: callback = callback->getNestedCallback(); } - osg::ref_ptr alphaFader (new AlphaFader(mRainIntensityUniform)); + osg::ref_ptr alphaFader (new AlphaFader(mAlphaUpdate)); if (composite) composite->addController(alphaFader); @@ -1310,6 +1310,7 @@ public: mAlphaFaders.push_back(alphaFader); } } + traverse(node); } @@ -1320,20 +1321,19 @@ public: private: std::vector > mAlphaFaders; - osg::Uniform *mRainIntensityUniform; + float *mAlphaUpdate; }; protected: float mAlpha; - osg::Uniform *mRainIntensityUniform; + float *mAlphaUpdate; }; class RainFader : public AlphaFader { public: - RainFader(osg::Uniform *rainIntensityUniform): AlphaFader() + RainFader(float *alphaUpdate): AlphaFader(alphaUpdate) { - mRainIntensityUniform = rainIntensityUniform; } virtual void setDefaults(osg::StateSet* stateset) @@ -1348,11 +1348,8 @@ public: virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { AlphaFader::apply(stateset,nv); - mRainIntensityUniform->set((float) (mAlpha * 2.0)); // mAlpha is limited to 0.6 so multiply by 2 to reach full intensity + *mAlphaUpdate = mAlpha * 2.0; // mAlpha is limited to 0.6 so multiply by 2 to reach full intensity } - -protected: - osg::Uniform* mRainIntensityUniform; }; void SkyManager::setCamera(osg::Camera *camera) @@ -1496,7 +1493,7 @@ void SkyManager::createRain() mRainNode->addChild(mRainParticleSystem); mRainNode->addChild(updater); - mRainFader = new RainFader(mRainIntensityUniform); + mRainFader = new RainFader(&mWeatherAlpha); mRainNode->addUpdateCallback(mRainFader); mRainNode->addCullCallback(mUnderwaterSwitch); mRainNode->setNodeMask(Mask_WeatherParticles); @@ -1549,7 +1546,16 @@ bool SkyManager::hasRain() void SkyManager::update(float duration) { - if (!mEnabled) return; + if (!mEnabled) + { + mRainIntensityUniform->set((float) 0.0); + return; + } + + if (mIsStorm || (!hasRain() && !mParticleNode)) + mRainIntensityUniform->set((float) 0.0); + else + mRainIntensityUniform->set((float) mWeatherAlpha); if (mIsStorm) { @@ -1661,9 +1667,7 @@ void SkyManager::setWeather(const WeatherResult& weather) SceneUtil::AssignControllerSourcesVisitor assignVisitor(std::shared_ptr(new SceneUtil::FrameTimeSource)); mParticleEffect->accept(assignVisitor); - osg::Uniform *rainUniform = weather.mIsStorm ? NULL : mRainIntensityUniform; - - AlphaFader::SetupVisitor alphaFaderSetupVisitor(rainUniform); + AlphaFader::SetupVisitor alphaFaderSetupVisitor(&mWeatherAlpha); mParticleEffect->accept(alphaFaderSetupVisitor); mParticleFaders = alphaFaderSetupVisitor.getAlphaFaders(); diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 816dbf798..4357d468c 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -252,6 +252,8 @@ namespace MWRender bool mEnabled; bool mSunEnabled; + float mWeatherAlpha; + osg::Vec4f mMoonScriptColor; }; } From a7cad65aab97f00757ef421452ba14ddd229cecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Tue, 17 Oct 2017 00:13:55 +0200 Subject: [PATCH 324/505] fix water shader switching bug --- apps/openmw/mwrender/sky.cpp | 15 ++++++++++----- apps/openmw/mwrender/water.cpp | 6 +++--- apps/openmw/mwrender/water.hpp | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 97633a6b9..6c599fc3f 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1548,14 +1548,19 @@ void SkyManager::update(float duration) { if (!mEnabled) { - mRainIntensityUniform->set((float) 0.0); + if (mRainIntensityUniform) + mRainIntensityUniform->set((float) 0.0); + return; } - if (mIsStorm || (!hasRain() && !mParticleNode)) - mRainIntensityUniform->set((float) 0.0); - else - mRainIntensityUniform->set((float) mWeatherAlpha); + if (mRainIntensityUniform) + { + if (mIsStorm || (!hasRain() && !mParticleNode)) + mRainIntensityUniform->set((float) 0.0); + else + mRainIntensityUniform->set((float) mWeatherAlpha); + } if (mIsStorm) { diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 8935eb37a..52b659984 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -416,13 +416,14 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem setHeight(mTop); - mRainIntensityUniform = NULL; updateWaterMaterial(); + + mRainIntensityUniform = new osg::Uniform("rainIntensity",(float) 0.0); } osg::Uniform *Water::getRainIntensityUniform() { - return mRainIntensityUniform; + return mRainIntensityUniform.get(); } void Water::updateWaterMaterial() @@ -556,7 +557,6 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R program->addShader(fragmentShader); shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); - mRainIntensityUniform = new osg::Uniform("rainIntensity",(float) 0.0); shaderStateset->addUniform(mRainIntensityUniform); node->setStateSet(shaderStateset); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 6c7adac37..a4fd1ed36 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -51,7 +51,7 @@ namespace MWRender { static const int CELL_SIZE = 8192; - osg::Uniform* mRainIntensityUniform; + osg::ref_ptr mRainIntensityUniform; osg::ref_ptr mParent; osg::ref_ptr mSceneRoot; From 4d4d247565338db653111fe92deb23c099966d3a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 17 Oct 2017 23:26:55 +0400 Subject: [PATCH 325/505] Use SwimTurnLeft/Right animations correctly --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ec65255bc..03acfdaf2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1874,7 +1874,7 @@ void CharacterController::update(float duration) : (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack))); } - else if(rot.z() != 0.0f && !inwater && !sneak && !(mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())) + else if(rot.z() != 0.0f && !sneak && !(mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())) { if(rot.z() > 0.0f) movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight; From 1f77f9654bba0e286ada5d3d593c1f4bf43ac781 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 18 Oct 2017 01:42:11 +0100 Subject: [PATCH 326/505] Strip quotes from the data-local setting if present (because for whatever reason it's a string, not a boost::filesystem::path) --- apps/openmw/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 9e44f237e..ac891b980 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -194,6 +194,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat std::string local(variables["data-local"].as().toStdString()); if (!local.empty()) { + if (local.front() == '\"') + local = local.substr(1, local.length() - 2); + dataDirs.push_back(Files::PathContainer::value_type(local)); } From 43e9e955c88aaade0b68bd00d7ce00e7c5f65bf9 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 18 Oct 2017 02:04:48 +0100 Subject: [PATCH 327/505] Do the same for the CS --- apps/opencs/editor.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 334674aa7..35ce51337 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -127,7 +127,11 @@ std::pair > CS::Editor::readConfi } std::string local = variables["data-local"].as().toStdString(); - if (!local.empty()) { + if (!local.empty()) + { + if (local.front() == '\"') + local = local.substr(1, local.length() - 2); + dataLocal.push_back(Files::PathContainer::value_type(local)); } From 2aad5bed7a9789b2feb22b225f23eefc73777107 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 18 Oct 2017 05:00:32 +0100 Subject: [PATCH 328/505] Mark worldimp functions as override to stop distracting Travis CI warnings and prevent future typos --- apps/openmw/mwworld/worldimp.hpp | 352 +++++++++++++++---------------- 1 file changed, 176 insertions(+), 176 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 774753b6c..c130c9d5b 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -137,7 +137,7 @@ namespace MWWorld MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true); public: // FIXME - void removeContainerScripts(const Ptr& reference); + void removeContainerScripts(const Ptr& reference) override; private: void addContainerScripts(const Ptr& reference, CellStore* cell); void PCDropped (const Ptr& item); @@ -191,362 +191,362 @@ namespace MWWorld virtual ~World(); - virtual void startNewGame (bool bypass); + virtual void startNewGame (bool bypass) override; ///< \param bypass Bypass regular game start. - virtual void clear(); + virtual void clear() override; - virtual int countSavedGameRecords() const; - virtual int countSavedGameCells() const; + virtual int countSavedGameRecords() const override; + virtual int countSavedGameCells() const override; - virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; + virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const override; virtual void readRecord (ESM::ESMReader& reader, uint32_t type, - const std::map& contentFileMap); + const std::map& contentFileMap) override; - virtual CellStore *getExterior (int x, int y); + virtual CellStore *getExterior (int x, int y) override; - virtual CellStore *getInterior (const std::string& name); + virtual CellStore *getInterior (const std::string& name) override; - virtual CellStore *getCell (const ESM::CellId& id); + virtual CellStore *getCell (const ESM::CellId& id) override; //switch to POV before showing player's death animation - virtual void useDeathCamera(); + virtual void useDeathCamera() override; - virtual void setWaterHeight(const float height); + virtual void setWaterHeight(const float height) override; - virtual bool toggleWater(); - virtual bool toggleWorld(); + virtual bool toggleWater() override; + virtual bool toggleWorld() override; - virtual void adjustSky(); + virtual void adjustSky() override; - virtual const Fallback::Map *getFallback() const; + virtual const Fallback::Map *getFallback() const override; - virtual Player& getPlayer(); - virtual MWWorld::Ptr getPlayerPtr(); + virtual Player& getPlayer() override; + virtual MWWorld::Ptr getPlayerPtr() override; - virtual const MWWorld::ESMStore& getStore() const; + virtual const MWWorld::ESMStore& getStore() const override; virtual std::vector& getEsmReader(); - virtual LocalScripts& getLocalScripts(); + virtual LocalScripts& getLocalScripts() override; - virtual bool hasCellChanged() const; + virtual bool hasCellChanged() const override; ///< Has the set of active cells changed, since the last frame? - virtual bool isCellExterior() const; + virtual bool isCellExterior() const override; - virtual bool isCellQuasiExterior() const; + virtual bool isCellQuasiExterior() const override; - virtual osg::Vec2f getNorthVector (const CellStore* cell); + virtual osg::Vec2f getNorthVector (const CellStore* cell) override; ///< get north vector for given interior cell - virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out); + virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out) override; ///< get a list of teleport door markers for a given cell, to be displayed on the local map - virtual void setGlobalInt (const std::string& name, int value); + virtual void setGlobalInt (const std::string& name, int value) override; ///< Set value independently from real type. - virtual void setGlobalFloat (const std::string& name, float value); + virtual void setGlobalFloat (const std::string& name, float value) override; ///< Set value independently from real type. - virtual int getGlobalInt (const std::string& name) const; + virtual int getGlobalInt (const std::string& name) const override; ///< Get value independently from real type. - virtual float getGlobalFloat (const std::string& name) const; + virtual float getGlobalFloat (const std::string& name) const override; ///< Get value independently from real type. - virtual char getGlobalVariableType (const std::string& name) const; + virtual char getGlobalVariableType (const std::string& name) const override; ///< Return ' ', if there is no global variable with this name. - virtual std::string getCellName (const MWWorld::CellStore *cell = 0) const; + virtual std::string getCellName (const MWWorld::CellStore *cell = 0) const override; ///< Return name of the cell. /// /// \note If cell==0, the cell the player is currently in will be used instead to /// generate a name. - virtual void removeRefScript (MWWorld::RefData *ref); + virtual void removeRefScript (MWWorld::RefData *ref) override; //< Remove the script attached to ref from mLocalScripts - virtual Ptr getPtr (const std::string& name, bool activeOnly); + virtual Ptr getPtr (const std::string& name, bool activeOnly) override; ///< Return a pointer to a liveCellRef with the given name. /// \param activeOnly do non search inactive cells. - virtual Ptr searchPtr (const std::string& name, bool activeOnly); + virtual Ptr searchPtr (const std::string& name, bool activeOnly) override; ///< Return a pointer to a liveCellRef with the given name. /// \param activeOnly do non search inactive cells. - virtual Ptr searchPtrViaActorId (int actorId); + virtual Ptr searchPtrViaActorId (int actorId) override; ///< Search is limited to the active cells. - virtual MWWorld::Ptr findContainer (const MWWorld::ConstPtr& ptr); + virtual MWWorld::Ptr findContainer (const MWWorld::ConstPtr& ptr) override; ///< Return a pointer to a liveCellRef which contains \a ptr. /// \note Search is limited to the active cells. - virtual void adjustPosition (const Ptr& ptr, bool force); + virtual void adjustPosition (const Ptr& ptr, bool force) override; ///< Adjust position after load to be on ground. Must be called after model load. /// @param force do this even if the ptr is flying - virtual void fixPosition (const Ptr& actor); + virtual void fixPosition (const Ptr& actor) override; ///< Attempt to fix position so that the Ptr is no longer inside collision geometry. - virtual void enable (const Ptr& ptr); + virtual void enable (const Ptr& ptr) override; - virtual void disable (const Ptr& ptr); + virtual void disable (const Ptr& ptr) override; - virtual void advanceTime (double hours, bool incremental = false); + virtual void advanceTime (double hours, bool incremental = false) override; ///< Advance in-game time. - virtual void setHour (double hour); + virtual void setHour (double hour) override; ///< Set in-game time hour. - virtual void setMonth (int month); + virtual void setMonth (int month) override; ///< Set in-game time month. - virtual void setDay (int day); + virtual void setDay (int day) override; ///< Set in-game time day. - virtual int getDay() const; - virtual int getMonth() const; - virtual int getYear() const; + virtual int getDay() const override; + virtual int getMonth() const override; + virtual int getYear() const override; - virtual std::string getMonthName (int month = -1) const; + virtual std::string getMonthName (int month = -1) const override; ///< Return name of month (-1: current month) - virtual TimeStamp getTimeStamp() const; + virtual TimeStamp getTimeStamp() const override; ///< Return current in-game time stamp. - virtual bool toggleSky(); + virtual bool toggleSky() override; ///< \return Resulting mode - virtual void changeWeather (const std::string& region, const unsigned int id); + virtual void changeWeather (const std::string& region, const unsigned int id) override; - virtual int getCurrentWeather() const; + virtual int getCurrentWeather() const override; - virtual int getMasserPhase() const; + virtual int getMasserPhase() const override; - virtual int getSecundaPhase() const; + virtual int getSecundaPhase() const override; - virtual void setMoonColour (bool red); + virtual void setMoonColour (bool red) override; - virtual void modRegion(const std::string ®ionid, const std::vector &chances); + virtual void modRegion(const std::string ®ionid, const std::vector &chances) override; - virtual float getTimeScaleFactor() const; + virtual float getTimeScaleFactor() const override; - virtual void changeToInteriorCell (const std::string& cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true); + virtual void changeToInteriorCell (const std::string& cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) override; ///< Move to interior cell. ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - virtual void changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true); + virtual void changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) override; ///< Move to exterior cell. ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent=true); + virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent=true) override; ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - virtual const ESM::Cell *getExterior (const std::string& cellName) const; + virtual const ESM::Cell *getExterior (const std::string& cellName) const override; ///< Return a cell matching the given name or a 0-pointer, if there is no such cell. - virtual void markCellAsUnchanged(); + virtual void markCellAsUnchanged() override; - virtual MWWorld::Ptr getFacedObject(); + virtual MWWorld::Ptr getFacedObject() override; ///< Return pointer to the object the player is looking at, if it is within activation range - virtual float getDistanceToFacedObject(); + virtual float getDistanceToFacedObject() override; /// 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 as a basis. - virtual std::pair getHitContact(const MWWorld::ConstPtr &ptr, float distance, std::vector &targets); + virtual std::pair getHitContact(const MWWorld::ConstPtr &ptr, float distance, std::vector &targets) override; /// @note No-op for items in containers. Use ContainerStore::removeItem instead. - virtual void deleteObject (const Ptr& ptr); + virtual void deleteObject (const Ptr& ptr) override; - virtual void undeleteObject (const Ptr& ptr); + virtual void undeleteObject (const Ptr& ptr) override; - virtual MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z); + virtual MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z) override; ///< @return an updated Ptr in case the Ptr's cell changes - virtual MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z, bool movePhysics=true); + virtual MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z, bool movePhysics=true) override; ///< @return an updated Ptr - virtual void scaleObject (const Ptr& ptr, float scale); + virtual void scaleObject (const Ptr& ptr, float scale) override; /// World rotates object, uses radians /// @note Rotations via this method use a different rotation order than the initial rotations in the CS. This /// could be considered a bug, but is needed for MW compatibility. /// \param adjust indicates rotation should be set or adjusted - virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); + virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false) override; - virtual MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos); + virtual MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) override; ///< Place an object. Makes a copy of the Ptr. - virtual MWWorld::Ptr safePlaceObject (const MWWorld::ConstPtr& ptr, const MWWorld::ConstPtr& referenceObject, MWWorld::CellStore* referenceCell, int direction, float distance); + virtual MWWorld::Ptr safePlaceObject (const MWWorld::ConstPtr& ptr, const MWWorld::ConstPtr& referenceObject, MWWorld::CellStore* referenceCell, int direction, float distance) override; ///< Place an object in a safe place next to \a referenceObject. \a direction and \a distance specify the wanted placement /// relative to \a referenceObject (but the object may be placed somewhere else if the wanted location is obstructed). - virtual float getMaxActivationDistance(); + virtual float getMaxActivationDistance() override; virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) - const; + const override; ///< Convert cell numbers to position. - virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const; + virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const override; ///< Convert position to cell numbers - virtual void queueMovement(const Ptr &ptr, const osg::Vec3f &velocity); + virtual void queueMovement(const Ptr &ptr, const osg::Vec3f &velocity) override; ///< Queues movement for \a ptr (in local space), to be applied in the next call to /// doPhysics. - virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2); + virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) override; ///< cast a Ray and return true if there is an object in the ray path. - virtual bool toggleCollisionMode(); + virtual bool toggleCollisionMode() override; ///< Toggle collision mode for player. If disabled player object should ignore /// collisions and gravity. ///< \return Resulting mode - virtual bool toggleRenderMode (MWRender::RenderMode mode); + virtual bool toggleRenderMode (MWRender::RenderMode mode) override; ///< Toggle a render mode. ///< \return Resulting mode - virtual const ESM::Potion *createRecord (const ESM::Potion& record); + virtual const ESM::Potion *createRecord (const ESM::Potion& record) override; ///< Create a new record (of type potion) in the ESM store. /// \return pointer to created record - virtual const ESM::Spell *createRecord (const ESM::Spell& record); + virtual const ESM::Spell *createRecord (const ESM::Spell& record) override; ///< Create a new record (of type spell) in the ESM store. /// \return pointer to created record - virtual const ESM::Class *createRecord (const ESM::Class& record); + virtual const ESM::Class *createRecord (const ESM::Class& record) override; ///< Create a new record (of type class) in the ESM store. /// \return pointer to created record - virtual const ESM::Cell *createRecord (const ESM::Cell& record); + virtual const ESM::Cell *createRecord (const ESM::Cell& record) override; ///< Create a new record (of type cell) in the ESM store. /// \return pointer to created record - virtual const ESM::NPC *createRecord(const ESM::NPC &record); + virtual const ESM::NPC *createRecord(const ESM::NPC &record) override; ///< Create a new record (of type npc) in the ESM store. /// \return pointer to created record - virtual const ESM::Armor *createRecord (const ESM::Armor& record); + virtual const ESM::Armor *createRecord (const ESM::Armor& record) override; ///< Create a new record (of type armor) in the ESM store. /// \return pointer to created record - virtual const ESM::Weapon *createRecord (const ESM::Weapon& record); + virtual const ESM::Weapon *createRecord (const ESM::Weapon& record) override; ///< Create a new record (of type weapon) in the ESM store. /// \return pointer to created record - virtual const ESM::Clothing *createRecord (const ESM::Clothing& record); + virtual const ESM::Clothing *createRecord (const ESM::Clothing& record) override; ///< Create a new record (of type clothing) in the ESM store. /// \return pointer to created record - virtual const ESM::Enchantment *createRecord (const ESM::Enchantment& record); + virtual const ESM::Enchantment *createRecord (const ESM::Enchantment& record) override; ///< Create a new record (of type enchantment) in the ESM store. /// \return pointer to created record - virtual const ESM::Book *createRecord (const ESM::Book& record); + virtual const ESM::Book *createRecord (const ESM::Book& record) override; ///< Create a new record (of type book) in the ESM store. /// \return pointer to created record - virtual const ESM::CreatureLevList *createOverrideRecord (const ESM::CreatureLevList& record); + virtual const ESM::CreatureLevList *createOverrideRecord (const ESM::CreatureLevList& record) override; ///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID. /// \return pointer to created record - virtual const ESM::ItemLevList *createOverrideRecord (const ESM::ItemLevList& record); + virtual const ESM::ItemLevList *createOverrideRecord (const ESM::ItemLevList& record) override; ///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID. /// \return pointer to created record - virtual void update (float duration, bool paused); + virtual void update (float duration, bool paused) override; - virtual void updateWindowManager (); + virtual void updateWindowManager () override; - virtual MWWorld::Ptr placeObject (const MWWorld::ConstPtr& object, float cursorX, float cursorY, int amount); + virtual MWWorld::Ptr placeObject (const MWWorld::ConstPtr& object, float cursorX, float cursorY, int amount) override; ///< copy and place an object into the gameworld at the specified cursor position /// @param object /// @param cursor X (relative 0-1) /// @param cursor Y (relative 0-1) /// @param number of objects to place - virtual MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object, int amount); + virtual MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object, int amount) override; ///< copy and place an object into the gameworld at the given actor's position /// @param actor giving the dropped object position /// @param object /// @param number of objects to place - virtual bool canPlaceObject(float cursorX, float cursorY); + virtual bool canPlaceObject(float cursorX, float cursorY) override; ///< @return true if it is possible to place on object at specified cursor location - virtual void processChangedSettings(const Settings::CategorySettingVector& settings); + virtual void processChangedSettings(const Settings::CategorySettingVector& settings) override; - virtual bool isFlying(const MWWorld::Ptr &ptr) const; - virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const; + virtual bool isFlying(const MWWorld::Ptr &ptr) const override; + virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const override; ///Is the head of the creature underwater? - virtual bool isSubmerged(const MWWorld::ConstPtr &object) const; - virtual bool isSwimming(const MWWorld::ConstPtr &object) const; - virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const; - virtual bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const; - virtual bool isWading(const MWWorld::ConstPtr &object) const; - virtual bool isWaterWalkingCastableOnTarget(const MWWorld::ConstPtr &target) const; - virtual bool isOnGround(const MWWorld::Ptr &ptr) const; + virtual bool isSubmerged(const MWWorld::ConstPtr &object) const override; + virtual bool isSwimming(const MWWorld::ConstPtr &object) const override; + virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const override; + virtual bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const override; + virtual bool isWading(const MWWorld::ConstPtr &object) const override; + virtual bool isWaterWalkingCastableOnTarget(const MWWorld::ConstPtr &target) const override; + virtual bool isOnGround(const MWWorld::Ptr &ptr) const override; - virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const; + virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const override; - virtual void togglePOV(); + virtual void togglePOV() override; - virtual bool isFirstPerson() const; + virtual bool isFirstPerson() const override; - virtual void togglePreviewMode(bool enable); + virtual void togglePreviewMode(bool enable) override; - virtual bool toggleVanityMode(bool enable); + virtual bool toggleVanityMode(bool enable) override; - virtual void allowVanityMode(bool allow); + virtual void allowVanityMode(bool allow) override; - virtual void togglePlayerLooking(bool enable); + virtual void togglePlayerLooking(bool enable) override; - virtual void changeVanityModeScale(float factor); + virtual void changeVanityModeScale(float factor) override; - virtual bool vanityRotateCamera(float * rot); - virtual void setCameraDistance(float dist, bool adjust = false, bool override = true); + virtual bool vanityRotateCamera(float * rot) override; + virtual void setCameraDistance(float dist, bool adjust = false, bool override = true) override; - virtual void setupPlayer(); - virtual void renderPlayer(); + virtual void setupPlayer() override; + virtual void renderPlayer() override; /// open or close a non-teleport door (depending on current state) - virtual void activateDoor(const MWWorld::Ptr& door); + virtual void activateDoor(const MWWorld::Ptr& door) override; /// update movement state of a non-teleport door as specified /// @param state see MWClass::setDoorState /// @note throws an exception when invoked on a teleport door - virtual void activateDoor(const MWWorld::Ptr& door, int state); + virtual void activateDoor(const MWWorld::Ptr& door, int state) override; - virtual bool getPlayerStandingOn (const MWWorld::ConstPtr& object); ///< @return true if the player is standing on \a object - virtual bool getActorStandingOn (const MWWorld::ConstPtr& object); ///< @return true if any actor is standing on \a object - virtual bool getPlayerCollidingWith(const MWWorld::ConstPtr& object); ///< @return true if the player is colliding with \a object - virtual bool getActorCollidingWith (const MWWorld::ConstPtr& object); ///< @return true if any actor is colliding with \a object - virtual void hurtStandingActors (const MWWorld::ConstPtr& object, float dmgPerSecond); + virtual bool getPlayerStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if the player is standing on \a object + virtual bool getActorStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if any actor is standing on \a object + virtual bool getPlayerCollidingWith(const MWWorld::ConstPtr& object) override; ///< @return true if the player is colliding with \a object + virtual bool getActorCollidingWith (const MWWorld::ConstPtr& object) override; ///< @return true if any actor is colliding with \a object + virtual void hurtStandingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; ///< Apply a health difference to any actors standing on \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. - virtual void hurtCollidingActors (const MWWorld::ConstPtr& object, float dmgPerSecond); + virtual void hurtCollidingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; ///< Apply a health difference to any actors colliding with \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. - virtual float getWindSpeed(); + virtual float getWindSpeed() override; - virtual void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out); + virtual void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; ///< get all containers in active cells owned by this Npc - virtual void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out); + virtual void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; ///< get all items in active cells owned by this Npc - virtual bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor); + virtual bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor) override; ///< get Line of Sight (morrowind stupid implementation) - virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist, bool includeWater = false); + virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist, bool includeWater = false) override; - virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable); + virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) override; - virtual int canRest(); + virtual int canRest() override; ///< check if the player is allowed to rest \n /// 0 - yes \n /// 1 - only waiting \n @@ -554,132 +554,132 @@ namespace MWWorld /// 3 - enemies are nearby (not implemented) /// \todo Probably shouldn't be here - virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr); - virtual const MWRender::Animation* getAnimation(const MWWorld::ConstPtr &ptr) const; - virtual void reattachPlayerCamera(); + virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) override; + virtual const MWRender::Animation* getAnimation(const MWWorld::ConstPtr &ptr) const override; + virtual void reattachPlayerCamera() override; /// \todo this does not belong here - virtual void screenshot (osg::Image* image, int w, int h); + virtual void screenshot (osg::Image* image, int w, int h) override; /// Find center of exterior cell above land surface /// \return false if exterior with given name not exists, true otherwise - virtual bool findExteriorPosition(const std::string &name, ESM::Position &pos); + virtual bool findExteriorPosition(const std::string &name, ESM::Position &pos) override; /// Find position in interior cell near door entrance /// \return false if interior with given name not exists, true otherwise - virtual bool findInteriorPosition(const std::string &name, ESM::Position &pos); + virtual bool findInteriorPosition(const std::string &name, ESM::Position &pos) override; /// Enables or disables use of teleport spell effects (recall, intervention, etc). - virtual void enableTeleporting(bool enable); + virtual void enableTeleporting(bool enable) override; /// Returns true if teleport spell effects are allowed. - virtual bool isTeleportingEnabled() const; + virtual bool isTeleportingEnabled() const override; /// Enables or disables use of levitation spell effect. - virtual void enableLevitation(bool enable); + virtual void enableLevitation(bool enable) override; /// Returns true if levitation spell effect is allowed. - virtual bool isLevitationEnabled() const; + virtual bool isLevitationEnabled() const override; - virtual bool getGodModeState(); + virtual bool getGodModeState() override; - virtual bool toggleGodMode(); + virtual bool toggleGodMode() override; - virtual bool toggleScripts(); - virtual bool getScriptsEnabled() const; + virtual bool toggleScripts() override; + virtual bool getScriptsEnabled() const override; /** * @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met. * @param actor * @return true if the spell can be casted (i.e. the animation should start) */ - virtual bool startSpellCast (const MWWorld::Ptr& actor); + virtual bool startSpellCast (const MWWorld::Ptr& actor) override; /** * @brief Cast the actual spell, should be called mid-animation * @param actor */ - virtual void castSpell (const MWWorld::Ptr& actor); + virtual void castSpell (const MWWorld::Ptr& actor) override; virtual void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) override; virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, - const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength); + const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) override; - virtual const std::vector& getContentFiles() const; + virtual const std::vector& getContentFiles() const override; - virtual void breakInvisibility (const MWWorld::Ptr& actor); + virtual void breakInvisibility (const MWWorld::Ptr& actor) override; // Are we in an exterior or pseudo-exterior cell and it's night? - virtual bool isDark() const; + virtual bool isDark() const override; - virtual bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result); + virtual bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) override; /// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) /// @note id must be lower case virtual void teleportToClosestMarker (const MWWorld::Ptr& ptr, - const std::string& id); + const std::string& id) override; /// List all references (filtered by \a type) detected by \a ptr. The range /// is determined by the current magnitude of the "Detect X" magic effect belonging to \a type. /// @note This also works for references in containers. virtual void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector& out, - DetectionType type); + DetectionType type) override; /// Update the value of some globals according to the world state, which may be used by dialogue entries. /// This should be called when initiating a dialogue. - virtual void updateDialogueGlobals(); + virtual void updateDialogueGlobals() override; /// Moves all stolen items from \a ptr to the closest evidence chest. - virtual void confiscateStolenItems(const MWWorld::Ptr& ptr); + virtual void confiscateStolenItems(const MWWorld::Ptr& ptr) override; - virtual void goToJail (); + virtual void goToJail () override; /// Spawn a random creature from a levelled list next to the player - virtual void spawnRandomCreature(const std::string& creatureList); + virtual void spawnRandomCreature(const std::string& creatureList) override; /// Spawn a blood effect for \a ptr at \a worldPosition - virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition); + virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) override; - virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos); + virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) override; virtual void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName, - const bool fromProjectile=false); + const bool fromProjectile=false) override; - virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor); + virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override; /// @see MWWorld::WeatherManager::isInStorm - virtual bool isInStorm() const; + virtual bool isInStorm() const override; /// @see MWWorld::WeatherManager::getStormDirection - virtual osg::Vec3f getStormDirection() const; + virtual osg::Vec3f getStormDirection() const override; /// Resets all actors in the current active cells to their original location within that cell. - virtual void resetActors(); + virtual void resetActors() override; - virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const; + virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const override; /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. - virtual osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target); + virtual osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; /// Return the distance between actor's weapon and target's collision box. - virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target); + virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; - virtual bool isPlayerInJail() const; + virtual bool isPlayerInJail() const override; /// Return terrain height at \a worldPos position. - virtual float getTerrainHeightAt(const osg::Vec3f& worldPos) const; + virtual float getTerrainHeightAt(const osg::Vec3f& worldPos) const override; /// Return physical or rendering half extents of the given actor. - virtual osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const; + virtual osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const override; /// Export scene graph to a file and return the filename. /// \param ptr object to export scene graph for (if empty, export entire scene graph) - virtual std::string exportSceneGraph(const MWWorld::Ptr& ptr); + virtual std::string exportSceneGraph(const MWWorld::Ptr& ptr) override; /// Preload VFX associated with this effect list - virtual void preloadEffects(const ESM::EffectList* effectList); + virtual void preloadEffects(const ESM::EffectList* effectList) override; }; } From 69da89be3994c6d825bc4d62e399e93b48350465 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 18 Oct 2017 13:05:04 +0100 Subject: [PATCH 329/505] Mark a method I missed out the first time as override --- apps/openmw/mwworld/worldimp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index c130c9d5b..83b81d22c 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -227,7 +227,7 @@ namespace MWWorld virtual const MWWorld::ESMStore& getStore() const override; - virtual std::vector& getEsmReader(); + virtual std::vector& getEsmReader() override; virtual LocalScripts& getLocalScripts() override; From 7440cf37bc96556771f5cf21fc591e8cc9d2505b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 18 Oct 2017 13:37:37 +0100 Subject: [PATCH 330/505] Remove redundant virtual keywords implied by override keywords --- apps/openmw/mwworld/worldimp.hpp | 354 +++++++++++++++---------------- 1 file changed, 177 insertions(+), 177 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 83b81d22c..784c01593 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -191,362 +191,362 @@ namespace MWWorld virtual ~World(); - virtual void startNewGame (bool bypass) override; + void startNewGame (bool bypass) override; ///< \param bypass Bypass regular game start. - virtual void clear() override; + void clear() override; - virtual int countSavedGameRecords() const override; - virtual int countSavedGameCells() const override; + int countSavedGameRecords() const override; + int countSavedGameCells() const override; - virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const override; + void write (ESM::ESMWriter& writer, Loading::Listener& progress) const override; - virtual void readRecord (ESM::ESMReader& reader, uint32_t type, + void readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) override; - virtual CellStore *getExterior (int x, int y) override; + CellStore *getExterior (int x, int y) override; - virtual CellStore *getInterior (const std::string& name) override; + CellStore *getInterior (const std::string& name) override; - virtual CellStore *getCell (const ESM::CellId& id) override; + CellStore *getCell (const ESM::CellId& id) override; //switch to POV before showing player's death animation - virtual void useDeathCamera() override; + void useDeathCamera() override; - virtual void setWaterHeight(const float height) override; + void setWaterHeight(const float height) override; - virtual bool toggleWater() override; - virtual bool toggleWorld() override; + bool toggleWater() override; + bool toggleWorld() override; - virtual void adjustSky() override; + void adjustSky() override; - virtual const Fallback::Map *getFallback() const override; + const Fallback::Map *getFallback() const override; - virtual Player& getPlayer() override; - virtual MWWorld::Ptr getPlayerPtr() override; + Player& getPlayer() override; + MWWorld::Ptr getPlayerPtr() override; - virtual const MWWorld::ESMStore& getStore() const override; + const MWWorld::ESMStore& getStore() const override; - virtual std::vector& getEsmReader() override; + std::vector& getEsmReader() override; - virtual LocalScripts& getLocalScripts() override; + LocalScripts& getLocalScripts() override; - virtual bool hasCellChanged() const override; + bool hasCellChanged() const override; ///< Has the set of active cells changed, since the last frame? - virtual bool isCellExterior() const override; + bool isCellExterior() const override; - virtual bool isCellQuasiExterior() const override; + bool isCellQuasiExterior() const override; - virtual osg::Vec2f getNorthVector (const CellStore* cell) override; + osg::Vec2f getNorthVector (const CellStore* cell) override; ///< get north vector for given interior cell - virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out) override; + void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out) override; ///< get a list of teleport door markers for a given cell, to be displayed on the local map - virtual void setGlobalInt (const std::string& name, int value) override; + void setGlobalInt (const std::string& name, int value) override; ///< Set value independently from real type. - virtual void setGlobalFloat (const std::string& name, float value) override; + void setGlobalFloat (const std::string& name, float value) override; ///< Set value independently from real type. - virtual int getGlobalInt (const std::string& name) const override; + int getGlobalInt (const std::string& name) const override; ///< Get value independently from real type. - virtual float getGlobalFloat (const std::string& name) const override; + float getGlobalFloat (const std::string& name) const override; ///< Get value independently from real type. - virtual char getGlobalVariableType (const std::string& name) const override; + char getGlobalVariableType (const std::string& name) const override; ///< Return ' ', if there is no global variable with this name. - virtual std::string getCellName (const MWWorld::CellStore *cell = 0) const override; + std::string getCellName (const MWWorld::CellStore *cell = 0) const override; ///< Return name of the cell. /// /// \note If cell==0, the cell the player is currently in will be used instead to /// generate a name. - virtual void removeRefScript (MWWorld::RefData *ref) override; + void removeRefScript (MWWorld::RefData *ref) override; //< Remove the script attached to ref from mLocalScripts - virtual Ptr getPtr (const std::string& name, bool activeOnly) override; + Ptr getPtr (const std::string& name, bool activeOnly) override; ///< Return a pointer to a liveCellRef with the given name. /// \param activeOnly do non search inactive cells. - virtual Ptr searchPtr (const std::string& name, bool activeOnly) override; + Ptr searchPtr (const std::string& name, bool activeOnly) override; ///< Return a pointer to a liveCellRef with the given name. /// \param activeOnly do non search inactive cells. - virtual Ptr searchPtrViaActorId (int actorId) override; + Ptr searchPtrViaActorId (int actorId) override; ///< Search is limited to the active cells. - virtual MWWorld::Ptr findContainer (const MWWorld::ConstPtr& ptr) override; + MWWorld::Ptr findContainer (const MWWorld::ConstPtr& ptr) override; ///< Return a pointer to a liveCellRef which contains \a ptr. /// \note Search is limited to the active cells. - virtual void adjustPosition (const Ptr& ptr, bool force) override; + void adjustPosition (const Ptr& ptr, bool force) override; ///< Adjust position after load to be on ground. Must be called after model load. /// @param force do this even if the ptr is flying - virtual void fixPosition (const Ptr& actor) override; + void fixPosition (const Ptr& actor) override; ///< Attempt to fix position so that the Ptr is no longer inside collision geometry. - virtual void enable (const Ptr& ptr) override; + void enable (const Ptr& ptr) override; - virtual void disable (const Ptr& ptr) override; + void disable (const Ptr& ptr) override; - virtual void advanceTime (double hours, bool incremental = false) override; + void advanceTime (double hours, bool incremental = false) override; ///< Advance in-game time. - virtual void setHour (double hour) override; + void setHour (double hour) override; ///< Set in-game time hour. - virtual void setMonth (int month) override; + void setMonth (int month) override; ///< Set in-game time month. - virtual void setDay (int day) override; + void setDay (int day) override; ///< Set in-game time day. - virtual int getDay() const override; - virtual int getMonth() const override; - virtual int getYear() const override; + int getDay() const override; + int getMonth() const override; + int getYear() const override; - virtual std::string getMonthName (int month = -1) const override; + std::string getMonthName (int month = -1) const override; ///< Return name of month (-1: current month) - virtual TimeStamp getTimeStamp() const override; + TimeStamp getTimeStamp() const override; ///< Return current in-game time stamp. - virtual bool toggleSky() override; + bool toggleSky() override; ///< \return Resulting mode - virtual void changeWeather (const std::string& region, const unsigned int id) override; + void changeWeather (const std::string& region, const unsigned int id) override; - virtual int getCurrentWeather() const override; + int getCurrentWeather() const override; - virtual int getMasserPhase() const override; + int getMasserPhase() const override; - virtual int getSecundaPhase() const override; + int getSecundaPhase() const override; - virtual void setMoonColour (bool red) override; + void setMoonColour (bool red) override; - virtual void modRegion(const std::string ®ionid, const std::vector &chances) override; + void modRegion(const std::string ®ionid, const std::vector &chances) override; - virtual float getTimeScaleFactor() const override; + float getTimeScaleFactor() const override; - virtual void changeToInteriorCell (const std::string& cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) override; + void changeToInteriorCell (const std::string& cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) override; ///< Move to interior cell. ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - virtual void changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) override; + void changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) override; ///< Move to exterior cell. ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent=true) override; + void changeToCell (const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent=true) override; ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - virtual const ESM::Cell *getExterior (const std::string& cellName) const override; + const ESM::Cell *getExterior (const std::string& cellName) const override; ///< Return a cell matching the given name or a 0-pointer, if there is no such cell. - virtual void markCellAsUnchanged() override; + void markCellAsUnchanged() override; - virtual MWWorld::Ptr getFacedObject() override; + MWWorld::Ptr getFacedObject() override; ///< Return pointer to the object the player is looking at, if it is within activation range - virtual float getDistanceToFacedObject() override; + float getDistanceToFacedObject() override; /// 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 as a basis. - virtual std::pair getHitContact(const MWWorld::ConstPtr &ptr, float distance, std::vector &targets) override; + std::pair getHitContact(const MWWorld::ConstPtr &ptr, float distance, std::vector &targets) override; /// @note No-op for items in containers. Use ContainerStore::removeItem instead. - virtual void deleteObject (const Ptr& ptr) override; + void deleteObject (const Ptr& ptr) override; - virtual void undeleteObject (const Ptr& ptr) override; + void undeleteObject (const Ptr& ptr) override; - virtual MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z) override; + MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z) override; ///< @return an updated Ptr in case the Ptr's cell changes - virtual MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z, bool movePhysics=true) override; + MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z, bool movePhysics=true) override; ///< @return an updated Ptr - virtual void scaleObject (const Ptr& ptr, float scale) override; + void scaleObject (const Ptr& ptr, float scale) override; /// World rotates object, uses radians /// @note Rotations via this method use a different rotation order than the initial rotations in the CS. This /// could be considered a bug, but is needed for MW compatibility. /// \param adjust indicates rotation should be set or adjusted - virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false) override; + void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false) override; - virtual MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) override; + MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) override; ///< Place an object. Makes a copy of the Ptr. - virtual MWWorld::Ptr safePlaceObject (const MWWorld::ConstPtr& ptr, const MWWorld::ConstPtr& referenceObject, MWWorld::CellStore* referenceCell, int direction, float distance) override; + MWWorld::Ptr safePlaceObject (const MWWorld::ConstPtr& ptr, const MWWorld::ConstPtr& referenceObject, MWWorld::CellStore* referenceCell, int direction, float distance) override; ///< Place an object in a safe place next to \a referenceObject. \a direction and \a distance specify the wanted placement /// relative to \a referenceObject (but the object may be placed somewhere else if the wanted location is obstructed). - virtual float getMaxActivationDistance() override; + float getMaxActivationDistance() override; - virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) + void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) const override; ///< Convert cell numbers to position. - virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const override; + void positionToIndex (float x, float y, int &cellX, int &cellY) const override; ///< Convert position to cell numbers - virtual void queueMovement(const Ptr &ptr, const osg::Vec3f &velocity) override; + void queueMovement(const Ptr &ptr, const osg::Vec3f &velocity) override; ///< Queues movement for \a ptr (in local space), to be applied in the next call to /// doPhysics. - virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) override; + bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) override; ///< cast a Ray and return true if there is an object in the ray path. - virtual bool toggleCollisionMode() override; + bool toggleCollisionMode() override; ///< Toggle collision mode for player. If disabled player object should ignore /// collisions and gravity. ///< \return Resulting mode - virtual bool toggleRenderMode (MWRender::RenderMode mode) override; + bool toggleRenderMode (MWRender::RenderMode mode) override; ///< Toggle a render mode. ///< \return Resulting mode - virtual const ESM::Potion *createRecord (const ESM::Potion& record) override; + const ESM::Potion *createRecord (const ESM::Potion& record) override; ///< Create a new record (of type potion) in the ESM store. /// \return pointer to created record - virtual const ESM::Spell *createRecord (const ESM::Spell& record) override; + const ESM::Spell *createRecord (const ESM::Spell& record) override; ///< Create a new record (of type spell) in the ESM store. /// \return pointer to created record - virtual const ESM::Class *createRecord (const ESM::Class& record) override; + const ESM::Class *createRecord (const ESM::Class& record) override; ///< Create a new record (of type class) in the ESM store. /// \return pointer to created record - virtual const ESM::Cell *createRecord (const ESM::Cell& record) override; + const ESM::Cell *createRecord (const ESM::Cell& record) override; ///< Create a new record (of type cell) in the ESM store. /// \return pointer to created record - virtual const ESM::NPC *createRecord(const ESM::NPC &record) override; + const ESM::NPC *createRecord(const ESM::NPC &record) override; ///< Create a new record (of type npc) in the ESM store. /// \return pointer to created record - virtual const ESM::Armor *createRecord (const ESM::Armor& record) override; + const ESM::Armor *createRecord (const ESM::Armor& record) override; ///< Create a new record (of type armor) in the ESM store. /// \return pointer to created record - virtual const ESM::Weapon *createRecord (const ESM::Weapon& record) override; + const ESM::Weapon *createRecord (const ESM::Weapon& record) override; ///< Create a new record (of type weapon) in the ESM store. /// \return pointer to created record - virtual const ESM::Clothing *createRecord (const ESM::Clothing& record) override; + const ESM::Clothing *createRecord (const ESM::Clothing& record) override; ///< Create a new record (of type clothing) in the ESM store. /// \return pointer to created record - virtual const ESM::Enchantment *createRecord (const ESM::Enchantment& record) override; + const ESM::Enchantment *createRecord (const ESM::Enchantment& record) override; ///< Create a new record (of type enchantment) in the ESM store. /// \return pointer to created record - virtual const ESM::Book *createRecord (const ESM::Book& record) override; + const ESM::Book *createRecord (const ESM::Book& record) override; ///< Create a new record (of type book) in the ESM store. /// \return pointer to created record - virtual const ESM::CreatureLevList *createOverrideRecord (const ESM::CreatureLevList& record) override; + const ESM::CreatureLevList *createOverrideRecord (const ESM::CreatureLevList& record) override; ///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID. /// \return pointer to created record - virtual const ESM::ItemLevList *createOverrideRecord (const ESM::ItemLevList& record) override; + const ESM::ItemLevList *createOverrideRecord (const ESM::ItemLevList& record) override; ///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID. /// \return pointer to created record - virtual void update (float duration, bool paused) override; + void update (float duration, bool paused) override; - virtual void updateWindowManager () override; + void updateWindowManager () override; - virtual MWWorld::Ptr placeObject (const MWWorld::ConstPtr& object, float cursorX, float cursorY, int amount) override; + MWWorld::Ptr placeObject (const MWWorld::ConstPtr& object, float cursorX, float cursorY, int amount) override; ///< copy and place an object into the gameworld at the specified cursor position /// @param object /// @param cursor X (relative 0-1) /// @param cursor Y (relative 0-1) /// @param number of objects to place - virtual MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object, int amount) override; + MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object, int amount) override; ///< copy and place an object into the gameworld at the given actor's position /// @param actor giving the dropped object position /// @param object /// @param number of objects to place - virtual bool canPlaceObject(float cursorX, float cursorY) override; + bool canPlaceObject(float cursorX, float cursorY) override; ///< @return true if it is possible to place on object at specified cursor location - virtual void processChangedSettings(const Settings::CategorySettingVector& settings) override; + void processChangedSettings(const Settings::CategorySettingVector& settings) override; - virtual bool isFlying(const MWWorld::Ptr &ptr) const override; - virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const override; + bool isFlying(const MWWorld::Ptr &ptr) const override; + bool isSlowFalling(const MWWorld::Ptr &ptr) const override; ///Is the head of the creature underwater? - virtual bool isSubmerged(const MWWorld::ConstPtr &object) const override; - virtual bool isSwimming(const MWWorld::ConstPtr &object) const override; - virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const override; - virtual bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const override; - virtual bool isWading(const MWWorld::ConstPtr &object) const override; - virtual bool isWaterWalkingCastableOnTarget(const MWWorld::ConstPtr &target) const override; - virtual bool isOnGround(const MWWorld::Ptr &ptr) const override; + bool isSubmerged(const MWWorld::ConstPtr &object) const override; + bool isSwimming(const MWWorld::ConstPtr &object) const override; + bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const override; + bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const override; + bool isWading(const MWWorld::ConstPtr &object) const override; + bool isWaterWalkingCastableOnTarget(const MWWorld::ConstPtr &target) const override; + bool isOnGround(const MWWorld::Ptr &ptr) const override; - virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const override; + osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const override; - virtual void togglePOV() override; + void togglePOV() override; - virtual bool isFirstPerson() const override; + bool isFirstPerson() const override; - virtual void togglePreviewMode(bool enable) override; + void togglePreviewMode(bool enable) override; - virtual bool toggleVanityMode(bool enable) override; + bool toggleVanityMode(bool enable) override; - virtual void allowVanityMode(bool allow) override; + void allowVanityMode(bool allow) override; - virtual void togglePlayerLooking(bool enable) override; + void togglePlayerLooking(bool enable) override; - virtual void changeVanityModeScale(float factor) override; + void changeVanityModeScale(float factor) override; - virtual bool vanityRotateCamera(float * rot) override; - virtual void setCameraDistance(float dist, bool adjust = false, bool override = true) override; + bool vanityRotateCamera(float * rot) override; + void setCameraDistance(float dist, bool adjust = false, bool override = true) override; - virtual void setupPlayer() override; - virtual void renderPlayer() override; + void setupPlayer() override; + void renderPlayer() override; /// open or close a non-teleport door (depending on current state) - virtual void activateDoor(const MWWorld::Ptr& door) override; + void activateDoor(const MWWorld::Ptr& door) override; /// update movement state of a non-teleport door as specified /// @param state see MWClass::setDoorState /// @note throws an exception when invoked on a teleport door - virtual void activateDoor(const MWWorld::Ptr& door, int state) override; + void activateDoor(const MWWorld::Ptr& door, int state) override; - virtual bool getPlayerStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if the player is standing on \a object - virtual bool getActorStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if any actor is standing on \a object - virtual bool getPlayerCollidingWith(const MWWorld::ConstPtr& object) override; ///< @return true if the player is colliding with \a object - virtual bool getActorCollidingWith (const MWWorld::ConstPtr& object) override; ///< @return true if any actor is colliding with \a object - virtual void hurtStandingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; + bool getPlayerStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if the player is standing on \a object + bool getActorStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if any actor is standing on \a object + bool getPlayerCollidingWith(const MWWorld::ConstPtr& object) override; ///< @return true if the player is colliding with \a object + bool getActorCollidingWith (const MWWorld::ConstPtr& object) override; ///< @return true if any actor is colliding with \a object + void hurtStandingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; ///< Apply a health difference to any actors standing on \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. - virtual void hurtCollidingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; + void hurtCollidingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; ///< Apply a health difference to any actors colliding with \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. - virtual float getWindSpeed() override; + float getWindSpeed() override; - virtual void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; + void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; ///< get all containers in active cells owned by this Npc - virtual void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; + void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; ///< get all items in active cells owned by this Npc - virtual bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor) override; + bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor) override; ///< get Line of Sight (morrowind stupid implementation) - virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist, bool includeWater = false) override; + float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist, bool includeWater = false) override; - virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) override; + void enableActorCollision(const MWWorld::Ptr& actor, bool enable) override; - virtual int canRest() override; + int canRest() override; ///< check if the player is allowed to rest \n /// 0 - yes \n /// 1 - only waiting \n @@ -554,132 +554,132 @@ namespace MWWorld /// 3 - enemies are nearby (not implemented) /// \todo Probably shouldn't be here - virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) override; - virtual const MWRender::Animation* getAnimation(const MWWorld::ConstPtr &ptr) const override; - virtual void reattachPlayerCamera() override; + MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) override; + const MWRender::Animation* getAnimation(const MWWorld::ConstPtr &ptr) const override; + void reattachPlayerCamera() override; /// \todo this does not belong here - virtual void screenshot (osg::Image* image, int w, int h) override; + void screenshot (osg::Image* image, int w, int h) override; /// Find center of exterior cell above land surface /// \return false if exterior with given name not exists, true otherwise - virtual bool findExteriorPosition(const std::string &name, ESM::Position &pos) override; + bool findExteriorPosition(const std::string &name, ESM::Position &pos) override; /// Find position in interior cell near door entrance /// \return false if interior with given name not exists, true otherwise - virtual bool findInteriorPosition(const std::string &name, ESM::Position &pos) override; + bool findInteriorPosition(const std::string &name, ESM::Position &pos) override; /// Enables or disables use of teleport spell effects (recall, intervention, etc). - virtual void enableTeleporting(bool enable) override; + void enableTeleporting(bool enable) override; /// Returns true if teleport spell effects are allowed. - virtual bool isTeleportingEnabled() const override; + bool isTeleportingEnabled() const override; /// Enables or disables use of levitation spell effect. - virtual void enableLevitation(bool enable) override; + void enableLevitation(bool enable) override; /// Returns true if levitation spell effect is allowed. - virtual bool isLevitationEnabled() const override; + bool isLevitationEnabled() const override; - virtual bool getGodModeState() override; + bool getGodModeState() override; - virtual bool toggleGodMode() override; + bool toggleGodMode() override; - virtual bool toggleScripts() override; - virtual bool getScriptsEnabled() const override; + bool toggleScripts() override; + bool getScriptsEnabled() const override; /** * @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met. * @param actor * @return true if the spell can be casted (i.e. the animation should start) */ - virtual bool startSpellCast (const MWWorld::Ptr& actor) override; + bool startSpellCast (const MWWorld::Ptr& actor) override; /** * @brief Cast the actual spell, should be called mid-animation * @param actor */ - virtual void castSpell (const MWWorld::Ptr& actor) override; + void castSpell (const MWWorld::Ptr& actor) override; - virtual void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) override; - virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, + void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) override; + void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) override; - virtual const std::vector& getContentFiles() const override; + const std::vector& getContentFiles() const override; - virtual void breakInvisibility (const MWWorld::Ptr& actor) override; + void breakInvisibility (const MWWorld::Ptr& actor) override; // Are we in an exterior or pseudo-exterior cell and it's night? - virtual bool isDark() const override; + bool isDark() const override; - virtual bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) override; + bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) override; /// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) /// @note id must be lower case - virtual void teleportToClosestMarker (const MWWorld::Ptr& ptr, + void teleportToClosestMarker (const MWWorld::Ptr& ptr, const std::string& id) override; /// List all references (filtered by \a type) detected by \a ptr. The range /// is determined by the current magnitude of the "Detect X" magic effect belonging to \a type. /// @note This also works for references in containers. - virtual void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector& out, + void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector& out, DetectionType type) override; /// Update the value of some globals according to the world state, which may be used by dialogue entries. /// This should be called when initiating a dialogue. - virtual void updateDialogueGlobals() override; + void updateDialogueGlobals() override; /// Moves all stolen items from \a ptr to the closest evidence chest. - virtual void confiscateStolenItems(const MWWorld::Ptr& ptr) override; + void confiscateStolenItems(const MWWorld::Ptr& ptr) override; - virtual void goToJail () override; + void goToJail () override; /// Spawn a random creature from a levelled list next to the player - virtual void spawnRandomCreature(const std::string& creatureList) override; + void spawnRandomCreature(const std::string& creatureList) override; /// Spawn a blood effect for \a ptr at \a worldPosition - virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) override; + void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) override; - virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) override; + void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) override; - virtual void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore, + void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName, const bool fromProjectile=false) override; - virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override; + void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override; /// @see MWWorld::WeatherManager::isInStorm - virtual bool isInStorm() const override; + bool isInStorm() const override; /// @see MWWorld::WeatherManager::getStormDirection - virtual osg::Vec3f getStormDirection() const override; + osg::Vec3f getStormDirection() const override; /// Resets all actors in the current active cells to their original location within that cell. - virtual void resetActors() override; + void resetActors() override; - virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const override; + bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const override; /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. - virtual osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; + osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; /// Return the distance between actor's weapon and target's collision box. - virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; + float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; - virtual bool isPlayerInJail() const override; + bool isPlayerInJail() const override; /// Return terrain height at \a worldPos position. - virtual float getTerrainHeightAt(const osg::Vec3f& worldPos) const override; + float getTerrainHeightAt(const osg::Vec3f& worldPos) const override; /// Return physical or rendering half extents of the given actor. - virtual osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const override; + osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const override; /// Export scene graph to a file and return the filename. /// \param ptr object to export scene graph for (if empty, export entire scene graph) - virtual std::string exportSceneGraph(const MWWorld::Ptr& ptr) override; + std::string exportSceneGraph(const MWWorld::Ptr& ptr) override; /// Preload VFX associated with this effect list - virtual void preloadEffects(const ESM::EffectList* effectList) override; + void preloadEffects(const ESM::EffectList* effectList) override; }; } From 2abff22c08525235d917afc60d79198f4467dfda Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 18 Oct 2017 13:48:31 +0100 Subject: [PATCH 331/505] Make MWWorld::World final to enable compiler optimisations --- apps/openmw/mwworld/worldimp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 784c01593..d7fec2fec 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -69,7 +69,7 @@ namespace MWWorld /// \brief The game world and its visual representation - class World : public MWBase::World + class World final: public MWBase::World { Resource::ResourceSystem* mResourceSystem; From 9571cd8754d88be35623eddeb19dd79c9d5c2173 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 19 Oct 2017 00:50:57 +0100 Subject: [PATCH 332/505] Switch defaultfilters to be handled by a binary-friendly version of the resource macro --- CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bf2896da..b47678e7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -329,8 +329,9 @@ endif () configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg "${OpenMW_BINARY_DIR}" "openmw-cs.cfg") -configure_resource_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters - "${OpenMW_BINARY_DIR}" "resources/defaultfilters" COPYONLY) +# Needs the copy version because the configure version assumes the end of the file has been reached when a null character is reached and there are no CMake expressions to evaluate. +copy_resource_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters + "${OpenMW_BINARY_DIR}" "resources/defaultfilters") configure_resource_file(${OpenMW_SOURCE_DIR}/files/gamecontrollerdb.txt "${OpenMW_BINARY_DIR}" "gamecontrollerdb.txt") From 6d8666d80dc5ac58bd193ea4cf22ebac4034e959 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Wed, 18 Oct 2017 20:21:44 -0400 Subject: [PATCH 333/505] Force new project file when creating new project --- apps/opencs/model/doc/document.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 7257b2fe3..7a825ba39 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -288,7 +288,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, if (mContentFiles.empty()) throw std::runtime_error ("Empty content file sequence"); - if (!boost::filesystem::exists (mProjectPath)) + if (mNew || !boost::filesystem::exists (mProjectPath)) { boost::filesystem::path customFiltersPath (configuration.getUserDataPath()); customFiltersPath /= "defaultfilters"; From d9fe3aac994f97ae9b69bfb97ad1eb86fdf3a4e8 Mon Sep 17 00:00:00 2001 From: Rhiyo Date: Thu, 19 Oct 2017 22:46:08 +1030 Subject: [PATCH 334/505] fixed new clothing replacing old clothing of same value Found on the bug http://bugs.openmw.org/issues/4165. In original Morrowind, new clothing of the same value wouldn't replace old clothing. Tested with common and expensive clothing by selling to merchants and using the AddItem console command in original Morrowind. In OpenMW, before this change, new clothing of the same value would replace old clothing, tested with the same methods used above. --- apps/openmw/mwworld/inventorystore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 50ee97d1c..3d3c8e4ef 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -340,7 +340,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) if (old.getTypeName() == typeid(ESM::Clothing).name()) { // check value - if (old.getClass().getValue (old) > test.getClass().getValue (test)) + if (old.getClass().getValue (old) >= test.getClass().getValue (test)) // old clothing was more valuable continue; } From 43f94a889016a508273bcc43a8c71ef210f8a2b5 Mon Sep 17 00:00:00 2001 From: lukago Date: Thu, 19 Oct 2017 16:50:04 +0200 Subject: [PATCH 335/505] simplify drag and drop on avatar for potions and ingredients --- apps/openmw/mwgui/inventorywindow.cpp | 19 +++++++++++++++---- apps/openmw/mwgui/inventorywindow.hpp | 3 ++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 735bf3682..2f3099c09 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -213,11 +213,13 @@ namespace MWGui void InventoryWindow::onItemSelected (int index) { - onItemSelectedFromSourceModel (mSortModel->mapToSource(index)); + onItemSelectedFromSourceModel (mSortModel->mapToSource(index), false); } - void InventoryWindow::onItemSelectedFromSourceModel (int index) + void InventoryWindow::onItemSelectedFromSourceModel (int index, bool takeMaxItemCount) { + mLastItemIndex = index; + if (mDragAndDrop->mIsOnDragAndDrop) { mDragAndDrop->drop(mTradeModel, mItemView); @@ -230,7 +232,8 @@ namespace MWGui MWWorld::Ptr object = item.mBase; int count = item.mCount; - bool shift = MyGUI::InputManager::getInstance().isShiftPressed(); + bool shift = takeMaxItemCount ? true : MyGUI::InputManager::getInstance().isShiftPressed(); + if (MyGUI::InputManager::getInstance().isControlPressed()) count = 1; @@ -528,6 +531,8 @@ namespace MWGui if (mDragAndDrop->mIsOnDragAndDrop) { MWWorld::Ptr ptr = mDragAndDrop->mItem.mBase; + int itemType = ptr.getContainerStore()->getType(ptr); + mDragAndDrop->finish(); if (mDragAndDrop->mSourceModel != mTradeModel) @@ -536,6 +541,12 @@ namespace MWGui ptr = mDragAndDrop->mSourceModel->moveItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount, mTradeModel); } useItem(ptr); + + if ((itemType == MWWorld::ContainerStore::Type_Ingredient || itemType == MWWorld::ContainerStore::Type_Potion) && mDragAndDrop->mDraggedCount > 1) + { + onItemSelectedFromSourceModel(mLastItemIndex, true); + } + } else { @@ -550,7 +561,7 @@ namespace MWGui { if (mTradeModel->getItem(i).mBase == itemSelected) { - onItemSelectedFromSourceModel(i); + onItemSelectedFromSourceModel(i, false); return; } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 5576b52ed..dde46558f 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -69,6 +69,7 @@ namespace MWGui DragAndDrop* mDragAndDrop; int mSelectedItem; + int mLastItemIndex; MWWorld::Ptr mPtr; @@ -103,7 +104,7 @@ namespace MWGui bool mTrading; void onItemSelected(int index); - void onItemSelectedFromSourceModel(int index); + void onItemSelectedFromSourceModel(int index, bool takeMaxCount); void onBackgroundSelected(); From f3e6b26e6bcda2c0899e3549e62722ac24d8688b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 19 Oct 2017 16:34:11 +0100 Subject: [PATCH 336/505] Tidy up indentation --- apps/openmw/mwworld/worldimp.hpp | 98 ++++++++++++++++---------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index d7fec2fec..5b772b4b1 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -528,25 +528,25 @@ namespace MWWorld void hurtStandingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; ///< Apply a health difference to any actors standing on \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. - void hurtCollidingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; + void hurtCollidingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; ///< Apply a health difference to any actors colliding with \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. - float getWindSpeed() override; + float getWindSpeed() override; - void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; + void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; ///< get all containers in active cells owned by this Npc - void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; + void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; ///< get all items in active cells owned by this Npc - bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor) override; + bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor) override; ///< get Line of Sight (morrowind stupid implementation) - float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist, bool includeWater = false) override; + float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist, bool includeWater = false) override; - void enableActorCollision(const MWWorld::Ptr& actor, bool enable) override; + void enableActorCollision(const MWWorld::Ptr& actor, bool enable) override; - int canRest() override; + int canRest() override; ///< check if the player is allowed to rest \n /// 0 - yes \n /// 1 - only waiting \n @@ -554,132 +554,132 @@ namespace MWWorld /// 3 - enemies are nearby (not implemented) /// \todo Probably shouldn't be here - MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) override; - const MWRender::Animation* getAnimation(const MWWorld::ConstPtr &ptr) const override; - void reattachPlayerCamera() override; + MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) override; + const MWRender::Animation* getAnimation(const MWWorld::ConstPtr &ptr) const override; + void reattachPlayerCamera() override; /// \todo this does not belong here - void screenshot (osg::Image* image, int w, int h) override; + void screenshot (osg::Image* image, int w, int h) override; /// Find center of exterior cell above land surface /// \return false if exterior with given name not exists, true otherwise - bool findExteriorPosition(const std::string &name, ESM::Position &pos) override; + bool findExteriorPosition(const std::string &name, ESM::Position &pos) override; /// Find position in interior cell near door entrance /// \return false if interior with given name not exists, true otherwise - bool findInteriorPosition(const std::string &name, ESM::Position &pos) override; + bool findInteriorPosition(const std::string &name, ESM::Position &pos) override; /// Enables or disables use of teleport spell effects (recall, intervention, etc). - void enableTeleporting(bool enable) override; + void enableTeleporting(bool enable) override; /// Returns true if teleport spell effects are allowed. - bool isTeleportingEnabled() const override; + bool isTeleportingEnabled() const override; /// Enables or disables use of levitation spell effect. - void enableLevitation(bool enable) override; + void enableLevitation(bool enable) override; /// Returns true if levitation spell effect is allowed. - bool isLevitationEnabled() const override; + bool isLevitationEnabled() const override; - bool getGodModeState() override; + bool getGodModeState() override; - bool toggleGodMode() override; + bool toggleGodMode() override; - bool toggleScripts() override; - bool getScriptsEnabled() const override; + bool toggleScripts() override; + bool getScriptsEnabled() const override; /** * @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met. * @param actor * @return true if the spell can be casted (i.e. the animation should start) */ - bool startSpellCast (const MWWorld::Ptr& actor) override; + bool startSpellCast (const MWWorld::Ptr& actor) override; /** * @brief Cast the actual spell, should be called mid-animation * @param actor */ - void castSpell (const MWWorld::Ptr& actor) override; + void castSpell (const MWWorld::Ptr& actor) override; - void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) override; - void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, + void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) override; + void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) override; - const std::vector& getContentFiles() const override; + const std::vector& getContentFiles() const override; - void breakInvisibility (const MWWorld::Ptr& actor) override; + void breakInvisibility (const MWWorld::Ptr& actor) override; // Are we in an exterior or pseudo-exterior cell and it's night? - bool isDark() const override; + bool isDark() const override; - bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) override; + bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) override; /// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) /// @note id must be lower case - void teleportToClosestMarker (const MWWorld::Ptr& ptr, + void teleportToClosestMarker (const MWWorld::Ptr& ptr, const std::string& id) override; /// List all references (filtered by \a type) detected by \a ptr. The range /// is determined by the current magnitude of the "Detect X" magic effect belonging to \a type. /// @note This also works for references in containers. - void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector& out, + void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector& out, DetectionType type) override; /// Update the value of some globals according to the world state, which may be used by dialogue entries. /// This should be called when initiating a dialogue. - void updateDialogueGlobals() override; + void updateDialogueGlobals() override; /// Moves all stolen items from \a ptr to the closest evidence chest. - void confiscateStolenItems(const MWWorld::Ptr& ptr) override; + void confiscateStolenItems(const MWWorld::Ptr& ptr) override; - void goToJail () override; + void goToJail () override; /// Spawn a random creature from a levelled list next to the player void spawnRandomCreature(const std::string& creatureList) override; /// Spawn a blood effect for \a ptr at \a worldPosition - void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) override; + void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) override; - void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) override; + void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) override; - void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore, + void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName, const bool fromProjectile=false) override; - void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override; + void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override; /// @see MWWorld::WeatherManager::isInStorm - bool isInStorm() const override; + bool isInStorm() const override; /// @see MWWorld::WeatherManager::getStormDirection - osg::Vec3f getStormDirection() const override; + osg::Vec3f getStormDirection() const override; /// Resets all actors in the current active cells to their original location within that cell. - void resetActors() override; + void resetActors() override; - bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const override; + bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const override; /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; /// Return the distance between actor's weapon and target's collision box. - float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; + float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; - bool isPlayerInJail() const override; + bool isPlayerInJail() const override; /// Return terrain height at \a worldPos position. - float getTerrainHeightAt(const osg::Vec3f& worldPos) const override; + float getTerrainHeightAt(const osg::Vec3f& worldPos) const override; /// Return physical or rendering half extents of the given actor. - osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const override; + osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const override; /// Export scene graph to a file and return the filename. /// \param ptr object to export scene graph for (if empty, export entire scene graph) - std::string exportSceneGraph(const MWWorld::Ptr& ptr) override; + std::string exportSceneGraph(const MWWorld::Ptr& ptr) override; /// Preload VFX associated with this effect list - void preloadEffects(const ESM::EffectList* effectList) override; + void preloadEffects(const ESM::EffectList* effectList) override; }; } From 03fc3353b9e3d1f9a7ebad673f96841140a77e4f Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 19 Oct 2017 16:34:50 +0100 Subject: [PATCH 337/505] Tidy up indentation 2 --- apps/openmw/mwworld/worldimp.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5b772b4b1..7af7b2968 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -635,7 +635,7 @@ namespace MWWorld void goToJail () override; /// Spawn a random creature from a levelled list next to the player - void spawnRandomCreature(const std::string& creatureList) override; + void spawnRandomCreature(const std::string& creatureList) override; /// Spawn a blood effect for \a ptr at \a worldPosition void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) override; @@ -661,7 +661,7 @@ namespace MWWorld /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. - osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; + osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; /// Return the distance between actor's weapon and target's collision box. float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; From a3225364ff2e689ff43c3f93b3961c91b0b505c0 Mon Sep 17 00:00:00 2001 From: lukago Date: Thu, 19 Oct 2017 17:17:14 +0200 Subject: [PATCH 338/505] refactor, use dragItem method --- apps/openmw/mwgui/inventorywindow.cpp | 22 ++++++++++------------ apps/openmw/mwgui/inventorywindow.hpp | 3 +-- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 2f3099c09..d0af00e5f 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1,7 +1,5 @@ #include "inventorywindow.hpp" -#include - #include #include #include @@ -26,7 +24,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/action.hpp" #include "../mwscript/interpretercontext.hpp" -#include "../mwrender/characterpreview.hpp" #include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -213,13 +210,11 @@ namespace MWGui void InventoryWindow::onItemSelected (int index) { - onItemSelectedFromSourceModel (mSortModel->mapToSource(index), false); + onItemSelectedFromSourceModel (mSortModel->mapToSource(index)); } - void InventoryWindow::onItemSelectedFromSourceModel (int index, bool takeMaxItemCount) + void InventoryWindow::onItemSelectedFromSourceModel (int index) { - mLastItemIndex = index; - if (mDragAndDrop->mIsOnDragAndDrop) { mDragAndDrop->drop(mTradeModel, mItemView); @@ -230,10 +225,9 @@ namespace MWGui std::string sound = item.mBase.getClass().getDownSoundId(item.mBase); MWWorld::Ptr object = item.mBase; + bool shift = MyGUI::InputManager::getInstance().isShiftPressed(); int count = item.mCount; - bool shift = takeMaxItemCount ? true : MyGUI::InputManager::getInstance().isShiftPressed(); - if (MyGUI::InputManager::getInstance().isControlPressed()) count = 1; @@ -540,11 +534,15 @@ namespace MWGui // Move item to the player's inventory ptr = mDragAndDrop->mSourceModel->moveItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount, mTradeModel); } + useItem(ptr); - if ((itemType == MWWorld::ContainerStore::Type_Ingredient || itemType == MWWorld::ContainerStore::Type_Potion) && mDragAndDrop->mDraggedCount > 1) + // If item is ingredient or potion don't stop drag and drop to simplify action of taking more than one 1 item + if ((itemType == MWWorld::ContainerStore::Type_Ingredient + || itemType == MWWorld::ContainerStore::Type_Potion) + && mDragAndDrop->mDraggedCount > 1) { - onItemSelectedFromSourceModel(mLastItemIndex, true); + dragItem (nullptr, mDragAndDrop->mDraggedCount - 1); } } @@ -561,7 +559,7 @@ namespace MWGui { if (mTradeModel->getItem(i).mBase == itemSelected) { - onItemSelectedFromSourceModel(i, false); + onItemSelectedFromSourceModel(i); return; } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index dde46558f..5576b52ed 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -69,7 +69,6 @@ namespace MWGui DragAndDrop* mDragAndDrop; int mSelectedItem; - int mLastItemIndex; MWWorld::Ptr mPtr; @@ -104,7 +103,7 @@ namespace MWGui bool mTrading; void onItemSelected(int index); - void onItemSelectedFromSourceModel(int index, bool takeMaxCount); + void onItemSelectedFromSourceModel(int index); void onBackgroundSelected(); From e64f14b7ce07fabc0b31e7557f0b4003ed2a3df2 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 20 Oct 2017 23:05:12 +0400 Subject: [PATCH 339/505] Do not replace an equpped ring of the same value --- apps/openmw/mwworld/inventorystore.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 3d3c8e4ef..ba3ea2381 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -330,10 +330,8 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) Ptr rightRing = *slots_.at(Slot_RightRing); // we want to swap cheaper ring only if both are equipped - if (rightRing.getClass().getValue(rightRing) < old.getClass().getValue(old)) - { + if (old.getClass().getValue (old) >= rightRing.getClass().getValue (rightRing)) continue; - } } } From eaff7e30aa052f311a7c8e00b85d9aa50004016f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 21 Oct 2017 16:56:21 +0400 Subject: [PATCH 340/505] Fix a 'Good Beast' companion window --- apps/openmw/mwgui/dialogue.cpp | 13 +++++++++---- apps/openmw/mwgui/dialogue.hpp | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index e13e626ae..39c73a23d 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -391,8 +391,8 @@ namespace MWGui // No greetings found. The dialogue window should not be shown. // If this is a companion, we must show the companion window directly (used by BM_bear_be_unique). MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); - if (isCompanion()) - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, mPtr); + if (isCompanion(actor)) + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, actor); return; } @@ -698,8 +698,13 @@ namespace MWGui bool DialogueWindow::isCompanion() { - return !mPtr.getClass().getScript(mPtr).empty() - && mPtr.getRefData().getLocals().getIntVar(mPtr.getClass().getScript(mPtr), "companion"); + return isCompanion(mPtr); + } + + bool DialogueWindow::isCompanion(const MWWorld::Ptr& actor) + { + return !actor.getClass().getScript(actor).empty() + && actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"); } void DialogueWindow::onPersuadeResult(const std::string &title, const std::string &text) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 5e362e9b5..472996a6c 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -133,6 +133,7 @@ namespace MWGui protected: void updateTopics(); void updateTopicsPane(); + bool isCompanion(const MWWorld::Ptr& actor); bool isCompanion(); void onPersuadeResult(const std::string& title, const std::string& text); From b6cb3b445cb5406b3c06d48c54fc1427d426d1bf Mon Sep 17 00:00:00 2001 From: lukago Date: Fri, 20 Oct 2017 01:10:17 +0200 Subject: [PATCH 341/505] use getIndex to handle other windows, nullsafe fixes --- apps/openmw/mwgui/inventorywindow.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index d0af00e5f..b3697008c 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1,5 +1,7 @@ #include "inventorywindow.hpp" +#include + #include #include #include @@ -225,8 +227,8 @@ namespace MWGui std::string sound = item.mBase.getClass().getDownSoundId(item.mBase); MWWorld::Ptr object = item.mBase; - bool shift = MyGUI::InputManager::getInstance().isShiftPressed(); int count = item.mCount; + bool shift = MyGUI::InputManager::getInstance().isShiftPressed(); if (MyGUI::InputManager::getInstance().isControlPressed()) count = 1; @@ -525,7 +527,6 @@ namespace MWGui if (mDragAndDrop->mIsOnDragAndDrop) { MWWorld::Ptr ptr = mDragAndDrop->mItem.mBase; - int itemType = ptr.getContainerStore()->getType(ptr); mDragAndDrop->finish(); @@ -538,13 +539,15 @@ namespace MWGui useItem(ptr); // If item is ingredient or potion don't stop drag and drop to simplify action of taking more than one 1 item - if ((itemType == MWWorld::ContainerStore::Type_Ingredient - || itemType == MWWorld::ContainerStore::Type_Potion) + if ((ptr.getTypeName() == typeid(ESM::Potion).name() || + ptr.getTypeName() == typeid(ESM::Ingredient).name()) && mDragAndDrop->mDraggedCount > 1) { - dragItem (nullptr, mDragAndDrop->mDraggedCount - 1); + // Item can be provided from other window for example container. + // But after DragAndDrop::startDrag item automaticly always gets to player inventory. + mSelectedItem = getModel()->getIndex(mDragAndDrop->mItem); + dragItem(nullptr, mDragAndDrop->mDraggedCount - 1); } - } else { From 46b015d3d93fdc03eddbb8dd725b36e9671adcae Mon Sep 17 00:00:00 2001 From: Marcin Baszczewski Date: Sun, 22 Oct 2017 10:10:04 +0200 Subject: [PATCH 342/505] Fix assert with empty setting value Local value could be empty, so it's important to check it size before read first char. --- components/config/gamesettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 0ea28dceb..b35612ee4 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -63,7 +63,7 @@ void Config::GameSettings::validatePaths() // Do the same for data-local QString local = mSettings.value(QString("data-local")); - if (local.at(0) == QChar('\"')) + if (local.length() && local.at(0) == QChar('\"')) { local.remove(0, 1); local.chop(1); From 768da57da2163af5806efb8206aee4006bb58e96 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 22 Oct 2017 19:06:47 +0200 Subject: [PATCH 343/505] Fix dialogue topics displayed in lower case --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 5 ++--- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 6fac03e92..acfe7f5ee 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -325,8 +325,7 @@ namespace MWDialogue { if (filter.responseAvailable (*iter)) { - std::string lower = Misc::StringUtils::lowerCase(iter->mId); - mActorKnownTopics.insert (lower); + mActorKnownTopics.insert (iter->mId); } } } @@ -342,7 +341,7 @@ namespace MWDialogue for (const std::string& topic : mActorKnownTopics) { //does the player know the topic? - if (mKnownTopics.count(Misc::StringUtils::lowerCase(topic))) + if (mKnownTopics.count(topic)) keywordList.push_back(topic); } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index d9c622120..a914d9a3e 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -8,6 +8,7 @@ #include #include +#include #include "../mwworld/ptr.hpp" @@ -22,13 +23,13 @@ namespace MWDialogue { class DialogueManager : public MWBase::DialogueManager { - std::set mKnownTopics;// Those are the topics the player knows. + std::set mKnownTopics;// Those are the topics the player knows. // Modified faction reactions. > typedef std::map > ModFactionReactionMap; ModFactionReactionMap mChangedFactionReaction; - std::set mActorKnownTopics; + std::set mActorKnownTopics; Translation::Storage& mTranslationDataStorage; MWScript::CompilerContext mCompilerContext; From 3d0094bd2e7cb4e0ee5929f3f1d909c18d4d33ff Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 22 Oct 2017 19:30:55 +0200 Subject: [PATCH 344/505] Fix behavior of 'journal' command when invoked with already seen entry --- apps/openmw/mwdialogue/journalimp.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 27a3b31b5..41eaed080 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -77,11 +77,15 @@ namespace MWDialogue void Journal::addEntry (const std::string& id, int index, const MWWorld::Ptr& actor) { - // bail out of we already have heard this... + // bail out if we already have heard this... std::string infoId = JournalEntry::idFromIndex (id, index); for (TEntryIter i = mJournal.begin (); i != mJournal.end (); ++i) if (i->mTopic == id && i->mInfoId == infoId) + { + setJournalIndex(id, index); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sJournalEntry}"); return; + } StampedJournalEntry entry = StampedJournalEntry::makeFromQuest (id, index, actor); From 32bdd500afde5cfc9c7825ad2b1884896c6978c8 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 22 Oct 2017 23:13:01 +0200 Subject: [PATCH 345/505] Updating OSG packages to 3.4.1 --- CI/before_script.msvc.sh | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index a7f30d7ed..39cb37bed 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -330,9 +330,9 @@ if [ -z $SKIP_DOWNLOAD ]; then "OpenAL-Soft-1.17.2.zip" # OSG - download "OpenSceneGraph 3.4.0-scrawl" \ - "http://www.lysator.liu.se/~ace/OpenMW/deps/OSG-3.4.0-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" \ - "OSG-3.4.0-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" + download "OpenSceneGraph 3.4.1-scrawl" \ + "http://www.lysator.liu.se/~ace/OpenMW/deps/OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" \ + "OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" # Qt if [ -z $APPVEYOR ]; then @@ -527,20 +527,20 @@ cd $DEPS echo # OSG -printf "OSG 3.4.0-scrawl... " +printf "OSG 3.4.1-scrawl... " { cd $DEPS_INSTALL if [ -d OSG ] && \ grep "OPENSCENEGRAPH_MAJOR_VERSION 3" OSG/include/osg/Version > /dev/null && \ grep "OPENSCENEGRAPH_MINOR_VERSION 4" OSG/include/osg/Version > /dev/null && \ - grep "OPENSCENEGRAPH_PATCH_VERSION 0" OSG/include/osg/Version > /dev/null + grep "OPENSCENEGRAPH_PATCH_VERSION 1" OSG/include/osg/Version > /dev/null then printf "Exists. " elif [ -z $SKIP_EXTRACT ]; then rm -rf OSG - eval 7z x -y "${DEPS}/OSG-3.4.0-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP - mv "OSG-3.4.0-scrawl-msvc${MSVC_YEAR}-win${BITS}" OSG + eval 7z x -y "${DEPS}/OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP + mv "OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}" OSG fi OSG_SDK="$(real_pwd)/OSG" @@ -556,8 +556,8 @@ printf "OSG 3.4.0-scrawl... " add_runtime_dlls "$(pwd)/OSG/bin/"{OpenThreads,zlib,libpng*}${SUFFIX}.dll \ "$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer}${SUFFIX}.dll - add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_"{bmp,dds,jpeg,osg,png,tga}${SUFFIX}.dll - add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer}${SUFFIX}.dll + add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_"{bmp,dds,jpeg,osg,png,tga}${SUFFIX}.dll + add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer}${SUFFIX}.dll echo Done. } @@ -717,10 +717,10 @@ if [ -z $CI ]; then echo echo "- OSG Plugin DLLs..." - mkdir -p $BUILD_CONFIG/osgPlugins-3.4.0 + mkdir -p $BUILD_CONFIG/osgPlugins-3.4.1 for DLL in $OSG_PLUGINS; do echo " $(basename $DLL)." - cp "$DLL" $BUILD_CONFIG/osgPlugins-3.4.0 + cp "$DLL" $BUILD_CONFIG/osgPlugins-3.4.1 done echo From 0153b54c3fac2824ab17c081b6f6a99ebe0e575e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 23 Oct 2017 14:08:08 +0200 Subject: [PATCH 346/505] increased version number --- CMakeLists.txt | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b47678e7d..8d9e4c9b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,7 @@ endif() message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) -set(OPENMW_VERSION_MINOR 42) +set(OPENMW_VERSION_MINOR 43) set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_COMMITHASH "") diff --git a/README.md b/README.md index aa6ae47b4..a6d68dd18 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ OpenMW is a recreation of the engine for the popular role-playing game Morrowind OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set. -* Version: 0.42.0 +* Version: 0.43.0 * License: GPLv3 (see [docs/license/GPL3.txt](https://github.com/OpenMW/openmw/blob/master/docs/license/GPL3.txt) for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net From dcd08e63294e9b474f92782627765e4c0494c674 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 23 Oct 2017 14:28:21 +0200 Subject: [PATCH 347/505] updated changelog --- CHANGELOG.md | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b390169c6..ac2a5472e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,140 @@ +0.43.0 +------ + + Bug #815: Different settings cause inconsistent underwater visibility + Bug #1452: autosave is not executed when waiting + Bug #1555: Closing containers with spacebar doesn't work after touching an item + Bug #1692: Can't close container when item is "held" + Bug #2405: Maximum distance for guards attacking hostile creatures is incorrect + Bug #2445: Spellcasting can be interrupted + Bug #2489: Keeping map open not persisted between saves + Bug #2594: 1st person view uses wrong body texture with Better bodies + Bug #2628: enablestatreviewmenu command doen't read race, class and sign values from current game + Bug #2639: Attacking flag isn't reset upon reloading + Bug #2698: Snow and rain VFX move with the player + Bug #2704: Some creature swim animations not being used + Bug #2789: Potential risk of misunderstanding using the colored "owned" crosshair feature + Bug #3045: Settings containing '#' cannot be loaded + Bug #3097: Drop() doesn't work when an item is held (with the mouse) + Bug #3110: GetDetected doesn't work without a reference + Bug #3126: Framerate nosedives when adjusting dialogue window size + Bug #3243: Ampersand in configuration files isn't escaped automatically + Bug #3365: Wrong water reflection along banks + Bug #3441: Golden saint always dispelling soul trap / spell priority issue + Bug #3528: Disposing of corpses breaks quests + Bug #3531: No FPS limit when playing bink videos even though "framerate limit" is set in settings.cfg + Bug #3647: Multi-effect spells play audio louder than in Vanilla + Bug #3656: NPCs forget where their place in the world is + Bug #3665: Music transitions are too abrupt + Bug #3679: Spell cast effect should disappear after using rest command + Bug #3684: Merchants do not restock empty soul gems if they acquire filled ones. + Bug #3694: Wrong magicka bonus applied on character creation + Bug #3706: Guards don't try to arrest the player if attacked + Bug #3709: Editor: Camera is not positioned correctly on mode switches related to orbital mode + Bug #3720: Death counter not cleaned of non-existing IDs when loading a game + Bug #3744: "Greater/lesser or equal" operators are not parsed when their signs are swapped + Bug #3749: Yagrum Bagarn moves to different position on encountering + Bug #3766: DisableLevitation does not remove visuals of preexisting effect + Bug #3787: Script commands in result box for voiced dialogue are ignored + Bug #3793: OpenMW tries to animate animated references even when they are disabled + Bug #3794: Default sound buffer size is too small for mods + Bug #3796: Mod 'Undress for me' doesn't work: NPCs re-equip everything + Bug #3798: tgm command behaviour differs from vanilla + Bug #3804: [Mod] Animated Morrowind: some animations do not loop correctly + Bug #3805: Slight enchant miscalculation + Bug #3826: Rendering problems with an image in a letter + Bug #3833: [Mod] Windows Glow: windows textures are much darker than in original game + Bug #3835: Bodyparts with multiple NiTriShapes are not handled correctly + Bug #3839: InventoryStore::purgeEffect() removes only first effect with argument ID + Bug #3843: Wrong jumping fatigue loss calculations + Bug #3850: Boethiah's voice is distorted underwater + Bug #3851: NPCs and player say things while underwater + Bug #3864: Crash when exiting to Khartag point from Ilunibi + Bug #3878: Swapping soul gems while enchanting allows constant effect enchantments using any soul gem + Bug #3879: Dialogue option: Go to jail, persists beyond quickload + Bug #3891: Journal displays empty entries + Bug #3892: Empty space before dialogue entry display + Bug #3898: (mod) PositionCell in dialogue results closes dialogue window + Bug #3906: "Could not find Data Files location" dialog can appear multiple times + Bug #3908: [Wizard] User gets stuck if they cancel out of installing from a CD + Bug #3909: Morrowind Content Language dropdown is the only element on the right half of the Settings window + Bug #3910: Launcher window can be resized so that it cuts off the scroll + Bug #3915: NC text key on nifs doesn't work + Bug #3919: Closing inventory while cursor hovers over spell (or other magic menu item) produces left click sound + Bug #3922: Combat AI should avoid enemy hits when casts Self-ranged spells + Bug #3934: [macOS] Copy/Paste from system clipboard uses Control key instead of Command key + Bug #3935: Incorrect attack strength for AI actors + Bug #3937: Combat AI: enchanted weapons have too high rating + Bug #3942: UI sounds are distorted underwater + Bug #3943: CPU/GPU usage should stop when the game is minimised + Bug #3944: Attempting to sell stolen items back to their owner does not remove them from your inventory + Bug #3955: Player's avatar rendering issues + Bug #3956: EditEffectDialog: Cancel button does not update a Range button and an Area slider properly + Bug #3957: Weird bodypart rendering if a node has reserved name + Bug #3960: Clothes with high cost (> 32768) are not handled properly + Bug #3963: When on edge of being burdened the condition doesn't lower as you run. + Bug #3971: Editor: Incorrect colour field in cell table + Bug #3974: Journal page turning doesn't produce sounds + Bug #3978: Instant opening and closing happens when using a Controller with Menus/Containers + Bug #3981: Lagging when spells are cast, especially noticeable on new landmasses such as Tamriel Rebuilt + Bug #3982: Down sounds instead of Up ones are played when trading + Bug #3987: NPCs attack after some taunting with no "Goodbye" + Bug #3991: Journal can still be opened at main menu + Bug #3995: Dispel cancels every temporary magic effect + Bug #4002: Build broken on OpenBSD with clang + Bug #4003: Reduce Render Area of Inventory Doll to Fit Within Border + Bug #4004: Manis Virmaulese attacks without saying anything + Bug #4010: AiWander: "return to the spawn position" feature does not work properly + Bug #4016: Closing menus with spacebar will still send certain assigned actions through afterwards + Bug #4017: GetPCRunning and GetPCSneaking should check that the PC is actually moving + Bug #4024: Poor music track distribution + Bug #4025: Custom spell with copy-pasted name always sorts to top of spell list + Bug #4027: Editor: OpenMW-CS misreports its own name as "OpenCS", under Mac OS + Bug #4033: Archers don't attack if the arrows have run out and there is no other weapon + Bug #4037: Editor: New greetings do not work in-game. + Bug #4049: Reloading a saved game while falling prevents damage + Bug #4056: Draw animation should not be played when player equips a new weapon + Bug #4074: Editor: Merging of LAND/LTEX records + Bug #4076: Disposition bar is not updated when "goodbye" selected in dialogue + Bug #4079: Alchemy skill increases do not take effect until next batch + Bug #4093: GetResistFire, getResistFrost and getResistShock doesn't work as in vanilla + Bug #4094: Level-up messages for levels past 20 are hardcoded not to be used + Bug #4095: Error in framelistener when take all items from a dead corpse + Bug #4096: Messagebox with the "%0.f" format should use 0 digit precision + Bug #4104: Cycling through weapons does not skip broken ones + Bug #4105: birthsign generation menu does not show full details + Bug #4107: Editor: Left pane in Preferences window is too narrow + Bug #4112: Inventory sort order is inconsistent + Bug #4113: 'Resolution not supported in fullscreen' message is inconvenient + Bug #4131: Pickpocketing behaviour is different from vanilla + Bug #4155: NPCs don't equip a second ring in some cases + Bug #4156: Snow doesn't create water ripples + Bug #4165: NPCs autoequip new clothing with the same price + Feature #452: Rain-induced water ripples + Feature #824: Fading for doors and teleport commands + Feature #933: Editor: LTEX record table + Feature #936: Editor: LAND record table + Feature #1374: AI: Resurface to breathe + Feature #2320: ess-Importer: convert projectiles + Feature #2509: Editor: highlighting occurrences of a word in a script + Feature #2748: Editor: Should use one resource manager per document + Feature #2834: Have openMW's UI remember what menu items were 'pinned' across boots. + Feature #2923: Option to show the damage of the arrows through tooltip. + Feature #3099: Disabling inventory while dragging an item forces you to drop it + Feature #3274: Editor: Script Editor - Shortcuts and context menu options for commenting code out and uncommenting code respectively + Feature #3275: Editor: User Settings- Add an option to reset settings to their default status (per category / all) + Feature #3400: Add keyboard shortcuts for menus + Feature #3492: Show success rate while enchanting + Feature #3530: Editor: Reload data files + Feature #3682: Editor: Default key binding reset + Feature #3921: Combat AI: aggro priorities + Feature #3941: Allow starting at an unnamed exterior cell with --start + Feature #3952: Add Visual Studio 2017 support + Feature #3953: Combat AI: use "WhenUsed" enchantments + Feature #4082: Leave the stack of ingredients or potions grabbed after using an ingredient/potion + Task #2258: Windows installer: launch OpenMW tickbox + Task #4152: The Windows CI script is moving files around that CMake should be dealing with + 0.42.0 ------ From 2a0b2c4e2485ca4e08ec1d440f515a0d77808a9d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 23 Oct 2017 23:31:59 +0200 Subject: [PATCH 348/505] Hide modal window before deleting it (Fixes #4168) --- apps/openmw/mwgui/messagebox.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 376a28aa7..7c89c4979 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -126,6 +126,7 @@ namespace MWGui if (mInterMessageBoxe != NULL) { std::cerr << "Warning: replacing an interactive message box that was not answered yet" << std::endl; + mInterMessageBoxe->setVisible(false); delete mInterMessageBoxe; mInterMessageBoxe = NULL; } From e564dd842e79f8518b6b336054867e0f8435d10b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 24 Oct 2017 00:25:41 +0200 Subject: [PATCH 349/505] Refactor dialogue responses to make sure messages from scripts are printer afterwards, not before the dialogue response (Fixes #4166) Don't delete Link objects prematurely (Fixes #4171) --- apps/openmw/mwbase/dialoguemanager.hpp | 17 ++-- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 30 +++--- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 12 +-- apps/openmw/mwgui/dialogue.cpp | 93 ++++++++++--------- apps/openmw/mwgui/dialogue.hpp | 13 ++- 5 files changed, 86 insertions(+), 79 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index c928fa940..a9afae786 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -36,6 +36,12 @@ namespace MWBase public: + class ResponseCallback + { + public: + virtual void addResponse(const std::string& title, const std::string& text) = 0; + }; + DialogueManager() {} virtual void clear() = 0; @@ -44,8 +50,7 @@ namespace MWBase virtual bool isInChoice() const = 0; - typedef std::pair Response; // title, text - virtual bool startDialogue (const MWWorld::Ptr& actor, Response& response) = 0; + virtual bool startDialogue (const MWWorld::Ptr& actor, ResponseCallback* callback) = 0; virtual void addTopic (const std::string& topic) = 0; @@ -58,15 +63,15 @@ namespace MWBase virtual void say(const MWWorld::Ptr &actor, const std::string &topic) = 0; - virtual Response keywordSelected (const std::string& keyword) = 0; + virtual void keywordSelected (const std::string& keyword, ResponseCallback* callback) = 0; virtual void goodbyeSelected() = 0; - virtual Response questionAnswered (int answer) = 0; + virtual void questionAnswered (int answer, ResponseCallback* callback) = 0; virtual std::list getAvailableTopics() = 0; - virtual bool checkServiceRefused (Response& response) = 0; + virtual bool checkServiceRefused (ResponseCallback* callback) = 0; - virtual Response persuade (int type) = 0; + virtual void persuade (int type, ResponseCallback* callback) = 0; virtual int getTemporaryDispositionChange () const = 0; /// @note This change is temporary and gets discarded when dialogue ends. diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index acfe7f5ee..88e65e535 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -101,7 +101,7 @@ namespace MWDialogue } } - bool DialogueManager::startDialogue (const MWWorld::Ptr& actor, Response& response) + bool DialogueManager::startDialogue (const MWWorld::Ptr& actor, ResponseCallback* callback) { updateGlobals(); @@ -151,7 +151,7 @@ namespace MWDialogue parseText (info->mResponse); MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - response = Response ("", Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); + callback->addResponse("", Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript, mActor); mLastTopic = it->mId; @@ -240,9 +240,8 @@ namespace MWDialogue } } - DialogueManager::Response DialogueManager::executeTopic (const std::string& topic) + void DialogueManager::executeTopic (const std::string& topic, ResponseCallback* callback) { - DialogueManager::Response response; Filter filter (mActor, mChoice, mTalkedTo); const MWWorld::Store &dialogues = @@ -274,7 +273,7 @@ namespace MWDialogue title = topic; MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - response = Response(title, Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); + callback->addResponse(title, Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); if (dialogue.mType == ESM::Dialogue::Topic) { @@ -295,7 +294,6 @@ namespace MWDialogue mLastTopic = topic; } - return response; } const ESM::Dialogue *DialogueManager::searchDialogue(const std::string& id) @@ -350,18 +348,16 @@ namespace MWDialogue return keywordList; } - DialogueManager::Response DialogueManager::keywordSelected (const std::string& keyword) + void DialogueManager::keywordSelected (const std::string& keyword, ResponseCallback* callback) { - Response response; if(!mIsInChoice) { const ESM::Dialogue* dialogue = searchDialogue(keyword); if (dialogue && dialogue->mType == ESM::Dialogue::Topic) { - response = executeTopic (keyword); + executeTopic (keyword, callback); } } - return response; } bool DialogueManager::isInChoice() const @@ -386,10 +382,9 @@ namespace MWDialogue mTemporaryDispositionChange = 0; } - DialogueManager::Response DialogueManager::questionAnswered (int answer) + void DialogueManager::questionAnswered (int answer, ResponseCallback* callback) { mChoice = answer; - DialogueManager::Response response; const ESM::Dialogue* dialogue = searchDialogue(mLastTopic); if (dialogue) @@ -408,7 +403,7 @@ namespace MWDialogue mChoices.clear(); MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - response = Response("", Interpreter::fixDefinesDialog(text, interpreterContext)); + callback->addResponse("", Interpreter::fixDefinesDialog(text, interpreterContext)); // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, // in which case it should not be added to the journal. @@ -434,7 +429,6 @@ namespace MWDialogue } updateActorKnownTopics(); - return response; } void DialogueManager::addChoice (const std::string& text, int choice) @@ -460,7 +454,7 @@ namespace MWDialogue mGoodbye = true; } - DialogueManager::Response DialogueManager::persuade(int type) + void DialogueManager::persuade(int type, ResponseCallback* callback) { bool success; float temp, perm; @@ -509,7 +503,7 @@ namespace MWDialogue text = "Bribe"; } - return executeTopic (text + (success ? " Success" : " Fail")); + executeTopic (text + (success ? " Success" : " Fail"), callback); } int DialogueManager::getTemporaryDispositionChange() const @@ -522,7 +516,7 @@ namespace MWDialogue mTemporaryDispositionChange += delta; } - bool DialogueManager::checkServiceRefused(Response& response) + bool DialogueManager::checkServiceRefused(ResponseCallback* callback) { Filter filter (mActor, mChoice, mTalkedTo); @@ -543,7 +537,7 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - response = Response(gmsts.find ("sServiceRefusal")->getString(), Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); + callback->addResponse(gmsts.find ("sServiceRefusal")->getString(), Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript, mActor); return true; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index a914d9a3e..f267f7542 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -57,7 +57,7 @@ namespace MWDialogue bool compile (const std::string& cmd, std::vector& code, const MWWorld::Ptr& actor); void executeScript (const std::string& script, const MWWorld::Ptr& actor); - Response executeTopic (const std::string& topic); + void executeTopic (const std::string& topic, ResponseCallback* callback); const ESM::Dialogue* searchDialogue(const std::string& id); @@ -69,7 +69,7 @@ namespace MWDialogue virtual bool isInChoice() const; - virtual bool startDialogue (const MWWorld::Ptr& actor, Response& response); + virtual bool startDialogue (const MWWorld::Ptr& actor, ResponseCallback* callback); std::list getAvailableTopics(); @@ -82,16 +82,16 @@ namespace MWDialogue virtual void goodbye(); - virtual bool checkServiceRefused (Response& response); + virtual bool checkServiceRefused (ResponseCallback* callback); virtual void say(const MWWorld::Ptr &actor, const std::string &topic); //calbacks for the GUI - virtual Response keywordSelected (const std::string& keyword); + virtual void keywordSelected (const std::string& keyword, ResponseCallback* callback); virtual void goodbyeSelected(); - virtual Response questionAnswered (int answer); + virtual void questionAnswered (int answer, ResponseCallback* callback); - virtual Response persuade (int type); + virtual void persuade (int type, ResponseCallback* callback); virtual int getTemporaryDispositionChange () const; /// @note This change is temporary and gets discarded when dialogue ends. diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 39c73a23d..8a7ae85ea 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -30,8 +30,29 @@ namespace MWGui { - PersuasionDialog::PersuasionDialog() + class ResponseCallback : public MWBase::DialogueManager::ResponseCallback + { + public: + ResponseCallback(DialogueWindow* win, bool needMargin=true) + : mWindow(win) + , mNeedMargin(needMargin) + { + + } + + void addResponse(const std::string& title, const std::string& text) + { + mWindow->addResponse(title, text, mNeedMargin); + } + + private: + DialogueWindow* mWindow; + bool mNeedMargin; + }; + + PersuasionDialog::PersuasionDialog(ResponseCallback* callback) : WindowModal("openmw_persuasion_dialog.layout") + , mCallback(callback) { getWidget(mCancelButton, "CancelButton"); getWidget(mAdmireButton, "AdmireButton"); @@ -69,9 +90,7 @@ namespace MWGui else /*if (sender == mBribe1000Button)*/ type = MWBase::MechanicsManager::PT_Bribe1000; - MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->persuade(type); - - eventPersuadeMsg(response.first, response.second); + MWBase::Environment::get().getDialogueManager()->persuade(type, mCallback.get()); setVisible(false); } @@ -244,13 +263,14 @@ namespace MWGui : WindowBase("openmw_dialogue_window.layout") , mIsCompanion(false) , mGoodbye(false) - , mPersuasionDialog() + , mPersuasionDialog(new ResponseCallback(this)) + , mCallback(new ResponseCallback(this)) + , mGreetingCallback(new ResponseCallback(this, false)) { // Centre dialog center(); mPersuasionDialog.setVisible(false); - mPersuasionDialog.eventPersuadeMsg += MyGUI::newDelegate(this, &DialogueWindow::onPersuadeResult); //History view getWidget(mHistory, "History"); @@ -277,8 +297,6 @@ namespace MWGui DialogueWindow::~DialogueWindow() { - mPersuasionDialog.eventPersuadeMsg.clear(); - deleteLater(); for (Link* link : mLinks) delete link; @@ -356,12 +374,11 @@ namespace MWGui const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - MWBase::DialogueManager::Response response; if (topic == gmst.find("sPersuasion")->getString()) mPersuasionDialog.setVisible(true); else if (topic == gmst.find("sCompanionShare")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion, mPtr); - else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused(response)) + else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused(mCallback.get())) { if (topic == gmst.find("sBarter")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter, mPtr); @@ -378,19 +395,34 @@ namespace MWGui else if (topic == gmst.find("sRepair")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair, mPtr); } - else - addResponse(response.first, response.second); } } void DialogueWindow::setPtr(const MWWorld::Ptr& actor) { - MWBase::DialogueManager::Response response; - if (!MWBase::Environment::get().getDialogueManager()->startDialogue(actor, response)) + bool sameActor = (mPtr == actor); + if (!sameActor) + { + for (std::vector::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) + delete (*it); + mHistoryContents.clear(); + mKeywords.clear(); + mTopicsList->clear(); + for (std::vector::iterator it = mLinks.begin(); it != mLinks.end(); ++it) + mDeleteLater.push_back(*it); // Links are not deleted right away to prevent issues with event handlers + mLinks.clear(); + } + + mPtr = actor; + mGoodbye = false; + mTopicsList->setEnabled(true); + + if (!MWBase::Environment::get().getDialogueManager()->startDialogue(actor, mGreetingCallback.get())) { // No greetings found. The dialogue window should not be shown. // If this is a companion, we must show the companion window directly (used by BM_bear_be_unique). MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); + mPtr = MWWorld::Ptr(); if (isCompanion(actor)) MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, actor); return; @@ -398,32 +430,11 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); - mGoodbye = false; - bool sameActor = (mPtr == actor); - mPtr = actor; - mTopicsList->setEnabled(true); setTitle(mPtr.getClass().getName(mPtr)); - mTopicsList->clear(); - - if (!sameActor) - { - for (std::vector::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) - delete (*it); - mHistoryContents.clear(); - - mKeywords.clear(); - updateTopicsPane(); - } - - for (std::vector::iterator it = mLinks.begin(); it != mLinks.end(); ++it) - mDeleteLater.push_back(*it); // Links are not deleted right away to prevent issues with event handlers - mLinks.clear(); - + updateTopicsPane(); updateDisposition(); restock(); - - addResponse(response.first, response.second, false); } void DialogueWindow::restock() @@ -608,14 +619,12 @@ namespace MWGui void DialogueWindow::onTopicActivated(const std::string &topicId) { - MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->keywordSelected(topicId); - addResponse(response.first, response.second); + MWBase::Environment::get().getDialogueManager()->keywordSelected(topicId, mCallback.get()); } void DialogueWindow::onChoiceActivated(int id) { - MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->questionAnswered(id); - addResponse(response.first, response.second); + MWBase::Environment::get().getDialogueManager()->questionAnswered(id, mCallback.get()); } void DialogueWindow::onGoodbyeActivated() @@ -707,8 +716,4 @@ namespace MWGui && actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"); } - void DialogueWindow::onPersuadeResult(const std::string &title, const std::string &text) - { - addResponse(title, text); - } } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 472996a6c..277032513 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -22,19 +22,20 @@ namespace MWGui namespace MWGui { + class ResponseCallback; + class PersuasionDialog : public WindowModal { public: - PersuasionDialog(); - - typedef MyGUI::delegates::CMultiDelegate2 EventHandle_Result; - EventHandle_Result eventPersuadeMsg; + PersuasionDialog(ResponseCallback* callback); virtual void onOpen(); virtual MyGUI::Widget* getDefaultKeyFocus(); private: + std::unique_ptr mCallback; + MyGUI::Button* mCancelButton; MyGUI::Button* mAdmireButton; MyGUI::Button* mIntimidateButton; @@ -136,7 +137,6 @@ namespace MWGui bool isCompanion(const MWWorld::Ptr& actor); bool isCompanion(); - void onPersuadeResult(const std::string& title, const std::string& text); void onSelectListItem(const std::string& topic, int id); void onByeClicked(MyGUI::Widget* _sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); @@ -180,6 +180,9 @@ namespace MWGui PersuasionDialog mPersuasionDialog; MyGUI::IntSize mCurrentWindowSize; + + std::unique_ptr mCallback; + std::unique_ptr mGreetingCallback; }; } #endif From 0c6ef17fb56babe42343bff7a3bc5d4f611b0767 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 24 Oct 2017 00:40:17 +0200 Subject: [PATCH 350/505] Add explicit variant of 'OnActivate' --- apps/openmw/mwscript/docs/vmformat.txt | 3 ++- apps/openmw/mwscript/miscextensions.cpp | 9 ++++----- components/compiler/extensions0.cpp | 2 +- components/compiler/opcodes.hpp | 1 + 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 851a6a29c..e999097db 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -453,5 +453,6 @@ op 0x2000302: Fixme op 0x2000303: Fixme, explicit op 0x2000304: Show op 0x2000305: Show, explicit +op 0x2000306: OnActivate, explicit -opcodes 0x2000304-0x3ffffff unused +opcodes 0x2000307-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 98b1a6b47..1067b5536 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -131,16 +131,14 @@ namespace MWScript } }; + template class OpOnActivate : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - - MWWorld::Ptr ptr = context.getReference(); + MWWorld::Ptr ptr = R()(runtime); runtime.push (ptr.getRefData().onActivate()); } @@ -1280,7 +1278,8 @@ namespace MWScript void installOpcodes (Interpreter::Interpreter& interpreter) { interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox); - interpreter.installSegment5 (Compiler::Misc::opcodeOnActivate, new OpOnActivate); + interpreter.installSegment5 (Compiler::Misc::opcodeOnActivate, new OpOnActivate); + interpreter.installSegment5 (Compiler::Misc::opcodeOnActivateExplicit, new OpOnActivate); interpreter.installSegment5 (Compiler::Misc::opcodeActivate, new OpActivate); interpreter.installSegment5 (Compiler::Misc::opcodeActivateExplicit, new OpActivate); interpreter.installSegment3 (Compiler::Misc::opcodeLock, new OpLock); diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index eb3e1e4ee..cd5bf7ef7 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -240,7 +240,7 @@ namespace Compiler void registerExtensions (Extensions& extensions) { extensions.registerFunction ("xbox", 'l', "", opcodeXBox); - extensions.registerFunction ("onactivate", 'l', "", opcodeOnActivate); + extensions.registerFunction ("onactivate", 'l', "", opcodeOnActivate, opcodeOnActivateExplicit); extensions.registerInstruction ("activate", "x", opcodeActivate, opcodeActivateExplicit); extensions.registerInstruction ("lock", "/l", opcodeLock, opcodeLockExplicit); extensions.registerInstruction ("unlock", "", opcodeUnlock, opcodeUnlockExplicit); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index b2333032b..6a6552467 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -200,6 +200,7 @@ namespace Compiler { const int opcodeXBox = 0x200000c; const int opcodeOnActivate = 0x200000d; + const int opcodeOnActivateExplicit = 0x2000306; const int opcodeActivate = 0x2000075; const int opcodeActivateExplicit = 0x2000244; const int opcodeLock = 0x20004; From 3731e2022887024758c80725f6c85d15e5463303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Tue, 24 Oct 2017 14:12:41 +0200 Subject: [PATCH 351/505] fix rain ripple regression --- apps/openmw/mwrender/renderingmanager.cpp | 1 + apps/openmw/mwrender/water.cpp | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6c4cc802b..4fbcdc4d5 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -252,6 +252,7 @@ namespace MWRender sceneRoot->setName("Scene Root"); mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager())); + mSky->setCamera(mViewer->getCamera()); mSky->setRainIntensityUniform(mWater->getRainIntensityUniform()); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 52b659984..c4dffb7a4 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -416,9 +416,9 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem setHeight(mTop); - updateWaterMaterial(); - mRainIntensityUniform = new osg::Uniform("rainIntensity",(float) 0.0); + + updateWaterMaterial(); } osg::Uniform *Water::getRainIntensityUniform() @@ -517,6 +517,7 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R osg::ref_ptr fragmentShader (shaderMgr.getShader("water_fragment.glsl", defineMap, osg::Shader::FRAGMENT)); osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png"))); + if (normalMap->getImage()) normalMap->getImage()->flipVertical(); normalMap->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); @@ -531,6 +532,7 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R shaderStateset->setTextureAttributeAndModes(0, normalMap, osg::StateAttribute::ON); shaderStateset->setTextureAttributeAndModes(1, reflection->getReflectionTexture(), osg::StateAttribute::ON); + if (refraction) { shaderStateset->setTextureAttributeAndModes(2, refraction->getRefractionTexture(), osg::StateAttribute::ON); @@ -552,13 +554,13 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R shaderStateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + shaderStateset->addUniform(mRainIntensityUniform.get()); + osg::ref_ptr program (new osg::Program); program->addShader(vertexShader); program->addShader(fragmentShader); shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); - shaderStateset->addUniform(mRainIntensityUniform); - node->setStateSet(shaderStateset); node->setUpdateCallback(NULL); } From 4a7be0ffda9368e4e2efc3cc61dc42ca9d5cd5b8 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 24 Oct 2017 20:02:35 +0000 Subject: [PATCH 352/505] Don't reset journal index to a lower value (Fixes #4172) --- apps/openmw/mwdialogue/journalimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 41eaed080..b56db1ebd 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -82,7 +82,8 @@ namespace MWDialogue for (TEntryIter i = mJournal.begin (); i != mJournal.end (); ++i) if (i->mTopic == id && i->mInfoId == infoId) { - setJournalIndex(id, index); + if (getJournalIndex(id) < index) + setJournalIndex(id, index); MWBase::Environment::get().getWindowManager()->messageBox ("#{sJournalEntry}"); return; } From 2e6cf53fddd29a9db02f926a384ddd0069aa12d8 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 24 Oct 2017 22:57:35 +0200 Subject: [PATCH 353/505] Update CPack configuration for NSIS packages Now grabs generated files from the configuration directory where they're generated --- CMakeLists.txt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d9e4c9b2..8d0e126c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -443,15 +443,18 @@ if(WIN32) FILE(GLOB dll_files_release "${OpenMW_BINARY_DIR}/Release/*.dll") INSTALL(FILES ${dll_files_debug} DESTINATION "." CONFIGURATIONS Debug) INSTALL(FILES ${dll_files_release} DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") + INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg" CONFIGURATIONS Debug) + INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg" CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt" "${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt" - "${OpenMW_BINARY_DIR}/settings-default.cfg" - "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION ".") + INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/settings-default.cfg" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/settings-default.cfg" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) + INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/gamecontrollerdb.txt" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/gamecontrollerdb.txt" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) if(BUILD_MYGUI_PLUGIN) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Debug) @@ -463,7 +466,9 @@ if(WIN32) INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Release/platforms" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) ENDIF() - INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") + INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Debug/resources" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Release/resources" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) + FILE(GLOB plugin_dir_debug "${OpenMW_BINARY_DIR}/Debug/osgPlugins-*") FILE(GLOB plugin_dir_release "${OpenMW_BINARY_DIR}/Release/osgPlugins-*") INSTALL(DIRECTORY ${plugin_dir_debug} DESTINATION "." CONFIGURATIONS Debug) From 3e51c9e6b3356bebdead4230933965179c1e294b Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 24 Oct 2017 23:23:55 +0200 Subject: [PATCH 354/505] Missed the OpenCS config file --- apps/opencs/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 777bb2d52..b9279bf91 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -252,7 +252,8 @@ endif() if (WIN32) target_link_libraries(openmw-cs ${Boost_LOCALE_LIBRARY}) INSTALL(TARGETS openmw-cs RUNTIME DESTINATION ".") - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION ".") + INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/openmw-cs.cfg" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/openmw-cs.cfg" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) endif() if (MSVC) From e3142b9643eff1ce1e6d631098aeb4c67d0e4d42 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 24 Oct 2017 23:10:50 +0100 Subject: [PATCH 355/505] Add missing variables to those forwarded to the git-version target --- components/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index e9b992e02..e9c872628 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -17,6 +17,8 @@ if (GIT_CHECKOUT) -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} -DOPENMW_VERSION=${OPENMW_VERSION} -DMACROSFILE=${CMAKE_SOURCE_DIR}/cmake/OpenMWMacros.cmake + "-DCMAKE_CONFIGURATION_TYPES=${CMAKE_CONFIGURATION_TYPES}" + "-DCMAKE_GENERATOR=${CMAKE_GENERATOR}" -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake VERBATIM) else (GIT_CHECKOUT) From daf7d8451cb507a38de54363bd82a65fd422ce71 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 24 Oct 2017 23:29:18 +0100 Subject: [PATCH 356/505] Switch to a more reliable method of passing the git-version targt the data it needs --- cmake/OpenMWMacros.cmake | 14 +++++++++----- components/CMakeLists.txt | 5 +++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 5f66705e7..fe2837a09 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -166,11 +166,15 @@ macro (openmw_add_executable target) endmacro (openmw_add_executable) macro (get_generator_is_multi_config VALUE) - if (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) - get_cmake_property(${VALUE} GENERATOR_IS_MULTI_CONFIG) - else (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) - list(LENGTH "${CMAKE_CONFIGURATION_TYPES}" ${VALUE}) - endif (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) + if (DEFINED generator_is_multi_config_var) + set(${VALUE} ${generator_is_multi_config_var}) + else (DEFINED generator_is_multi_config_var) + if (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) + get_cmake_property(${VALUE} GENERATOR_IS_MULTI_CONFIG) + else (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) + list(LENGTH "${CMAKE_CONFIGURATION_TYPES}" ${VALUE}) + endif (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) + endif (DEFINED generator_is_multi_config_var) endmacro (get_generator_is_multi_config) macro (copy_resource_file source_path destination_dir_base dest_path_relative) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index e9c872628..fb78bd432 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -5,7 +5,8 @@ set (VERSION_IN_FILE "${OpenMW_SOURCE_DIR}/files/version.in") set (VERSION_FILE_PATH_BASE "${OpenMW_BINARY_DIR}") set (VERSION_FILE_PATH_RELATIVE resources/version) if (GIT_CHECKOUT) - add_custom_target (git-version + get_generator_is_multi_config(multi_config) + add_custom_target (git-version COMMAND ${CMAKE_COMMAND} -DGIT_EXECUTABLE=${GIT_EXECUTABLE} -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} @@ -18,7 +19,7 @@ if (GIT_CHECKOUT) -DOPENMW_VERSION=${OPENMW_VERSION} -DMACROSFILE=${CMAKE_SOURCE_DIR}/cmake/OpenMWMacros.cmake "-DCMAKE_CONFIGURATION_TYPES=${CMAKE_CONFIGURATION_TYPES}" - "-DCMAKE_GENERATOR=${CMAKE_GENERATOR}" + -Dgenerator_is_multi_config_var=${multi_config} -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake VERBATIM) else (GIT_CHECKOUT) From c1a871ff1fe4b20d2dc26dbc56a5ddaf28514e22 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 24 Oct 2017 23:31:40 +0100 Subject: [PATCH 357/505] Make indentation consistent. --- components/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index fb78bd432..a0b426a16 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -17,9 +17,9 @@ if (GIT_CHECKOUT) -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} -DOPENMW_VERSION=${OPENMW_VERSION} - -DMACROSFILE=${CMAKE_SOURCE_DIR}/cmake/OpenMWMacros.cmake - "-DCMAKE_CONFIGURATION_TYPES=${CMAKE_CONFIGURATION_TYPES}" - -Dgenerator_is_multi_config_var=${multi_config} + -DMACROSFILE=${CMAKE_SOURCE_DIR}/cmake/OpenMWMacros.cmake + "-DCMAKE_CONFIGURATION_TYPES=${CMAKE_CONFIGURATION_TYPES}" + -Dgenerator_is_multi_config_var=${multi_config} -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake VERBATIM) else (GIT_CHECKOUT) From d19839a66670f4410ebf97e7dcd42f1c89300114 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 25 Oct 2017 21:55:58 +0200 Subject: [PATCH 358/505] standerdise on 3.1.0 --- CMakeLists.txt | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b47678e7d..f4b912c70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,16 +24,8 @@ if (USE_QT) set_property(CACHE DESIRED_QT_VERSION PROPERTY STRINGS 4 5) endif() -if (APPLE) - # OS X build process relies on this fix: https://github.com/Kitware/CMake/commit/3df5147043d83aa09acd5c9ce31d5c602efb99db - cmake_minimum_required(VERSION 3.1.0) -elseif (USE_QT AND DESIRED_QT_VERSION MATCHES 5) - # 2.8.11+ is required to make Qt5 happy and allow linking QtMain on Windows. - cmake_minimum_required(VERSION 2.8.11) -else() - # We probably support older versions than this. - cmake_minimum_required(VERSION 2.6) -endif() +# set the minimum required version across the board +cmake_minimum_required(VERSION 3.1.0) project(OpenMW) From 03401bb5df4a804d9ae016ee8fe147ed4eb0b246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 27 Oct 2017 20:19:20 +0200 Subject: [PATCH 359/505] remove redundant condition --- apps/openmw/mwphysics/physicssystem.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 34932e360..36041a85e 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -357,10 +357,9 @@ namespace MWPhysics osg::Vec3f nextpos = newPosition + velocity * remainingTime; // If not able to fly, don't allow to swim up into the air - if(newPosition.z() < swimlevel && - !isFlying && // can't fly + if(!isFlying && // can't fly nextpos.z() > swimlevel && // but about to go above water - newPosition.z() <= swimlevel) + newPosition.z() < swimlevel) { const osg::Vec3f down(0,0,-1); velocity = slide(velocity, down); From 04af200ae8a6ebf19542f18753abcfc21763d0fe Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sat, 28 Oct 2017 13:37:41 +0200 Subject: [PATCH 360/505] Downgrade MyGUI to 3.2.2 for Windows builds --- CI/before_script.msvc.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 39cb37bed..9f6051863 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -320,9 +320,9 @@ if [ -z $SKIP_DOWNLOAD ]; then "ffmpeg-3.2.4-dev-win${BITS}.zip" # MyGUI - download "MyGUI 3.2.3-git" \ - "http://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.3-git-msvc${MSVC_YEAR}-win${BITS}.7z" \ - "MyGUI-3.2.3-git-msvc${MSVC_YEAR}-win${BITS}.7z" + download "MyGUI 3.2.2" \ + "http://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" \ + "MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" # OpenAL download "OpenAL-Soft 1.17.2" \ @@ -474,20 +474,20 @@ cd $DEPS echo # MyGUI -printf "MyGUI 3.2.3-git... " +printf "MyGUI 3.2.2... " { cd $DEPS_INSTALL if [ -d MyGUI ] && \ grep "MYGUI_VERSION_MAJOR 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \ grep "MYGUI_VERSION_MINOR 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \ - grep "MYGUI_VERSION_PATCH 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null + grep "MYGUI_VERSION_PATCH 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null then printf "Exists. " elif [ -z $SKIP_EXTRACT ]; then rm -rf MyGUI - eval 7z x -y "${DEPS}/MyGUI-3.2.3-git-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP - mv "MyGUI-3.2.3-git-msvc${MSVC_YEAR}-win${BITS}" MyGUI + eval 7z x -y "${DEPS}/MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP + mv "MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}" MyGUI fi export MYGUI_HOME="$(real_pwd)/MyGUI" From f9c396e0eae7037d0217b79cbbb5fe3878853a29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sat, 28 Oct 2017 15:48:07 +0200 Subject: [PATCH 361/505] stop landing animation when turning --- apps/openmw/mwmechanics/character.cpp | 6 ++++++ apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 7 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 03acfdaf2..dc910c577 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -372,6 +372,9 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState } } + if (jumpAnimName.length() > 0) + mJumpAnimName = jumpAnimName; + if(mJumpState == JumpState_InAir) { mAnimation->disable(mCurrentJump); @@ -555,6 +558,9 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if (mPtr.getClass().isActor()) refreshHitRecoilAnims(); + if (isTurning() && mJumpState != JumpState_InAir) + mAnimation->disable(mJumpAnimName); + const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType)); if (!mPtr.getClass().isBipedal(mPtr)) weap = sWeaponTypeListEnd; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index af90c18b8..c03702ef2 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -184,6 +184,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener JumpingState mJumpState; std::string mCurrentJump; + std::string mJumpAnimName; WeaponType mWeaponType; std::string mCurrentWeapon; From 41dc82abadfe785b57c08c2e2a3e68edd67a308f Mon Sep 17 00:00:00 2001 From: David Walley <31402617+loriel2@users.noreply.github.com> Date: Sat, 28 Oct 2017 17:05:30 +0100 Subject: [PATCH 362/505] Update Links to Documentation in settings.cfg files (#1523) * Update settings-default.cfg * Update settings.cpp --- components/settings/settings.cpp | 2 +- files/settings-default.cfg | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index e93642ee2..2e7b5a8ae 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -292,7 +292,7 @@ public: ostream << "# to its default, simply remove it from this file. For available" << std::endl; ostream << "# settings, see the file 'settings-default.cfg' or the documentation at:" << std::endl; ostream << "#" << std::endl; - ostream << "# https://wiki.openmw.org/index.php?title=Settings" << std::endl; + ostream << "# http://openmw.readthedocs.io/en/master/reference/modding/settings/index.html" << std::endl; } // We still have one more thing to do before we're completely done writing the file. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index aec667a9c..253883402 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -6,9 +6,9 @@ # ranges of recommended values. For detailed explanations of the # significance of each setting, interaction with other settings, hard # limits on value ranges and more information in general, please read -# the detailed documentation at the OpenMW Wiki page: +# the detailed documentation at: # -# https://wiki.openmw.org/index.php?title=Settings +# http://openmw.readthedocs.io/en/master/reference/modding/settings/index.html # [Camera] From 5c8f4914419fa3421d86f8884a517e942ce08f93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sat, 28 Oct 2017 18:46:52 +0200 Subject: [PATCH 363/505] move animation disabling code to a better place --- apps/openmw/mwmechanics/character.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index dc910c577..83c7ce844 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -558,9 +558,6 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if (mPtr.getClass().isActor()) refreshHitRecoilAnims(); - if (isTurning() && mJumpState != JumpState_InAir) - mAnimation->disable(mJumpAnimName); - const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType)); if (!mPtr.getClass().isBipedal(mPtr)) weap = sWeaponTypeListEnd; @@ -1883,9 +1880,15 @@ void CharacterController::update(float duration) else if(rot.z() != 0.0f && !sneak && !(mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())) { if(rot.z() > 0.0f) + { movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight; + mAnimation->disable(mJumpAnimName); + } else if(rot.z() < 0.0f) + { movestate = inwater ? CharState_SwimTurnLeft : CharState_TurnLeft; + mAnimation->disable(mJumpAnimName); + } } } From 1ee5dcff775995f783478204954786ece270b677 Mon Sep 17 00:00:00 2001 From: rexelion Date: Sat, 28 Oct 2017 20:56:08 +0100 Subject: [PATCH 364/505] added a function to determine if a script contains OnActivate --- apps/openmw/mwbase/scriptmanager.hpp | 4 ++++ apps/openmw/mwscript/scriptmanagerimp.cpp | 6 ++++++ apps/openmw/mwscript/scriptmanagerimp.hpp | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/apps/openmw/mwbase/scriptmanager.hpp b/apps/openmw/mwbase/scriptmanager.hpp index 7bdeba132..44d350115 100644 --- a/apps/openmw/mwbase/scriptmanager.hpp +++ b/apps/openmw/mwbase/scriptmanager.hpp @@ -42,6 +42,10 @@ namespace MWBase ///< Compile script with the given namen /// \return Success? + virtual bool hasOnActivate (const std::string& name) = 0; + ///< Determine if a script with the given name contains OnActivate + /// \return Contains OnActivate? + virtual std::pair compileAll() = 0; ///< Compile all scripts /// \return count, success diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 7c1f9bf4d..01ff97be2 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -88,6 +88,12 @@ namespace MWScript return false; } + bool ScriptManager::hasOnActivate(const std::string& name) + { + const ESM::Script *script = mStore.get().find(name); + return script->mScriptText.find("OnActivate"); + } + void ScriptManager::run (const std::string& name, Interpreter::Context& interpreterContext) { // compile script diff --git a/apps/openmw/mwscript/scriptmanagerimp.hpp b/apps/openmw/mwscript/scriptmanagerimp.hpp index c22a5da81..3835be26e 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.hpp +++ b/apps/openmw/mwscript/scriptmanagerimp.hpp @@ -62,6 +62,10 @@ namespace MWScript ///< Compile script with the given namen /// \return Success? + virtual bool hasOnActivate(const std::string& name); + ///< Determine if a script with the given name contains OnActivate + /// \return Contains OnActivate? + virtual std::pair compileAll(); ///< Compile all scripts /// \return count, success From 4e6f53d6f16572086ad1c0d5455e16ed3ce359af Mon Sep 17 00:00:00 2001 From: rexelion Date: Sun, 29 Oct 2017 11:45:17 +0000 Subject: [PATCH 365/505] item added to the player and OnActivate is triggered when the inventory is closed --- apps/openmw/mwgui/inventorywindow.cpp | 20 ++++++++++++++++++++ apps/openmw/mwgui/inventorywindow.hpp | 4 ++++ apps/openmw/mwgui/windowmanagerimp.cpp | 2 ++ 3 files changed, 26 insertions(+) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index b3697008c..8586cfb5b 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1,6 +1,7 @@ #include "inventorywindow.hpp" #include +#include #include #include @@ -149,6 +150,15 @@ namespace MWGui mItemView->setModel(NULL); } + void InventoryWindow::activateItems() + { + for (std::vector::iterator it = mItemsToActivate.begin(); it != mItemsToActivate.end(); it++) + { + it->getRefData().activate(); + } + mItemsToActivate.clear(); + } + void InventoryWindow::setGuiMode(GuiMode mode) { std::string setting = "inventory"; @@ -653,6 +663,16 @@ namespace MWGui if (object.getClass().getName(object) == "") // objects without name presented to user can never be picked up return; + std::string scriptName = object.getClass().getScript(object); // Objects that have OnActivte in their script cannot be picked up through inventory + if (!scriptName.empty() && MWBase::Environment::get().getScriptManager()->hasOnActivate(scriptName)) + { + if (std::find(mItemsToActivate.begin(), mItemsToActivate.end(), object) == mItemsToActivate.end()) + { + mItemsToActivate.push_back(object); + } + return; + } + int count = object.getRefData().getCount(); MWWorld::Ptr player = MWMechanics::getPlayer(); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 5576b52ed..3f88d8822 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -58,6 +58,8 @@ namespace MWGui void clear(); + void activateItems(); + void useItem(const MWWorld::Ptr& ptr); void setGuiMode(GuiMode mode); @@ -70,6 +72,8 @@ namespace MWGui int mSelectedItem; + std::vector mItemsToActivate; + MWWorld::Ptr mPtr; MWGui::ItemView* mItemView; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index ccdd6916c..e2a10ccc3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1171,6 +1171,8 @@ namespace MWGui mGuiModeStates[mode].update(false); if (!noSound) playSound(mGuiModeStates[mode].mCloseSound); + if (mode == GM_Inventory) + mInventoryWindow->activateItems(); // Activate cursed items when inventory is closed } if (!mGuiModes.empty()) From 7bc512974f2d2d663c6813cd3d55de337b7c1858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Mon, 30 Oct 2017 15:26:38 +0100 Subject: [PATCH 366/505] use mcurrentjump instead of custom attrib --- apps/openmw/mwmechanics/character.cpp | 12 +++++------- apps/openmw/mwmechanics/character.hpp | 1 - 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 83c7ce844..a2e07fc5c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -372,9 +372,6 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState } } - if (jumpAnimName.length() > 0) - mJumpAnimName = jumpAnimName; - if(mJumpState == JumpState_InAir) { mAnimation->disable(mCurrentJump); @@ -385,8 +382,9 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState } else { - mAnimation->disable(mCurrentJump); - mCurrentJump.clear(); + if (startAtLoop) + mAnimation->disable(mCurrentJump); + if (mAnimation->hasAnimation("jump")) mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, true, 1.0f, "loop stop", "stop", 0.0f, 0); @@ -1882,12 +1880,12 @@ void CharacterController::update(float duration) if(rot.z() > 0.0f) { movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight; - mAnimation->disable(mJumpAnimName); + mAnimation->disable(mCurrentJump); } else if(rot.z() < 0.0f) { movestate = inwater ? CharState_SwimTurnLeft : CharState_TurnLeft; - mAnimation->disable(mJumpAnimName); + mAnimation->disable(mCurrentJump); } } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c03702ef2..af90c18b8 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -184,7 +184,6 @@ class CharacterController : public MWRender::Animation::TextKeyListener JumpingState mJumpState; std::string mCurrentJump; - std::string mJumpAnimName; WeaponType mWeaponType; std::string mCurrentWeapon; From 3c65bdaf1408632bcbc0019b3cf7bb060294ead0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Mon, 30 Oct 2017 18:05:45 +0100 Subject: [PATCH 367/505] weapon cycle fix --- apps/openmw/mwgui/inventorywindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index b3697008c..a92c77760 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -735,7 +735,7 @@ namespace MWGui } } - if (!found) + if (!found || selected == cycled) return; useItem(model.getItem(cycled).mBase); From e8743f3f795ff8b4b7c3bfe103ca930587872258 Mon Sep 17 00:00:00 2001 From: rexelion Date: Mon, 30 Oct 2017 20:59:36 +0000 Subject: [PATCH 368/505] check the presence of OnActivate using the SuppressActivate flag instead of looking for keywords --- apps/openmw/mwbase/scriptmanager.hpp | 4 ---- apps/openmw/mwgui/inventorywindow.cpp | 3 +-- apps/openmw/mwscript/scriptmanagerimp.cpp | 6 ------ apps/openmw/mwscript/scriptmanagerimp.hpp | 4 ---- apps/openmw/mwworld/refdata.cpp | 5 +++++ apps/openmw/mwworld/refdata.hpp | 2 ++ 6 files changed, 8 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwbase/scriptmanager.hpp b/apps/openmw/mwbase/scriptmanager.hpp index 44d350115..7bdeba132 100644 --- a/apps/openmw/mwbase/scriptmanager.hpp +++ b/apps/openmw/mwbase/scriptmanager.hpp @@ -42,10 +42,6 @@ namespace MWBase ///< Compile script with the given namen /// \return Success? - virtual bool hasOnActivate (const std::string& name) = 0; - ///< Determine if a script with the given name contains OnActivate - /// \return Contains OnActivate? - virtual std::pair compileAll() = 0; ///< Compile all scripts /// \return count, success diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 8586cfb5b..5fe644d45 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -663,8 +663,7 @@ namespace MWGui if (object.getClass().getName(object) == "") // objects without name presented to user can never be picked up return; - std::string scriptName = object.getClass().getScript(object); // Objects that have OnActivte in their script cannot be picked up through inventory - if (!scriptName.empty() && MWBase::Environment::get().getScriptManager()->hasOnActivate(scriptName)) + if (object.getRefData().hasSuppressActivate()) // if Flag_SuppressActivate is set, script that contains OnActivate is attached to the item { if (std::find(mItemsToActivate.begin(), mItemsToActivate.end(), object) == mItemsToActivate.end()) { diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 01ff97be2..7c1f9bf4d 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -88,12 +88,6 @@ namespace MWScript return false; } - bool ScriptManager::hasOnActivate(const std::string& name) - { - const ESM::Script *script = mStore.get().find(name); - return script->mScriptText.find("OnActivate"); - } - void ScriptManager::run (const std::string& name, Interpreter::Context& interpreterContext) { // compile script diff --git a/apps/openmw/mwscript/scriptmanagerimp.hpp b/apps/openmw/mwscript/scriptmanagerimp.hpp index 3835be26e..c22a5da81 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.hpp +++ b/apps/openmw/mwscript/scriptmanagerimp.hpp @@ -62,10 +62,6 @@ namespace MWScript ///< Compile script with the given namen /// \return Success? - virtual bool hasOnActivate(const std::string& name); - ///< Determine if a script with the given name contains OnActivate - /// \return Contains OnActivate? - virtual std::pair compileAll(); ///< Compile all scripts /// \return count, success diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index f6fa3556f..95b0fb3e0 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -192,6 +192,11 @@ namespace MWWorld return mEnabled; } + bool RefData::hasSuppressActivate() + { + return mFlags & Flag_SuppressActivate; + } + void RefData::enable() { if (!mEnabled) diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 75eec6742..4dfa9e91c 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -111,6 +111,8 @@ namespace MWWorld bool isEnabled() const; + bool hasSuppressActivate(); + void enable(); void disable(); From ff1265c0e7b67e68462886ab0d2d3b5cbeda8d2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Tue, 31 Oct 2017 14:22:24 +0100 Subject: [PATCH 369/505] refactor jump animation --- apps/openmw/mwmechanics/character.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a2e07fc5c..f262850a4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -380,7 +380,7 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState mAnimation->play(mCurrentJump, Priority_Jump, jumpmask, false, 1.0f, (startAtLoop?"loop start":"start"), "stop", 0.0f, ~0ul); } - else + else if (mJumpState == JumpState_Landing) { if (startAtLoop) mAnimation->disable(mCurrentJump); @@ -389,6 +389,14 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, true, 1.0f, "loop stop", "stop", 0.0f, 0); } + else // JumpState_None + { + if (mCurrentJump.length() > 0) + { + mAnimation->disable(mCurrentJump); + mCurrentJump.clear(); + } + } } } @@ -1693,7 +1701,6 @@ void CharacterController::update(float duration) mHasMovedInXY = std::abs(vec.x())+std::abs(vec.y()) > 0.0f; isrunning = isrunning && mHasMovedInXY; - // advance athletics if(mHasMovedInXY && mPtr == getPlayer()) { @@ -1848,7 +1855,8 @@ void CharacterController::update(float duration) } else { - jumpstate = JumpState_None; + jumpstate = mAnimation->isPlaying(mCurrentJump) ? JumpState_Landing : JumpState_None; + vec.z() = 0.0f; inJump = false; From a9e5e1948270945bbb16be1219cb61a10ce8ddd8 Mon Sep 17 00:00:00 2001 From: rexelion Date: Tue, 31 Oct 2017 18:16:40 +0000 Subject: [PATCH 370/505] OnActivate is triggered when the item is picked up --- apps/openmw/mwgui/inventorywindow.cpp | 26 +++++++------------------- apps/openmw/mwgui/inventorywindow.hpp | 4 ---- apps/openmw/mwgui/windowmanagerimp.cpp | 2 -- apps/openmw/mwworld/actiontake.cpp | 3 +++ 4 files changed, 10 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 5fe644d45..1e9f534d6 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1,7 +1,6 @@ #include "inventorywindow.hpp" #include -#include #include #include @@ -150,15 +149,6 @@ namespace MWGui mItemView->setModel(NULL); } - void InventoryWindow::activateItems() - { - for (std::vector::iterator it = mItemsToActivate.begin(); it != mItemsToActivate.end(); it++) - { - it->getRefData().activate(); - } - mItemsToActivate.clear(); - } - void InventoryWindow::setGuiMode(GuiMode mode) { std::string setting = "inventory"; @@ -663,15 +653,6 @@ namespace MWGui if (object.getClass().getName(object) == "") // objects without name presented to user can never be picked up return; - if (object.getRefData().hasSuppressActivate()) // if Flag_SuppressActivate is set, script that contains OnActivate is attached to the item - { - if (std::find(mItemsToActivate.begin(), mItemsToActivate.end(), object) == mItemsToActivate.end()) - { - mItemsToActivate.push_back(object); - } - return; - } - int count = object.getRefData().getCount(); MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -682,6 +663,13 @@ namespace MWGui // add to player inventory // can't use ActionTake here because we need an MWWorld::Ptr to the newly inserted object MWWorld::Ptr newObject = *player.getClass().getContainerStore (player).add (object, object.getRefData().getCount(), player); + + if (object.getRefData().hasSuppressActivate()) // if Flag_SuppressActivate is set, script that contains OnActivate is attached to the item + { + newObject.getRefData().onActivate(); // set the flag_SuppressActivate flag for the new item + newObject.getRefData().activate(); + } + // remove from world MWBase::Environment::get().getWorld()->deleteObject (object); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 3f88d8822..5576b52ed 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -58,8 +58,6 @@ namespace MWGui void clear(); - void activateItems(); - void useItem(const MWWorld::Ptr& ptr); void setGuiMode(GuiMode mode); @@ -72,8 +70,6 @@ namespace MWGui int mSelectedItem; - std::vector mItemsToActivate; - MWWorld::Ptr mPtr; MWGui::ItemView* mItemView; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e2a10ccc3..ccdd6916c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1171,8 +1171,6 @@ namespace MWGui mGuiModeStates[mode].update(false); if (!noSound) playSound(mGuiModeStates[mode].mCloseSound); - if (mode == GM_Inventory) - mInventoryWindow->activateItems(); // Activate cursed items when inventory is closed } if (!mGuiModes.empty()) diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index d858859a6..52e30c8ac 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -14,6 +14,9 @@ namespace MWWorld void ActionTake::executeImp (const Ptr& actor) { + //No need to do anything if moving items from the player's inventory back into player's inventory + if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr() && getTarget().getCell() == 0) + return; MWBase::Environment::get().getMechanicsManager()->itemTaken( actor, getTarget(), MWWorld::Ptr(), getTarget().getRefData().getCount()); MWWorld::Ptr newitem = *actor.getClass().getContainerStore (actor).add (getTarget(), getTarget().getRefData().getCount(), actor); From 5b8610b34b61e5b587cc196205aa3bb1275d5967 Mon Sep 17 00:00:00 2001 From: rexelion Date: Wed, 1 Nov 2017 23:44:50 +0000 Subject: [PATCH 371/505] knocked out characters wait some time before getting up --- apps/openmw/mwmechanics/character.cpp | 6 +++++- apps/openmw/mwmechanics/character.hpp | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 03acfdaf2..c3ca8f512 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -248,12 +248,15 @@ void CharacterController::refreshHitRecoilAnims() bool knockdown = mPtr.getClass().getCreatureStats(mPtr).getKnockedDown(); bool block = mPtr.getClass().getCreatureStats(mPtr).getBlock(); bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr); + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor(); if(mHitState == CharState_None) { if ((mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0 || mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0) && mAnimation->hasAnimation("knockout")) { + mKnockoutTime = MWBase::Environment::get().getWorld()->getTimeStamp(); if (isSwimming && mAnimation->hasAnimation("swimknockout")) { mHitState = CharState_SwimKnockOut; @@ -338,7 +341,8 @@ void CharacterController::refreshHitRecoilAnims() mPtr.getClass().getCreatureStats(mPtr).setBlock(false); mHitState = CharState_None; } - else if (isKnockedOut() && mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() > 0) + else if (isKnockedOut() && mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() > 0 + && (currentTime - mKnockoutTime) > 3*timeScale/3600) //Wait 3 seconds before getting up { mHitState = isSwimming ? CharState_SwimKnockDown : CharState_KnockDown; mAnimation->disable(mCurrentHit); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index af90c18b8..0654b8534 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -7,6 +7,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/timestamp.hpp" #include "../mwrender/animation.hpp" @@ -196,6 +197,8 @@ class CharacterController : public MWRender::Animation::TextKeyListener float mSecondsOfSwimming; float mSecondsOfRunning; + MWWorld::TimeStamp mKnockoutTime; + MWWorld::ConstPtr mHeadTrackTarget; float mTurnAnimationThreshold; // how long to continue playing turning animation after actor stopped turning From de83ad0116c434e8bf90ab4f330a93e50f392191 Mon Sep 17 00:00:00 2001 From: rexelion Date: Sat, 4 Nov 2017 00:24:09 +0000 Subject: [PATCH 372/505] use real time; wait random number of seconds --- apps/openmw/mwmechanics/character.cpp | 7 +++---- apps/openmw/mwmechanics/character.hpp | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c3ca8f512..dffc095e9 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -248,15 +248,14 @@ void CharacterController::refreshHitRecoilAnims() bool knockdown = mPtr.getClass().getCreatureStats(mPtr).getKnockedDown(); bool block = mPtr.getClass().getCreatureStats(mPtr).getBlock(); bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr); - MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor(); if(mHitState == CharState_None) { if ((mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0 || mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0) && mAnimation->hasAnimation("knockout")) { - mKnockoutTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + mTimeToWake = time(NULL); + mTimeToWake += rand() % 2 + 1; // Wake up after 1 to 3 seconds if (isSwimming && mAnimation->hasAnimation("swimknockout")) { mHitState = CharState_SwimKnockOut; @@ -342,7 +341,7 @@ void CharacterController::refreshHitRecoilAnims() mHitState = CharState_None; } else if (isKnockedOut() && mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() > 0 - && (currentTime - mKnockoutTime) > 3*timeScale/3600) //Wait 3 seconds before getting up + && time(NULL) > mTimeToWake) { mHitState = isSwimming ? CharState_SwimKnockDown : CharState_KnockDown; mAnimation->disable(mCurrentHit); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 0654b8534..af8415e35 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -197,7 +197,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener float mSecondsOfSwimming; float mSecondsOfRunning; - MWWorld::TimeStamp mKnockoutTime; + time_t mTimeToWake; MWWorld::ConstPtr mHeadTrackTarget; From bcbfa5fe1e97696a96794b0b55d3ec8b427a1212 Mon Sep 17 00:00:00 2001 From: rexelion Date: Sat, 4 Nov 2017 00:38:33 +0000 Subject: [PATCH 373/505] prevent activation, leave the rest to the script --- apps/openmw/mwgui/inventorywindow.cpp | 9 +++------ apps/openmw/mwworld/actiontake.cpp | 3 --- apps/openmw/mwworld/refdata.cpp | 5 ----- apps/openmw/mwworld/refdata.hpp | 2 -- 4 files changed, 3 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 1e9f534d6..063bc5c01 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -653,6 +653,9 @@ namespace MWGui if (object.getClass().getName(object) == "") // objects without name presented to user can never be picked up return; + if (!object.getRefData().activate()) + return; + int count = object.getRefData().getCount(); MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -663,12 +666,6 @@ namespace MWGui // add to player inventory // can't use ActionTake here because we need an MWWorld::Ptr to the newly inserted object MWWorld::Ptr newObject = *player.getClass().getContainerStore (player).add (object, object.getRefData().getCount(), player); - - if (object.getRefData().hasSuppressActivate()) // if Flag_SuppressActivate is set, script that contains OnActivate is attached to the item - { - newObject.getRefData().onActivate(); // set the flag_SuppressActivate flag for the new item - newObject.getRefData().activate(); - } // remove from world MWBase::Environment::get().getWorld()->deleteObject (object); diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index 52e30c8ac..d858859a6 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -14,9 +14,6 @@ namespace MWWorld void ActionTake::executeImp (const Ptr& actor) { - //No need to do anything if moving items from the player's inventory back into player's inventory - if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr() && getTarget().getCell() == 0) - return; MWBase::Environment::get().getMechanicsManager()->itemTaken( actor, getTarget(), MWWorld::Ptr(), getTarget().getRefData().getCount()); MWWorld::Ptr newitem = *actor.getClass().getContainerStore (actor).add (getTarget(), getTarget().getRefData().getCount(), actor); diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 95b0fb3e0..f6fa3556f 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -192,11 +192,6 @@ namespace MWWorld return mEnabled; } - bool RefData::hasSuppressActivate() - { - return mFlags & Flag_SuppressActivate; - } - void RefData::enable() { if (!mEnabled) diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 4dfa9e91c..75eec6742 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -111,8 +111,6 @@ namespace MWWorld bool isEnabled() const; - bool hasSuppressActivate(); - void enable(); void disable(); From 8c2cc0f42fa6b6e7717962a87a1d2c584460ca0b Mon Sep 17 00:00:00 2001 From: rexelion Date: Sat, 4 Nov 2017 00:44:16 +0000 Subject: [PATCH 374/505] break invisibility first --- apps/openmw/mwgui/inventorywindow.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 063bc5c01..e1301edd4 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -653,13 +653,13 @@ namespace MWGui if (object.getClass().getName(object) == "") // objects without name presented to user can never be picked up return; - if (!object.getRefData().activate()) - return; - int count = object.getRefData().getCount(); MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getWorld()->breakInvisibility(player); + + if (!object.getRefData().activate()) + return; MWBase::Environment::get().getMechanicsManager()->itemTaken(player, object, MWWorld::Ptr(), count); From ee2f3db9a87abf24341f4247b7748d5aa935ef6e Mon Sep 17 00:00:00 2001 From: rexelion Date: Sat, 4 Nov 2017 01:31:15 +0000 Subject: [PATCH 375/505] fixed randomness --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index dffc095e9..deb9daa93 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -255,7 +255,7 @@ void CharacterController::refreshHitRecoilAnims() && mAnimation->hasAnimation("knockout")) { mTimeToWake = time(NULL); - mTimeToWake += rand() % 2 + 1; // Wake up after 1 to 3 seconds + mTimeToWake += (int)( (float)rand() / (float)RAND_MAX * 2) + 1; // Wake up after 1 to 3 seconds if (isSwimming && mAnimation->hasAnimation("swimknockout")) { mHitState = CharState_SwimKnockOut; From ab66034ed17f045839f4fd16ac1fec4872e6afad Mon Sep 17 00:00:00 2001 From: rexelion Date: Sat, 4 Nov 2017 02:15:56 +0000 Subject: [PATCH 376/505] use uniform_int_distribution instead of rand() --- apps/openmw/mwmechanics/character.cpp | 6 +++++- apps/openmw/mwmechanics/character.hpp | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index deb9daa93..ade9d635b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -20,6 +20,7 @@ #include "character.hpp" #include +#include #include @@ -254,8 +255,11 @@ void CharacterController::refreshHitRecoilAnims() || mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0) && mAnimation->hasAnimation("knockout")) { + std::random_device r; + std::mt19937 gen(r()); + std::uniform_int_distribution dist(1, 3); mTimeToWake = time(NULL); - mTimeToWake += (int)( (float)rand() / (float)RAND_MAX * 2) + 1; // Wake up after 1 to 3 seconds + mTimeToWake += dist(gen); // Wake up after 1 to 3 seconds if (isSwimming && mAnimation->hasAnimation("swimknockout")) { mHitState = CharState_SwimKnockOut; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index af8415e35..12b4d6adc 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -7,7 +7,6 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwworld/timestamp.hpp" #include "../mwrender/animation.hpp" From f34223fce9ec847a5694825e32867294be1e326f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 2 Nov 2017 20:01:22 +0100 Subject: [PATCH 377/505] check the real distance to target in aipursue --- apps/openmw/mwmechanics/aipursue.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index f9884eb6d..835966467 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -50,8 +50,13 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte //Set the target desition from the actor ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos; + ESM::Position aPos = actor.getRefData().getPosition(); - if (pathTo(actor, dest, duration, 100)) { + float pathTolerance = 100.0; + + if (pathTo(actor, dest, duration, pathTolerance) && + MWMechanics::distance(dest,aPos.pos[0],aPos.pos[1],aPos.pos[2]) < pathTolerance) // check the true distance in case the target is far away in Z-direction + { target.getClass().activate(target,actor).get()->execute(actor); //Arrest player when reached return true; } From 48ec680f233f2ea616569e77872d757df7a488a0 Mon Sep 17 00:00:00 2001 From: rexelion Date: Sat, 4 Nov 2017 19:37:20 +0000 Subject: [PATCH 378/505] use game time instead of real time --- apps/openmw/mwmechanics/character.cpp | 17 ++++++++++------- apps/openmw/mwmechanics/character.hpp | 4 +++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ade9d635b..83d6cc1f3 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -20,7 +20,6 @@ #include "character.hpp" #include -#include #include @@ -243,6 +242,11 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i return prefix + toString(roll); } +void CharacterController::updateKnockoutTimer(float duration) +{ + mTimeUntilWake -= duration; +} + void CharacterController::refreshHitRecoilAnims() { bool recovery = mPtr.getClass().getCreatureStats(mPtr).getHitRecovery(); @@ -255,11 +259,7 @@ void CharacterController::refreshHitRecoilAnims() || mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0) && mAnimation->hasAnimation("knockout")) { - std::random_device r; - std::mt19937 gen(r()); - std::uniform_int_distribution dist(1, 3); - mTimeToWake = time(NULL); - mTimeToWake += dist(gen); // Wake up after 1 to 3 seconds + mTimeUntilWake = Misc::Rng::rollClosedProbability() * 2 + 1; // Wake up after 1 to 3 seconds if (isSwimming && mAnimation->hasAnimation("swimknockout")) { mHitState = CharState_SwimKnockOut; @@ -345,7 +345,7 @@ void CharacterController::refreshHitRecoilAnims() mHitState = CharState_None; } else if (isKnockedOut() && mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() > 0 - && time(NULL) > mTimeToWake) + && mTimeUntilWake <= 0) { mHitState = isSwimming ? CharState_SwimKnockDown : CharState_KnockDown; mAnimation->disable(mCurrentHit); @@ -1635,6 +1635,9 @@ void CharacterController::update(float duration) float speed = 0.f; updateMagicEffects(); + + if (isKnockedOut()) + updateKnockoutTimer(duration); bool godmode = mPtr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 12b4d6adc..0b9e60c11 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -196,7 +196,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener float mSecondsOfSwimming; float mSecondsOfRunning; - time_t mTimeToWake; + float mTimeUntilWake; MWWorld::ConstPtr mHeadTrackTarget; @@ -226,6 +226,8 @@ class CharacterController : public MWRender::Animation::TextKeyListener void updateMagicEffects(); + void updateKnockoutTimer(float duration); + void playDeath(float startpoint, CharacterState death); CharacterState chooseRandomDeathState() const; void playRandomDeath(float startpoint = 0.0f); From e3c42251f99744e30164d0a258a0b4cc82e3a4f7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 5 Nov 2017 15:36:26 +0000 Subject: [PATCH 379/505] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 839a04e42..c4190343d 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -129,6 +129,7 @@ Programmers Radu-Marius Popovici (rpopovici) Rafael Moura (dhustkoder) rdimesio + rexelion riothamus Rob Cutmore (rcutmore) Robert MacGregor (Ragora) From 282800b5b24b6ac9aa127031dfcec7a78e873bd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sun, 5 Nov 2017 16:37:38 +0100 Subject: [PATCH 380/505] Create LICENSE (#1532) * Create LICENSE Let's add the license file so that GitHub officially registers it and displays it next to the project. * move license files * update licenses in cmakelists.txt * fix link in README --- CMakeLists.txt | 6 +++--- docs/license/GPL3.txt => LICENSE | 6 +++--- README.md | 4 ++-- {docs/license => files/mygui}/DejaVu Font License.txt | 0 4 files changed, 8 insertions(+), 8 deletions(-) rename docs/license/GPL3.txt => LICENSE (99%) rename {docs/license => files/mygui}/DejaVu Font License.txt (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index b47678e7d..507c89c45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -412,7 +412,7 @@ IF(NOT WIN32 AND NOT APPLE) #ENDIF(BUILD_MYGUI_PLUGIN) # Install licenses - INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" ) + INSTALL(FILES "files/mygui/DejaVu Font License.txt" DESTINATION "${LICDIR}" ) # Install icon and desktop file INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw") @@ -446,9 +446,9 @@ if(WIN32) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/LICENSE" DESTINATION "." RENAME "LICENSE.txt") INSTALL(FILES - "${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt" - "${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt" + "${OpenMW_SOURCE_DIR}/files/mygui/DejaVu Font License.txt" "${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION ".") diff --git a/docs/license/GPL3.txt b/LICENSE similarity index 99% rename from docs/license/GPL3.txt rename to LICENSE index 94a9ed024..9cecc1d46 100644 --- a/docs/license/GPL3.txt +++ b/LICENSE @@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - - Copyright (C) + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - Copyright (C) + {project} Copyright (C) {year} {fullname} This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. diff --git a/README.md b/README.md index aa6ae47b4..3e5556cb4 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,12 @@ OpenMW is a recreation of the engine for the popular role-playing game Morrowind OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set. * Version: 0.42.0 -* License: GPLv3 (see [docs/license/GPL3.txt](https://github.com/OpenMW/openmw/blob/master/docs/license/GPL3.txt) for more information) +* License: GPLv3 (see [LICENSE](https://github.com/OpenMW/openmw/blob/master/LICENSE) for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net Font Licenses: -* DejaVuLGCSansMono.ttf: custom (see docs/license/DejaVu Font License.txt for more information) +* DejaVuLGCSansMono.ttf: custom (see [files/mygui/DejaVu Font License.txt](https://github.com/OpenMW/openmw/blob/master/files/mygui/DejaVu%20Font%20License.txt) for more information) Current Status -------------- diff --git a/docs/license/DejaVu Font License.txt b/files/mygui/DejaVu Font License.txt similarity index 100% rename from docs/license/DejaVu Font License.txt rename to files/mygui/DejaVu Font License.txt From de7a7d842bb6d90660c8da66c47ec30ec8091c06 Mon Sep 17 00:00:00 2001 From: rexelion Date: Sun, 5 Nov 2017 18:30:34 +0000 Subject: [PATCH 381/505] mTimeUntilWake is initialised in the constructor --- apps/openmw/mwmechanics/character.cpp | 8 ++------ apps/openmw/mwmechanics/character.hpp | 2 -- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 83d6cc1f3..0f99725fd 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -242,11 +242,6 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i return prefix + toString(roll); } -void CharacterController::updateKnockoutTimer(float duration) -{ - mTimeUntilWake -= duration; -} - void CharacterController::refreshHitRecoilAnims() { bool recovery = mPtr.getClass().getCreatureStats(mPtr).getHitRecovery(); @@ -766,6 +761,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mSecondsOfRunning(0) , mTurnAnimationThreshold(0) , mAttackingOrSpell(false) + , mTimeUntilWake(0.f) { if(!mAnimation) return; @@ -1637,7 +1633,7 @@ void CharacterController::update(float duration) updateMagicEffects(); if (isKnockedOut()) - updateKnockoutTimer(duration); + mTimeUntilWake -= duration; bool godmode = mPtr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 0b9e60c11..6de18fe62 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -226,8 +226,6 @@ class CharacterController : public MWRender::Animation::TextKeyListener void updateMagicEffects(); - void updateKnockoutTimer(float duration); - void playDeath(float startpoint, CharacterState death); CharacterState chooseRandomDeathState() const; void playRandomDeath(float startpoint = 0.0f); From 430d01a39a61342e11048c4c166692fbb2a1c64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sun, 5 Nov 2017 20:19:47 +0100 Subject: [PATCH 382/505] additional animation refactor --- apps/openmw/mwmechanics/character.cpp | 29 +++++++++++++-------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f262850a4..107ccf09b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -372,29 +372,28 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState } } - if(mJumpState == JumpState_InAir) + if (!mCurrentJump.empty()) { mAnimation->disable(mCurrentJump); - mCurrentJump = jumpAnimName; - if (mAnimation->hasAnimation("jump")) - mAnimation->play(mCurrentJump, Priority_Jump, jumpmask, false, + mCurrentJump.clear(); + } + + if(mJumpState == JumpState_InAir) + { + if (mAnimation->hasAnimation(jumpAnimName)) + { + mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, false, 1.0f, (startAtLoop?"loop start":"start"), "stop", 0.0f, ~0ul); + mCurrentJump = jumpAnimName; + } } else if (mJumpState == JumpState_Landing) { - if (startAtLoop) - mAnimation->disable(mCurrentJump); - - if (mAnimation->hasAnimation("jump")) + if (mAnimation->hasAnimation(jumpAnimName)) + { mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, true, 1.0f, "loop stop", "stop", 0.0f, 0); - } - else // JumpState_None - { - if (mCurrentJump.length() > 0) - { - mAnimation->disable(mCurrentJump); - mCurrentJump.clear(); + mCurrentJump = jumpAnimName; } } } From 7d39c5450ca099e2b61e0380c338241e2b7bdf39 Mon Sep 17 00:00:00 2001 From: Alexander Stillich Date: Sun, 5 Nov 2017 21:40:35 +0100 Subject: [PATCH 383/505] Fixed escaping @ in boost program options filter --- components/files/escape.cpp | 3 ++- components/files/escape.hpp | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/components/files/escape.cpp b/components/files/escape.cpp index f28870c70..3c3d04d51 100644 --- a/components/files/escape.cpp +++ b/components/files/escape.cpp @@ -27,7 +27,8 @@ namespace Files std::string EscapeHashString::processString(const std::string & str) { std::string temp = boost::replace_all_copy(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#"); - boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, std::string((char)escape_hash_filter::sEscape, 1)); + auto format = std::string(1, (char)escape_hash_filter::sEscape); + boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, format); return temp; } diff --git a/components/files/escape.hpp b/components/files/escape.hpp index 2017c2ed2..64410f3ab 100644 --- a/components/files/escape.hpp +++ b/components/files/escape.hpp @@ -78,6 +78,12 @@ namespace Files mFinishLine = true; } } + else if (character == sEscape) + { + mNext.push(sEscape); + mNext.push(sEscapeIdentifier); + record = false; + } else if (mPrevious == sEscape) { mNext.push(sEscape); From f98a821482e51b2c1bbb5a6c7c43393608dee2da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sun, 5 Nov 2017 23:46:15 +0100 Subject: [PATCH 384/505] fix possible bug in aipursue --- apps/openmw/mwmechanics/aipursue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index 835966467..27d4ab0cb 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -55,7 +55,7 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte float pathTolerance = 100.0; if (pathTo(actor, dest, duration, pathTolerance) && - MWMechanics::distance(dest,aPos.pos[0],aPos.pos[1],aPos.pos[2]) < pathTolerance) // check the true distance in case the target is far away in Z-direction + abs(dest.mZ - aPos.pos[2]) < pathTolerance) // check the true distance in case the target is far away in Z-direction { target.getClass().activate(target,actor).get()->execute(actor); //Arrest player when reached return true; From 492b99b008e677cee28181f88e756f3fb7481b24 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Tue, 7 Nov 2017 00:41:27 -0500 Subject: [PATCH 385/505] Transparent object markers --- apps/opencs/model/prefs/state.cpp | 1 + apps/opencs/view/render/object.cpp | 38 +++++++++++++++++++++++++----- apps/opencs/view/render/object.hpp | 7 ++++++ 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 1f84c5a87..2a40c4e18 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -191,6 +191,7 @@ void CSMPrefs::State::declare() setTooltip ("Acceleration factor during drag operations while holding down shift"). setRange (0.001, 100.0); declareDouble ("rotate-factor", "Free rotation factor", 0.007).setPrecision(4).setRange(0.0001, 0.1); + declareDouble ("object-marker-alpha", "Object Marker Transparency", 0.5).setPrecision(2).setRange(0,1); declareCategory ("Tooltips"); declareBool ("scene", "Show Tooltips in 3D scenes", true); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 522057097..d725f5dc9 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -285,15 +286,15 @@ osg::ref_ptr CSVRender::Object::makeMoveOrScaleMarker (int axis) for (int i=0; i<8; ++i) colours->push_back (osg::Vec4f (axis==0 ? 1.0f : 0.2f, axis==1 ? 1.0f : 0.2f, - axis==2 ? 1.0f : 0.2f, 1.0f)); + axis==2 ? 1.0f : 0.2f, mMarkerTransparency)); for (int i=8; i<8+4+1; ++i) colours->push_back (osg::Vec4f (axis==0 ? 1.0f : 0.0f, axis==1 ? 1.0f : 0.0f, - axis==2 ? 1.0f : 0.0f, 1.0f)); + axis==2 ? 1.0f : 0.0f, mMarkerTransparency)); geometry->setColorArray (colours, osg::Array::BIND_PER_VERTEX); - geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF); + setupCommonMarkerState(geometry); osg::ref_ptr geode (new osg::Geode); geode->addDrawable (geometry); @@ -350,7 +351,11 @@ osg::ref_ptr CSVRender::Object::makeRotateMarker (int axis) vertices->at(index++) = getMarkerPosition(outerX, outerY, -MarkerShaftWidth / 2, axis); } - colors->at(0) = osg::Vec4f (axis==0 ? 1.0f : 0.2f, axis==1 ? 1.0f : 0.2f, axis==2 ? 1.0f : 0.2f, 1.0f); + colors->at(0) = osg::Vec4f ( + axis==0 ? 1.0f : 0.2f, + axis==1 ? 1.0f : 0.2f, + axis==2 ? 1.0f : 0.2f, + mMarkerTransparency); for (size_t i = 0; i < SegmentCount; ++i) { @@ -374,7 +379,7 @@ osg::ref_ptr CSVRender::Object::makeRotateMarker (int axis) geometry->setColorArray(colors, osg::Array::BIND_OVERALL); geometry->addPrimitiveSet(primitives); - geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF); + setupCommonMarkerState(geometry); osg::ref_ptr geode = new osg::Geode(); geode->addDrawable (geometry); @@ -382,6 +387,21 @@ osg::ref_ptr CSVRender::Object::makeRotateMarker (int axis) return geode; } +void CSVRender::Object::setupCommonMarkerState(osg::ref_ptr geometry) +{ + const int RenderBin = osg::StateSet::TRANSPARENT_BIN - 1; + + osg::ref_ptr state = geometry->getOrCreateStateSet(); + state->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + state->setMode(GL_BLEND, osg::StateAttribute::ON); + + osg::ref_ptr depth(new osg::Depth); + depth->setWriteMask(false); + state->setAttributeAndModes(depth, osg::StateAttribute::ON); + + state->setRenderBinDetails(RenderBin, "RenderBin"); +} + osg::Vec3f CSVRender::Object::getMarkerPosition (float x, float y, float z, int axis) { switch (axis) @@ -399,7 +419,7 @@ osg::Vec3f CSVRender::Object::getMarkerPosition (float x, float y, float z, int CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode, const std::string& id, bool referenceable, bool forceBaseToZero) : mData (data), mBaseNode(0), mSelected(false), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero), - mScaleOverride (1), mOverrideFlags (0), mSubMode (-1) + mScaleOverride (1), mOverrideFlags (0), mSubMode (-1), mMarkerTransparency(0.5f) { mRootNode = new osg::PositionAttitudeTransform; @@ -629,6 +649,12 @@ void CSVRender::Object::setScale (float scale) adjustTransform(); } +void CSVRender::Object::setMarkerTransparency(float value) +{ + mMarkerTransparency = value; + updateMarker(); +} + void CSVRender::Object::apply (CSMWorld::CommandMacro& commands) { const CSMWorld::RefCollection& collection = mData.getReferences(); diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index e14697e62..3e54093d3 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -96,6 +97,7 @@ namespace CSVRender int mOverrideFlags; osg::ref_ptr mMarker[3]; int mSubMode; + float mMarkerTransparency; /// Not implemented Object (const Object&); @@ -121,6 +123,9 @@ namespace CSVRender osg::ref_ptr makeMoveOrScaleMarker (int axis); osg::ref_ptr makeRotateMarker (int axis); + /// Sets up a stateset with properties common to all marker types. + void setupCommonMarkerState(osg::ref_ptr geometry); + osg::Vec3f getMarkerPosition (float x, float y, float z, int axis); public: @@ -179,6 +184,8 @@ namespace CSVRender /// Set override scale void setScale (float scale); + void setMarkerTransparency(float value); + /// Apply override changes via command and end edit mode void apply (CSMWorld::CommandMacro& commands); From a1d9f11b04dbff794889d816ee4bb31fab05bb32 Mon Sep 17 00:00:00 2001 From: rexelion Date: Tue, 7 Nov 2017 11:43:21 +0000 Subject: [PATCH 386/505] use fProjectileMaxSpeed for ranged weapons distance --- apps/openmw/mwmechanics/aicombataction.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index d44498966..df636dd56 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -115,6 +115,7 @@ namespace MWMechanics isRanged = false; static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get().find("fCombatDistance")->getFloat(); + static const float fProjectileMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get().find("fProjectileMaxSpeed")->getFloat(); if (mWeapon.isEmpty()) { @@ -128,7 +129,7 @@ namespace MWMechanics if (weapon->mData.mType >= ESM::Weapon::MarksmanBow) { isRanged = true; - return 1000.f; + return fProjectileMaxSpeed; } else return weapon->mData.mReach * fCombatDistance; From cab00024615730360fba3f66fc2cfb058acabea3 Mon Sep 17 00:00:00 2001 From: rexelion Date: Tue, 7 Nov 2017 17:57:23 +0000 Subject: [PATCH 387/505] Backing up distance is now dependent on opponents's weapon range; don't back up from ranged oponents --- apps/openmw/mwmechanics/aicombat.cpp | 49 ++++++++++++++-------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 68d282d0c..cd9211a3f 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -490,6 +490,28 @@ namespace MWMechanics void AiCombatStorage::startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target) { + // get the range of the target's weapon + float rangeAttackOfTarget = 0.f; + MWWorld::Ptr targetWeapon = MWWorld::Ptr(); + const MWWorld::Class& targetClass = target.getClass(); + + if (targetClass.hasInventoryStore(target)) + { + MWMechanics::WeaponType weapType = WeapType_None; + MWWorld::ContainerStoreIterator weaponSlot = + MWMechanics::getActiveWeapon(targetClass.getCreatureStats(target), targetClass.getInventoryStore(target), &weapType); + if (weapType != WeapType_PickProbe && weapType != WeapType_Spell && weapType != WeapType_None && weapType != WeapType_HandToHand) + targetWeapon = *weaponSlot; + } + + std::shared_ptr targetWeaponAction(new ActionWeapon(targetWeapon)); + + bool isRangedCombat = false; + if (targetWeaponAction.get()) + { + rangeAttackOfTarget = targetWeaponAction->getCombatRange(isRangedCombat); + } + if (mMovement.mPosition[0] || mMovement.mPosition[1]) { mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); @@ -498,28 +520,6 @@ namespace MWMechanics // dodge movements (for NPCs and bipedal creatures) else if (actor.getClass().isBipedal(actor)) { - // get the range of the target's weapon - float rangeAttackOfTarget = 0.f; - MWWorld::Ptr targetWeapon = MWWorld::Ptr(); - const MWWorld::Class& targetClass = target.getClass(); - - if (targetClass.hasInventoryStore(target)) - { - MWMechanics::WeaponType weapType = WeapType_None; - MWWorld::ContainerStoreIterator weaponSlot = - MWMechanics::getActiveWeapon(targetClass.getCreatureStats(target), targetClass.getInventoryStore(target), &weapType); - if (weapType != WeapType_PickProbe && weapType != WeapType_Spell && weapType != WeapType_None && weapType != WeapType_HandToHand) - targetWeapon = *weaponSlot; - } - - std::shared_ptr targetWeaponAction (new ActionWeapon(targetWeapon)); - - if (targetWeaponAction.get()) - { - bool isRangedCombat = false; - rangeAttackOfTarget = targetWeaponAction->getCombatRange(isRangedCombat); - } - // apply sideway movement (kind of dodging) with some probability // if actor is within range of target's weapon if (distToTarget <= rangeAttackOfTarget && Misc::Rng::rollClosedProbability() < 0.25) @@ -533,13 +533,14 @@ namespace MWMechanics // Below behavior for backing up during ranged combat differs from vanilla. // Vanilla is observed as backing up only as far as fCombatDistance or // opponent's weapon range, or not backing up if opponent is also using a ranged weapon - if (isDistantCombat && distToTarget < rangeAttack / 4) + if (isDistantCombat) { // actor should not back up into water if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.5f)) return; - mMovement.mPosition[1] = -1; + if (!isRangedCombat && distToTarget <= rangeAttackOfTarget*1.5) // Don't back up if the target is wielding ranged weapon + mMovement.mPosition[1] = -1; } } From af3e1f92ec71df8b3a10f638f9a7d6b18fa474d6 Mon Sep 17 00:00:00 2001 From: Alexander Stillich Date: Tue, 7 Nov 2017 22:16:59 +0100 Subject: [PATCH 388/505] Added StringUtil::replaceAll() --- components/misc/stringops.hpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 9acd81710..12c222036 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -2,6 +2,7 @@ #define MISC_STRINGOPS_H #include +#include #include #include @@ -138,6 +139,35 @@ public: return notFound; } + + /** @brief Replaces all occurrences of a string in another string. + * + * @param str The string to operate on. + * @param what The string to replace. + * @param with The replacement string. + * @param what_len The length of the string to replace. + * @param with_len The length of the replacement string. + * + * @return A reference to the string passed in @p str. + */ + static std::string &replaceAll(std::string &str, const char *what, const char *with, + std::size_t what_len=std::string::npos, std::size_t with_len=std::string::npos) + { + if (what_len == std::string::npos) + what_len = strlen(what); + + if (with_len == std::string::npos) + with_len = strlen(with); + + std::size_t found; + std::size_t offset = 0; + while((found = str.find(what, offset, what_len)) != std::string::npos) + { + str.replace(found, what_len, with, with_len); + offset = found + with_len; + } + return str; + } }; } From 70d578d050ea9e26cf14064ee0e2bb62a051ceae Mon Sep 17 00:00:00 2001 From: Alexander Stillich Date: Tue, 7 Nov 2017 23:10:58 +0100 Subject: [PATCH 389/505] Removed escape_hash_filter::mPrevious, removed usage of boost::replace_all --- components/files/escape.cpp | 15 ++++++++++----- components/files/escape.hpp | 11 ----------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/components/files/escape.cpp b/components/files/escape.cpp index 3c3d04d51..93ae9b885 100644 --- a/components/files/escape.cpp +++ b/components/files/escape.cpp @@ -1,6 +1,6 @@ #include "escape.hpp" -#include +#include namespace Files { @@ -8,7 +8,7 @@ namespace Files const int escape_hash_filter::sEscapeIdentifier = 'a'; const int escape_hash_filter::sHashIdentifier = 'h'; - escape_hash_filter::escape_hash_filter() : mNext(), mPrevious(), mSeenNonWhitespace(false), mFinishLine(false) + escape_hash_filter::escape_hash_filter() : mSeenNonWhitespace(false), mFinishLine(false) { } @@ -26,9 +26,14 @@ namespace Files std::string EscapeHashString::processString(const std::string & str) { - std::string temp = boost::replace_all_copy(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#"); - auto format = std::string(1, (char)escape_hash_filter::sEscape); - boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, format); + std::string temp = str; + + static const char hash[] = { escape_hash_filter::sEscape, escape_hash_filter::sHashIdentifier }; + Misc::StringUtils::replaceAll(temp, hash, "#", 2, 1); + + static const char escape[] = { escape_hash_filter::sEscape, escape_hash_filter::sEscapeIdentifier }; + Misc::StringUtils::replaceAll(temp, escape, "@", 2, 1); + return temp; } diff --git a/components/files/escape.hpp b/components/files/escape.hpp index 64410f3ab..d01bd8d98 100644 --- a/components/files/escape.hpp +++ b/components/files/escape.hpp @@ -30,7 +30,6 @@ namespace Files private: std::queue mNext; - int mPrevious; bool mSeenNonWhitespace; bool mFinishLine; @@ -42,11 +41,9 @@ namespace Files if (mNext.empty()) { int character = boost::iostreams::get(src); - bool record = true; if (character == boost::iostreams::WOULD_BLOCK) { mNext.push(character); - record = false; } else if (character == EOF) { @@ -79,12 +76,6 @@ namespace Files } } else if (character == sEscape) - { - mNext.push(sEscape); - mNext.push(sEscapeIdentifier); - record = false; - } - else if (mPrevious == sEscape) { mNext.push(sEscape); mNext.push(sEscapeIdentifier); @@ -95,8 +86,6 @@ namespace Files } if (!mSeenNonWhitespace && !isspace(character)) mSeenNonWhitespace = true; - if (record) - mPrevious = character; } int retval = mNext.front(); mNext.pop(); From 43b5c2e36bc19db88f391f6a40429be4cf25c3a0 Mon Sep 17 00:00:00 2001 From: Alexander Stillich Date: Tue, 7 Nov 2017 23:20:10 +0100 Subject: [PATCH 390/505] Fixed parameter naming --- components/misc/stringops.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 12c222036..9f4931d72 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -145,26 +145,26 @@ public: * @param str The string to operate on. * @param what The string to replace. * @param with The replacement string. - * @param what_len The length of the string to replace. - * @param with_len The length of the replacement string. + * @param whatLen The length of the string to replace. + * @param withLen The length of the replacement string. * * @return A reference to the string passed in @p str. */ static std::string &replaceAll(std::string &str, const char *what, const char *with, - std::size_t what_len=std::string::npos, std::size_t with_len=std::string::npos) + std::size_t whatLen=std::string::npos, std::size_t withLen=std::string::npos) { - if (what_len == std::string::npos) - what_len = strlen(what); + if (whatLen == std::string::npos) + whatLen = strlen(what); - if (with_len == std::string::npos) - with_len = strlen(with); + if (withLen == std::string::npos) + withLen = strlen(with); std::size_t found; std::size_t offset = 0; - while((found = str.find(what, offset, what_len)) != std::string::npos) + while((found = str.find(what, offset, whatLen)) != std::string::npos) { - str.replace(found, what_len, with, with_len); - offset = found + with_len; + str.replace(found, whatLen, with, withLen); + offset = found + withLen; } return str; } From 7b4add2ae4b83aaad977c63e53322f7ed0055ce7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 7 Nov 2017 23:44:38 +0100 Subject: [PATCH 391/505] Fall back to non-shader material if creating the shader fails Also fixes an uncaught exception that will break the whole game. --- components/terrain/material.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 8aec54835..640f2932b 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -116,7 +116,10 @@ namespace Terrain osg::ref_ptr vertexShader = shaderManager->getShader("terrain_vertex.glsl", defineMap, osg::Shader::VERTEX); osg::ref_ptr fragmentShader = shaderManager->getShader("terrain_fragment.glsl", defineMap, osg::Shader::FRAGMENT); if (!vertexShader || !fragmentShader) - throw std::runtime_error("Unable to create shader"); + { + // Try again without shader. Error already logged by above + return createPasses(false, forcePerPixelLighting, clampLighting, shaderManager, layers, blendmaps, blendmapScale, layerTileSize); + } stateset->setAttributeAndModes(shaderManager->getProgram(vertexShader, fragmentShader)); } From 244cc5b861c58f284b01f071400cd47254006014 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 7 Nov 2017 23:54:31 +0100 Subject: [PATCH 392/505] Reduce error spam --- components/shader/shadermanager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 7cb49c6cb..5efd1b86e 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -131,7 +131,11 @@ namespace Shader { std::string shaderSource = templateIt->second; if (!parseDefines(shaderSource, defines)) + { + // Add to the cache anyway to avoid logging the same error over and over. + mShaders.insert(std::make_pair(std::make_pair(shaderTemplate, defines), nullptr)); return NULL; + } osg::ref_ptr shader (new osg::Shader(shaderType)); shader->setShaderSource(shaderSource); From e42bd71081010b5c5484b54ed4fc811e7ccf13fe Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 8 Nov 2017 00:03:02 +0100 Subject: [PATCH 393/505] Add missing WaitDialog::clear() (Fixes #4196) --- apps/openmw/mwgui/waitdialog.cpp | 6 ++++++ apps/openmw/mwgui/waitdialog.hpp | 2 ++ 2 files changed, 8 insertions(+) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index a7ad687cb..61febf315 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -96,6 +96,12 @@ namespace MWGui return (!mTimeAdvancer.isRunning()); //Only exit if not currently waiting } + void WaitDialog::clear() + { + mSleeping = false; + mTimeAdvancer.stop(); + } + void WaitDialog::onOpen() { if (mTimeAdvancer.isRunning()) diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index eb6a55640..2aecb002f 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -33,6 +33,8 @@ namespace MWGui virtual bool exit(); + virtual void clear(); + void onFrame(float dt); bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } From 95b3c1181a873ac9b5f3269e950a6ea17c4b732d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 8 Nov 2017 00:53:06 +0100 Subject: [PATCH 394/505] Update shader with a non-color tracking material when equipment is changed during chameleon/invisibility effects (Fixes #4190) --- apps/openmw/mwrender/npcanimation.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 8211c2f5f..ece57c273 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -388,9 +388,6 @@ void NpcAnimation::rebuild() { updateNpcBase(); - if (mAlpha != 1.f) - mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); - MWBase::Environment::get().getMechanicsManager()->forceStateUpdate(mPtr); } @@ -651,6 +648,9 @@ void NpcAnimation::updateParts() if (wasArrowAttached) attachArrow(); + + if (mAlpha != 1.f) + mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); } @@ -917,6 +917,8 @@ void NpcAnimation::showWeapons(bool showWeapon) attachArrow(); } } + if (mAlpha != 1.f) + mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); } else { @@ -942,6 +944,8 @@ void NpcAnimation::showCarriedLeft(bool show) if (iter->getTypeName() == typeid(ESM::Light).name() && mObjectParts[ESM::PRT_Shield]) addExtraLight(mObjectParts[ESM::PRT_Shield]->getNode()->asGroup(), iter->get()->mBase); } + if (mAlpha != 1.f) + mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); } else removeIndividualPart(ESM::PRT_Shield); From 9ecdcc187f76028bfa9c2a26d53345cb89b16dc5 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 8 Nov 2017 01:08:26 +0100 Subject: [PATCH 395/505] Clarify a warning message refers to inventory objects --- apps/openmw/mwworld/containerstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index cd04a425b..981f63e34 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -806,7 +806,7 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& inventory) case ESM::REC_WEAP: readEquipmentState (getState (weapons, state), thisIndex, inventory); break; case ESM::REC_LIGH: readEquipmentState (getState (lights, state), thisIndex, inventory); break; case 0: - std::cerr << "Warning: Dropping reference to '" << state.mRef.mRefID << "' (object no longer exists)" << std::endl; + std::cerr << "Dropping inventory reference to '" << state.mRef.mRefID << "' (object no longer exists)" << std::endl; break; default: std::cerr << "Warning: Invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; From 41ecbdbe6c47b54c34854d59bbe8f0fc5c936444 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 8 Nov 2017 00:03:02 +0100 Subject: [PATCH 396/505] Add missing WaitDialog::clear() (Fixes #4196) --- apps/openmw/mwgui/waitdialog.cpp | 6 ++++++ apps/openmw/mwgui/waitdialog.hpp | 2 ++ 2 files changed, 8 insertions(+) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index a7ad687cb..61febf315 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -96,6 +96,12 @@ namespace MWGui return (!mTimeAdvancer.isRunning()); //Only exit if not currently waiting } + void WaitDialog::clear() + { + mSleeping = false; + mTimeAdvancer.stop(); + } + void WaitDialog::onOpen() { if (mTimeAdvancer.isRunning()) diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index eb6a55640..2aecb002f 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -33,6 +33,8 @@ namespace MWGui virtual bool exit(); + virtual void clear(); + void onFrame(float dt); bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } From 983c33c4c89209ef6679743cd9f17654d4265eb4 Mon Sep 17 00:00:00 2001 From: rexelion Date: Thu, 9 Nov 2017 14:23:26 +0000 Subject: [PATCH 397/505] don't use a pointer for ActionWeapon --- apps/openmw/mwmechanics/aicombat.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index cd9211a3f..6e3268831 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -504,13 +504,8 @@ namespace MWMechanics targetWeapon = *weaponSlot; } - std::shared_ptr targetWeaponAction(new ActionWeapon(targetWeapon)); - bool isRangedCombat = false; - if (targetWeaponAction.get()) - { - rangeAttackOfTarget = targetWeaponAction->getCombatRange(isRangedCombat); - } + rangeAttackOfTarget = ActionWeapon(targetWeapon).getCombatRange(isRangedCombat); if (mMovement.mPosition[0] || mMovement.mPosition[1]) { From 197ea9564663006100606b74f9c87a499a7a6ba4 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Thu, 9 Nov 2017 13:04:46 -0500 Subject: [PATCH 398/505] Prevent arrows for move/scale markers from intersecting. --- apps/opencs/view/render/object.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index d725f5dc9..0ed7830f3 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -221,7 +221,7 @@ osg::ref_ptr CSVRender::Object::makeMoveOrScaleMarker (int axis) for (int i=0; i<2; ++i) { - float length = i ? shaftLength : 0; + float length = i ? shaftLength : MarkerShaftWidth; vertices->push_back (getMarkerPosition (-MarkerShaftWidth/2, -MarkerShaftWidth/2, length, axis)); vertices->push_back (getMarkerPosition (-MarkerShaftWidth/2, MarkerShaftWidth/2, length, axis)); From de214db8d46c97349fa81d01bd3489ac04d5ae51 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Thu, 9 Nov 2017 13:45:32 -0500 Subject: [PATCH 399/505] Use configured transparency. --- apps/opencs/view/render/object.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 0ed7830f3..a3ecbadeb 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -22,6 +22,7 @@ #include "../../model/world/universalid.hpp" #include "../../model/world/commandmacro.hpp" #include "../../model/world/cellcoordinates.hpp" +#include "../../model/prefs/state.hpp" #include #include @@ -473,6 +474,7 @@ void CSVRender::Object::setSelected(bool selected) else mRootNode->addChild(mBaseNode); + mMarkerTransparency = CSMPrefs::get()["3D Scene Input"]["object-marker-alpha"].toDouble(); updateMarker(); } From 556117f6e6b6e51d89cc0681abcb45bbaed3497b Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 10 Nov 2017 01:56:06 -0500 Subject: [PATCH 400/505] Update marker transparency when changed. --- apps/opencs/view/render/worldspacewidget.cpp | 14 ++++++++++++++ apps/opencs/view/render/worldspacewidget.hpp | 1 + 2 files changed, 15 insertions(+) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 325fa5f6d..a80a61a79 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -51,6 +51,7 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg , mToolTipPos (-1, -1) , mShowToolTips(false) , mToolTipDelay(0) + , mInConstructor(true) { setAcceptDrops(true); @@ -114,6 +115,8 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg CSMPrefs::Shortcut* abortShortcut = new CSMPrefs::Shortcut("scene-edit-abort", this); connect(abortShortcut, SIGNAL(activated()), this, SLOT(abortDrag())); + + mInConstructor = false; } CSVRender::WorldspaceWidget::~WorldspaceWidget () @@ -128,6 +131,17 @@ void CSVRender::WorldspaceWidget::settingChanged (const CSMPrefs::Setting *setti mDragWheelFactor = setting->toDouble(); else if (*setting=="3D Scene Input/drag-shift-factor") mDragShiftFactor = setting->toDouble(); + else if (*setting=="3D Scene Input/object-marker-alpha" && !mInConstructor) + { + float alpha = setting->toDouble(); + // getSelection is virtual, thus this can not be called from the constructor + auto selection = getSelection(Mask_Reference); + for (osg::ref_ptr tag : selection) + { + if (auto objTag = dynamic_cast(tag.get())) + objTag->mObject->setMarkerTransparency(alpha); + } + } else if (*setting=="Tooltips/scene-delay") mToolTipDelay = setting->toInt(); else if (*setting=="Tooltips/scene") diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 08b97e1be..9160ca47e 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -65,6 +65,7 @@ namespace CSVRender QPoint mToolTipPos; bool mShowToolTips; int mToolTipDelay; + bool mInConstructor; public: From 3604b73d6016aaa62808e888e47c2da27d4c109c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 4 Oct 2017 21:25:22 +0400 Subject: [PATCH 401/505] Move onTakeItem() to item models --- apps/openmw/mwgui/container.cpp | 33 +++-------------------- apps/openmw/mwgui/containeritemmodel.cpp | 24 +++++++++++++++-- apps/openmw/mwgui/containeritemmodel.hpp | 1 + apps/openmw/mwgui/inventoryitemmodel.cpp | 15 +++++++++++ apps/openmw/mwgui/inventoryitemmodel.hpp | 1 + apps/openmw/mwgui/itemmodel.cpp | 9 +++++++ apps/openmw/mwgui/itemmodel.hpp | 2 ++ apps/openmw/mwgui/pickpocketitemmodel.cpp | 29 ++++++++++++++++++-- apps/openmw/mwgui/pickpocketitemmodel.hpp | 4 +++ apps/openmw/mwgui/sortfilteritemmodel.cpp | 4 +++ apps/openmw/mwgui/sortfilteritemmodel.hpp | 2 ++ 11 files changed, 91 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 74ed4fff9..be3cb1522 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -8,13 +8,13 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwmechanics/pickpocket.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "countdialog.hpp" #include "inventorywindow.hpp" @@ -142,8 +142,7 @@ namespace MWGui if (mPtr.getClass().isNpc() && !loot) { // we are stealing stuff - MWWorld::Ptr player = MWMechanics::getPlayer(); - mModel = new PickpocketItemModel(player, new InventoryItemModel(container), + mModel = new PickpocketItemModel(mPtr, new InventoryItemModel(container), !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown()); } else @@ -271,32 +270,8 @@ namespace MWGui bool ContainerWindow::onTakeItem(const ItemStack &item, int count) { - MWWorld::Ptr player = MWMechanics::getPlayer(); - // TODO: move to ItemModels - if (dynamic_cast(mModel) - && !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown()) - { - MWMechanics::Pickpocket pickpocket(player, mPtr); - if (pickpocket.pick(item.mBase, count)) - { - MWBase::Environment::get().getMechanicsManager()->commitCrime( - player, mPtr, MWBase::MechanicsManager::OT_Pickpocket, 0, true); - MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); - mPickpocketDetected = true; - return false; - } - else - player.getClass().skillUsageSucceeded(player, ESM::Skill::Sneak, 1); - } - else - { - // Looting a dead corpse is considered OK - if (mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead()) - return true; - else - MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, mPtr, count); - } - return true; + // TODO: mPickpocketDetected = true; + return mModel->onTakeItem(item.mBase, count); } } diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index 479638672..ee89f1350 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -2,12 +2,15 @@ #include +#include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwmechanics/actorutil.hpp" @@ -183,4 +186,21 @@ void ContainerItemModel::update() } } +bool ContainerItemModel::onTakeItem(const MWWorld::Ptr &item, int count) +{ + if (mItemSources.empty()) + return false; + + MWWorld::Ptr target = mItemSources[0]; + + // Looting a dead corpse is considered OK + if (target.getClass().isActor() && target.getClass().getCreatureStats(target).isDead()) + return true; + + MWWorld::Ptr player = MWMechanics::getPlayer(); + MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item, target, count); + + return true; +} + } diff --git a/apps/openmw/mwgui/containeritemmodel.hpp b/apps/openmw/mwgui/containeritemmodel.hpp index c6ecafd46..a0dbc2cf9 100644 --- a/apps/openmw/mwgui/containeritemmodel.hpp +++ b/apps/openmw/mwgui/containeritemmodel.hpp @@ -26,6 +26,7 @@ namespace MWGui virtual void removeItem (const ItemStack& item, size_t count); virtual void update(); + virtual bool onTakeItem(const MWWorld::Ptr &item, int count); private: std::vector mItemSources; diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index 222243ec1..b807a58f4 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -9,6 +9,9 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" + namespace MWGui { @@ -116,4 +119,16 @@ void InventoryItemModel::update() } } +bool InventoryItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const +{ + // Looting a dead corpse is considered OK + if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead()) + return true; + + MWWorld::Ptr player = MWMechanics::getPlayer(); + MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item, mActor, count); + + return true; +} + } diff --git a/apps/openmw/mwgui/inventoryitemmodel.hpp b/apps/openmw/mwgui/inventoryitemmodel.hpp index f58ee2939..95afeb5d4 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.hpp +++ b/apps/openmw/mwgui/inventoryitemmodel.hpp @@ -22,6 +22,7 @@ namespace MWGui virtual MWWorld::Ptr moveItem (const ItemStack& item, size_t count, ItemModel* otherModel); virtual void update(); + virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; protected: MWWorld::Ptr mActor; diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index ffcf9075e..5a6afdf02 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -129,6 +129,11 @@ namespace MWGui return true; } + bool ItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + { + return true; + } + ProxyItemModel::ProxyItemModel() : mSourceModel(NULL) @@ -198,4 +203,8 @@ namespace MWGui mSourceModel = sourceModel; } + bool ProxyItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + { + return mSourceModel->onTakeItem (item, count); + } } diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index bc6be8023..c4a3a03e8 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -75,6 +75,7 @@ namespace MWGui /// Is the player allowed to insert items into this model? (default true) virtual bool allowedToInsertItems() const; + virtual bool onTakeItem(const MWWorld::Ptr &item, int count); private: ItemModel(const ItemModel&); @@ -94,6 +95,7 @@ namespace MWGui virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); virtual ModelIndex getIndex (ItemStack item); + virtual bool onTakeItem(const MWWorld::Ptr &item, int count); /// @note Takes ownership of the passed pointer. void setSourceModel(ItemModel* sourceModel); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index ec4b378a0..e610854c1 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -3,15 +3,24 @@ #include #include +#include "../mwmechanics/actorutil.hpp" +#include "../mwmechanics/pickpocket.hpp" + #include "../mwworld/class.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" + namespace MWGui { - PickpocketItemModel::PickpocketItemModel(const MWWorld::Ptr& thief, ItemModel *sourceModel, bool hideItems) + PickpocketItemModel::PickpocketItemModel(const MWWorld::Ptr& actor, ItemModel *sourceModel, bool hideItems) + : mActor(actor) { + MWWorld::Ptr player = MWMechanics::getPlayer(); mSourceModel = sourceModel; - int chance = thief.getClass().getSkill(thief, ESM::Skill::Sneak); + int chance = player.getClass().getSkill(player, ESM::Skill::Sneak); mSourceModel->update(); @@ -75,4 +84,20 @@ namespace MWGui return false; } + bool PickpocketItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const + { + MWWorld::Ptr player = MWMechanics::getPlayer(); + MWMechanics::Pickpocket pickpocket(player, mActor); + if (pickpocket.pick(item, count)) + { + MWBase::Environment::get().getMechanicsManager()->commitCrime( + player, mActor, MWBase::MechanicsManager::OT_Pickpocket, 0, true); + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); + return false; + } + else + player.getClass().skillUsageSucceeded(player, ESM::Skill::Sneak, 1); + + return true; + } } diff --git a/apps/openmw/mwgui/pickpocketitemmodel.hpp b/apps/openmw/mwgui/pickpocketitemmodel.hpp index 1b08ec485..ad8788da7 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.hpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.hpp @@ -18,6 +18,10 @@ namespace MWGui virtual void update(); virtual void removeItem (const ItemStack& item, size_t count); virtual bool allowedToInsertItems() const; + virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + + protected: + MWWorld::Ptr mActor; private: std::vector mHiddenItems; diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index e294ebe07..932f362fb 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -311,4 +311,8 @@ namespace MWGui std::sort(mItems.begin(), mItems.end(), cmp); } + bool SortFilterItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + { + return mSourceModel->onTakeItem (item, count); + } } diff --git a/apps/openmw/mwgui/sortfilteritemmodel.hpp b/apps/openmw/mwgui/sortfilteritemmodel.hpp index 6ddb019b0..e99726b0f 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.hpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.hpp @@ -29,6 +29,8 @@ namespace MWGui /// Use ItemStack::Type for sorting? void setSortByType(bool sort) { mSortByType = sort; } + bool onTakeItem(const MWWorld::Ptr &item, int count); + static const int Category_Weapon = (1<<1); static const int Category_Apparel = (1<<2); static const int Category_Misc = (1<<3); From ac33ff94827188d2623a042120ad51874ae7253b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 4 Oct 2017 22:37:08 +0400 Subject: [PATCH 402/505] Move onDropItem() check to item models --- apps/openmw/mwgui/container.cpp | 24 ++-------------- apps/openmw/mwgui/containeritemmodel.cpp | 34 +++++++++++++++++++++-- apps/openmw/mwgui/containeritemmodel.hpp | 5 +++- apps/openmw/mwgui/inventoryitemmodel.cpp | 2 +- apps/openmw/mwgui/inventoryitemmodel.hpp | 3 +- apps/openmw/mwgui/itemmodel.cpp | 14 ++++++++-- apps/openmw/mwgui/itemmodel.hpp | 7 +++-- apps/openmw/mwgui/pickpocketitemmodel.cpp | 12 +++++++- apps/openmw/mwgui/pickpocketitemmodel.hpp | 1 + apps/openmw/mwgui/sortfilteritemmodel.cpp | 7 ++++- apps/openmw/mwgui/sortfilteritemmodel.hpp | 3 +- 11 files changed, 79 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index be3cb1522..3fa07b070 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -100,28 +100,10 @@ namespace MWGui void ContainerWindow::dropItem() { - if (mPtr.getTypeName() == typeid(ESM::Container).name()) - { - // check container organic flag - MWWorld::LiveCellRef* ref = mPtr.get(); - if (ref->mBase->mFlags & ESM::Container::Organic) - { - MWBase::Environment::get().getWindowManager()-> - messageBox("#{sContentsMessage2}"); - return; - } - - // check that we don't exceed container capacity - MWWorld::Ptr item = mDragAndDrop->mItem.mBase; - float weight = item.getClass().getWeight(item) * mDragAndDrop->mDraggedCount; - if (mPtr.getClass().getCapacity(mPtr) < mPtr.getClass().getEncumbrance(mPtr) + weight) - { - MWBase::Environment::get().getWindowManager()->messageBox("#{sContentsMessage3}"); - return; - } - } + bool success = mModel->onDropItem(mDragAndDrop->mItem.mBase, mDragAndDrop->mDraggedCount); - mDragAndDrop->drop(mModel, mItemView); + if (success) + mDragAndDrop->drop(mModel, mItemView); } void ContainerWindow::onBackgroundSelected() diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index ee89f1350..ef7aa8215 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -10,6 +10,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwmechanics/actorutil.hpp" @@ -185,8 +186,37 @@ void ContainerItemModel::update() } } } +bool ContainerItemModel::onDropItem(const MWWorld::Ptr &item, int count) const +{ + if (mItemSources.empty()) + return false; + + MWWorld::Ptr target = mItemSources[0]; -bool ContainerItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + if (target.getTypeName() != typeid(ESM::Container).name()) + return true; + + // check container organic flag + MWWorld::LiveCellRef* ref = target.get(); + if (ref->mBase->mFlags & ESM::Container::Organic) + { + MWBase::Environment::get().getWindowManager()-> + messageBox("#{sContentsMessage2}"); + return false; + } + + // check that we don't exceed container capacity + float weight = item.getClass().getWeight(item) * count; + if (target.getClass().getCapacity(target) < target.getClass().getEncumbrance(target) + weight) + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sContentsMessage3}"); + return false; + } + + return true; +} + +bool ContainerItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const { if (mItemSources.empty()) return false; @@ -196,7 +226,7 @@ bool ContainerItemModel::onTakeItem(const MWWorld::Ptr &item, int count) // Looting a dead corpse is considered OK if (target.getClass().isActor() && target.getClass().getCreatureStats(target).isDead()) return true; - + MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item, target, count); diff --git a/apps/openmw/mwgui/containeritemmodel.hpp b/apps/openmw/mwgui/containeritemmodel.hpp index a0dbc2cf9..fb57096ef 100644 --- a/apps/openmw/mwgui/containeritemmodel.hpp +++ b/apps/openmw/mwgui/containeritemmodel.hpp @@ -18,6 +18,10 @@ namespace MWGui ContainerItemModel (const MWWorld::Ptr& source); virtual bool allowedToUseItems() const; + + virtual bool onDropItem(const MWWorld::Ptr &item, int count) const; + virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + virtual ItemStack getItem (ModelIndex index); virtual ModelIndex getIndex (ItemStack item); virtual size_t getItemCount(); @@ -26,7 +30,6 @@ namespace MWGui virtual void removeItem (const ItemStack& item, size_t count); virtual void update(); - virtual bool onTakeItem(const MWWorld::Ptr &item, int count); private: std::vector mItemSources; diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index b807a58f4..aed08feb1 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -124,7 +124,7 @@ bool InventoryItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const // Looting a dead corpse is considered OK if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead()) return true; - + MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item, mActor, count); diff --git a/apps/openmw/mwgui/inventoryitemmodel.hpp b/apps/openmw/mwgui/inventoryitemmodel.hpp index 95afeb5d4..c5ca80eed 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.hpp +++ b/apps/openmw/mwgui/inventoryitemmodel.hpp @@ -15,6 +15,8 @@ namespace MWGui virtual ModelIndex getIndex (ItemStack item); virtual size_t getItemCount(); + virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); @@ -22,7 +24,6 @@ namespace MWGui virtual MWWorld::Ptr moveItem (const ItemStack& item, size_t count, ItemModel* otherModel); virtual void update(); - virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; protected: MWWorld::Ptr mActor; diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 5a6afdf02..25dce728a 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -129,7 +129,12 @@ namespace MWGui return true; } - bool ItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + bool ItemModel::onDropItem(const MWWorld::Ptr &item, int count) const + { + return true; + } + + bool ItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const { return true; } @@ -203,7 +208,12 @@ namespace MWGui mSourceModel = sourceModel; } - bool ProxyItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + bool ProxyItemModel::onDropItem(const MWWorld::Ptr &item, int count) const + { + return mSourceModel->onDropItem (item, count); + } + + bool ProxyItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const { return mSourceModel->onTakeItem (item, count); } diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index c4a3a03e8..78c646e33 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -75,7 +75,8 @@ namespace MWGui /// Is the player allowed to insert items into this model? (default true) virtual bool allowedToInsertItems() const; - virtual bool onTakeItem(const MWWorld::Ptr &item, int count); + virtual bool onDropItem(const MWWorld::Ptr &item, int count) const; + virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; private: ItemModel(const ItemModel&); @@ -92,10 +93,12 @@ namespace MWGui bool allowedToUseItems() const; + virtual bool onDropItem(const MWWorld::Ptr &item, int count) const; + virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); virtual ModelIndex getIndex (ItemStack item); - virtual bool onTakeItem(const MWWorld::Ptr &item, int count); /// @note Takes ownership of the passed pointer. void setSourceModel(ItemModel* sourceModel); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index e610854c1..ba8fd7d75 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -4,6 +4,7 @@ #include #include "../mwmechanics/actorutil.hpp" +#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/pickpocket.hpp" #include "../mwworld/class.hpp" @@ -80,12 +81,21 @@ namespace MWGui bool PickpocketItemModel::allowedToInsertItems() const { - // don't allow "reverse pickpocket" (yet) + // don't allow "reverse pickpocket" (it will be handled by scripts after 1.0) + return false; + } + + bool PickpocketItemModel::onDropItem(const MWWorld::Ptr &item, int count) + { + // don't allow "reverse pickpocket" (it will be handled by scripts after 1.0) return false; } bool PickpocketItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const { + if (mActor.getClass().getCreatureStats(mActor).getKnockedDown()) + return mSourceModel->onTakeItem(item, count); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::Pickpocket pickpocket(player, mActor); if (pickpocket.pick(item, count)) diff --git a/apps/openmw/mwgui/pickpocketitemmodel.hpp b/apps/openmw/mwgui/pickpocketitemmodel.hpp index ad8788da7..a759cd993 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.hpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.hpp @@ -18,6 +18,7 @@ namespace MWGui virtual void update(); virtual void removeItem (const ItemStack& item, size_t count); virtual bool allowedToInsertItems() const; + virtual bool onDropItem(const MWWorld::Ptr &item, int count) const; virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; protected: diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 932f362fb..15c7fbfcb 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -311,7 +311,12 @@ namespace MWGui std::sort(mItems.begin(), mItems.end(), cmp); } - bool SortFilterItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + bool SortFilterItemModel::onDropItem(const MWWorld::Ptr &item, int count) const + { + return mSourceModel->onDropItem (item, count); + } + + bool SortFilterItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const { return mSourceModel->onTakeItem (item, count); } diff --git a/apps/openmw/mwgui/sortfilteritemmodel.hpp b/apps/openmw/mwgui/sortfilteritemmodel.hpp index e99726b0f..fa8d836b5 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.hpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.hpp @@ -29,7 +29,8 @@ namespace MWGui /// Use ItemStack::Type for sorting? void setSortByType(bool sort) { mSortByType = sort; } - bool onTakeItem(const MWWorld::Ptr &item, int count); + bool onDropItem(const MWWorld::Ptr &item, int count) const; + bool onTakeItem(const MWWorld::Ptr &item, int count) const; static const int Category_Weapon = (1<<1); static const int Category_Apparel = (1<<2); From 3694b6ec90369c9e070ac785d08a3a6496afadfd Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 4 Oct 2017 23:26:06 +0400 Subject: [PATCH 403/505] Move onClose() check to item models --- apps/openmw/mwgui/container.cpp | 24 +------------------ apps/openmw/mwgui/container.hpp | 2 -- apps/openmw/mwgui/containeritemmodel.cpp | 4 ++-- apps/openmw/mwgui/containeritemmodel.hpp | 4 ++-- apps/openmw/mwgui/inventoryitemmodel.cpp | 2 +- apps/openmw/mwgui/inventoryitemmodel.hpp | 2 +- apps/openmw/mwgui/itemmodel.cpp | 17 ++++++++----- apps/openmw/mwgui/itemmodel.hpp | 12 ++++++---- apps/openmw/mwgui/pickpocketitemmodel.cpp | 29 +++++++++++++++++++++-- apps/openmw/mwgui/pickpocketitemmodel.hpp | 7 ++++-- apps/openmw/mwgui/sortfilteritemmodel.cpp | 13 ++++++---- apps/openmw/mwgui/sortfilteritemmodel.hpp | 5 ++-- 12 files changed, 70 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 3fa07b070..03c7b54be 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -12,9 +12,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwmechanics/pickpocket.hpp" #include "../mwmechanics/creaturestats.hpp" -#include "../mwmechanics/actorutil.hpp" #include "countdialog.hpp" #include "inventorywindow.hpp" @@ -33,7 +31,6 @@ namespace MWGui ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) : WindowBase("openmw_container_window.layout") , mDragAndDrop(dragAndDrop) - , mPickpocketDetected(false) , mSortModel(NULL) , mModel(NULL) , mSelectedItem(-1) @@ -114,7 +111,6 @@ namespace MWGui void ContainerWindow::setPtr(const MWWorld::Ptr& container) { - mPickpocketDetected = false; mPtr = container; bool loot = mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead(); @@ -159,24 +155,7 @@ namespace MWGui { WindowBase::onClose(); - if (dynamic_cast(mModel) - // Make sure we were actually closed, rather than just temporarily hidden (e.g. console or main menu opened) - && !MWBase::Environment::get().getWindowManager()->containsMode(GM_Container) - // If it was already detected while taking an item, no need to check now - && !mPickpocketDetected - ) - { - MWWorld::Ptr player = MWMechanics::getPlayer(); - MWMechanics::Pickpocket pickpocket(player, mPtr); - if (pickpocket.finish()) - { - MWBase::Environment::get().getMechanicsManager()->commitCrime( - player, mPtr, MWBase::MechanicsManager::OT_Pickpocket, 0, true); - MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); - mPickpocketDetected = true; - return; - } - } + mModel->onClose(); } void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) @@ -252,7 +231,6 @@ namespace MWGui bool ContainerWindow::onTakeItem(const ItemStack &item, int count) { - // TODO: mPickpocketDetected = true; return mModel->onTakeItem(item.mBase, count); } diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 50c69da3b..cf02d165d 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -44,8 +44,6 @@ namespace MWGui private: DragAndDrop* mDragAndDrop; - bool mPickpocketDetected; - MWGui::ItemView* mItemView; SortFilterItemModel* mSortModel; ItemModel* mModel; diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index ef7aa8215..8e42b3ebc 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -186,7 +186,7 @@ void ContainerItemModel::update() } } } -bool ContainerItemModel::onDropItem(const MWWorld::Ptr &item, int count) const +bool ContainerItemModel::onDropItem(const MWWorld::Ptr &item, int count) { if (mItemSources.empty()) return false; @@ -216,7 +216,7 @@ bool ContainerItemModel::onDropItem(const MWWorld::Ptr &item, int count) const return true; } -bool ContainerItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const +bool ContainerItemModel::onTakeItem(const MWWorld::Ptr &item, int count) { if (mItemSources.empty()) return false; diff --git a/apps/openmw/mwgui/containeritemmodel.hpp b/apps/openmw/mwgui/containeritemmodel.hpp index fb57096ef..e8d1c5328 100644 --- a/apps/openmw/mwgui/containeritemmodel.hpp +++ b/apps/openmw/mwgui/containeritemmodel.hpp @@ -19,8 +19,8 @@ namespace MWGui virtual bool allowedToUseItems() const; - virtual bool onDropItem(const MWWorld::Ptr &item, int count) const; - virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + virtual bool onDropItem(const MWWorld::Ptr &item, int count); + virtual bool onTakeItem(const MWWorld::Ptr &item, int count); virtual ItemStack getItem (ModelIndex index); virtual ModelIndex getIndex (ItemStack item); diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index aed08feb1..c9f55d352 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -119,7 +119,7 @@ void InventoryItemModel::update() } } -bool InventoryItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const +bool InventoryItemModel::onTakeItem(const MWWorld::Ptr &item, int count) { // Looting a dead corpse is considered OK if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead()) diff --git a/apps/openmw/mwgui/inventoryitemmodel.hpp b/apps/openmw/mwgui/inventoryitemmodel.hpp index c5ca80eed..38730bd4d 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.hpp +++ b/apps/openmw/mwgui/inventoryitemmodel.hpp @@ -15,7 +15,7 @@ namespace MWGui virtual ModelIndex getIndex (ItemStack item); virtual size_t getItemCount(); - virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + virtual bool onTakeItem(const MWWorld::Ptr &item, int count); virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 25dce728a..c59bc8bf4 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -129,12 +129,12 @@ namespace MWGui return true; } - bool ItemModel::onDropItem(const MWWorld::Ptr &item, int count) const + bool ItemModel::onDropItem(const MWWorld::Ptr &item, int count) { return true; } - bool ItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const + bool ItemModel::onTakeItem(const MWWorld::Ptr &item, int count) { return true; } @@ -208,13 +208,18 @@ namespace MWGui mSourceModel = sourceModel; } - bool ProxyItemModel::onDropItem(const MWWorld::Ptr &item, int count) const + void ProxyItemModel::onClose() { - return mSourceModel->onDropItem (item, count); + mSourceModel->onClose(); } - bool ProxyItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const + bool ProxyItemModel::onDropItem(const MWWorld::Ptr &item, int count) { - return mSourceModel->onTakeItem (item, count); + return mSourceModel->onDropItem(item, count); + } + + bool ProxyItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + { + return mSourceModel->onTakeItem(item, count); } } diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index 78c646e33..d50718e5d 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -75,8 +75,11 @@ namespace MWGui /// Is the player allowed to insert items into this model? (default true) virtual bool allowedToInsertItems() const; - virtual bool onDropItem(const MWWorld::Ptr &item, int count) const; - virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + virtual void onClose() + { + } + virtual bool onDropItem(const MWWorld::Ptr &item, int count); + virtual bool onTakeItem(const MWWorld::Ptr &item, int count); private: ItemModel(const ItemModel&); @@ -93,8 +96,9 @@ namespace MWGui bool allowedToUseItems() const; - virtual bool onDropItem(const MWWorld::Ptr &item, int count) const; - virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + virtual void onClose(); + virtual bool onDropItem(const MWWorld::Ptr &item, int count); + virtual bool onTakeItem(const MWWorld::Ptr &item, int count); virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index ba8fd7d75..b073ef73f 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -17,7 +17,7 @@ namespace MWGui { PickpocketItemModel::PickpocketItemModel(const MWWorld::Ptr& actor, ItemModel *sourceModel, bool hideItems) - : mActor(actor) + : mActor(actor), mPickpocketDetected(false) { MWWorld::Ptr player = MWMechanics::getPlayer(); mSourceModel = sourceModel; @@ -91,11 +91,35 @@ namespace MWGui return false; } - bool PickpocketItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const + void PickpocketItemModel::onClose() + { + // Make sure we were actually closed, rather than just temporarily hidden (e.g. console or main menu opened) + if (MWBase::Environment::get().getWindowManager()->containsMode(GM_Container) + // If it was already detected while taking an item, no need to check now + || mPickpocketDetected) + return; + + MWWorld::Ptr player = MWMechanics::getPlayer(); + MWMechanics::Pickpocket pickpocket(player, mActor); + if (pickpocket.finish()) + { + MWBase::Environment::get().getMechanicsManager()->commitCrime( + player, mActor, MWBase::MechanicsManager::OT_Pickpocket, 0, true); + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); + mPickpocketDetected = true; + } + } + + bool PickpocketItemModel::onTakeItem(const MWWorld::Ptr &item, int count) { if (mActor.getClass().getCreatureStats(mActor).getKnockedDown()) return mSourceModel->onTakeItem(item, count); + return stealItem(item, count); + } + + bool PickpocketItemModel::stealItem(const MWWorld::Ptr &item, int count) + { MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::Pickpocket pickpocket(player, mActor); if (pickpocket.pick(item, count)) @@ -103,6 +127,7 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->commitCrime( player, mActor, MWBase::MechanicsManager::OT_Pickpocket, 0, true); MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); + mPickpocketDetected = true; return false; } else diff --git a/apps/openmw/mwgui/pickpocketitemmodel.hpp b/apps/openmw/mwgui/pickpocketitemmodel.hpp index a759cd993..9aa686c39 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.hpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.hpp @@ -18,11 +18,14 @@ namespace MWGui virtual void update(); virtual void removeItem (const ItemStack& item, size_t count); virtual bool allowedToInsertItems() const; - virtual bool onDropItem(const MWWorld::Ptr &item, int count) const; - virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + virtual void onClose(); + virtual bool onDropItem(const MWWorld::Ptr &item, int count); + virtual bool onTakeItem(const MWWorld::Ptr &item, int count); protected: MWWorld::Ptr mActor; + bool mPickpocketDetected; + bool stealItem(const MWWorld::Ptr &item, int count); private: std::vector mHiddenItems; diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 15c7fbfcb..1ee3cf631 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -311,13 +311,18 @@ namespace MWGui std::sort(mItems.begin(), mItems.end(), cmp); } - bool SortFilterItemModel::onDropItem(const MWWorld::Ptr &item, int count) const + void SortFilterItemModel::onClose() { - return mSourceModel->onDropItem (item, count); + mSourceModel->onClose(); } - bool SortFilterItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const + bool SortFilterItemModel::onDropItem(const MWWorld::Ptr &item, int count) { - return mSourceModel->onTakeItem (item, count); + return mSourceModel->onDropItem(item, count); + } + + bool SortFilterItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + { + return mSourceModel->onTakeItem(item, count); } } diff --git a/apps/openmw/mwgui/sortfilteritemmodel.hpp b/apps/openmw/mwgui/sortfilteritemmodel.hpp index fa8d836b5..98da8d8c9 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.hpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.hpp @@ -29,8 +29,9 @@ namespace MWGui /// Use ItemStack::Type for sorting? void setSortByType(bool sort) { mSortByType = sort; } - bool onDropItem(const MWWorld::Ptr &item, int count) const; - bool onTakeItem(const MWWorld::Ptr &item, int count) const; + void onClose(); + bool onDropItem(const MWWorld::Ptr &item, int count); + bool onTakeItem(const MWWorld::Ptr &item, int count); static const int Category_Weapon = (1<<1); static const int Category_Apparel = (1<<2); From 1cd539bad2724df2815ad6df0ed37e3fa29c1ee2 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 10 Nov 2017 02:06:06 -0500 Subject: [PATCH 404/505] Fix render order for markers --- apps/opencs/view/render/object.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index a3ecbadeb..c5da094e6 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -390,7 +390,7 @@ osg::ref_ptr CSVRender::Object::makeRotateMarker (int axis) void CSVRender::Object::setupCommonMarkerState(osg::ref_ptr geometry) { - const int RenderBin = osg::StateSet::TRANSPARENT_BIN - 1; + const int RenderBin = osg::StateSet::TRANSPARENT_BIN; osg::ref_ptr state = geometry->getOrCreateStateSet(); state->setMode(GL_LIGHTING, osg::StateAttribute::OFF); From 69a56eaea3fee303e3ef58d58d5ca6bd43668143 Mon Sep 17 00:00:00 2001 From: rexelion Date: Fri, 10 Nov 2017 10:44:53 +0000 Subject: [PATCH 405/505] don't initialise rangeAttackOfTarget --- apps/openmw/mwmechanics/aicombat.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 6e3268831..07fb455f3 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -491,7 +491,6 @@ namespace MWMechanics void AiCombatStorage::startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target) { // get the range of the target's weapon - float rangeAttackOfTarget = 0.f; MWWorld::Ptr targetWeapon = MWWorld::Ptr(); const MWWorld::Class& targetClass = target.getClass(); @@ -505,7 +504,7 @@ namespace MWMechanics } bool isRangedCombat = false; - rangeAttackOfTarget = ActionWeapon(targetWeapon).getCombatRange(isRangedCombat); + float rangeAttackOfTarget = ActionWeapon(targetWeapon).getCombatRange(isRangedCombat); if (mMovement.mPosition[0] || mMovement.mPosition[1]) { From b9baee51d556f5e4555fb227292a850cd8b51525 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 10 Nov 2017 21:47:14 +0100 Subject: [PATCH 406/505] Fix overlapping widgets in trade window layout (Fixes #4205) --- files/mygui/openmw_trade_window.layout | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index d1f31c475..ebfe9b30f 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -53,18 +53,17 @@ - - - - - + + + + - + - + From 1afbf99f74c8a5b4c0aedad91ff20f3d3529fee4 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 10 Nov 2017 21:48:11 +0100 Subject: [PATCH 407/505] Make movement keys not function in text input mode --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index a5bb93b6c..5aa795c10 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -176,6 +176,8 @@ namespace MWInput void InputManager::handleGuiArrowKey(int action) { + if (SDL_IsTextInputActive()) + return; MyGUI::KeyCode key; switch (action) { From b06512a60d9f020cdd8d9f44fe6ef76f216eb9dd Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 10 Nov 2017 22:02:43 +0100 Subject: [PATCH 408/505] Fix error message that referred to the wrong file (Bug #4159) --- apps/openmw/mwrender/animation.cpp | 6 +++--- apps/openmw/mwrender/animation.hpp | 7 ++++--- apps/openmw/mwrender/creatureanimation.cpp | 8 ++++---- apps/openmw/mwrender/npcanimation.cpp | 12 ++++++------ 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 90b69de8e..a1aa24871 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -536,7 +536,7 @@ namespace MWRender return mKeyframes->mTextKeys; } - void Animation::addAnimSource(const std::string &model) + void Animation::addAnimSource(const std::string &model, const std::string& baseModel) { std::string kfname = model; Misc::StringUtils::lowerCaseInPlace(kfname); @@ -565,7 +565,7 @@ namespace MWRender NodeMap::const_iterator found = nodeMap.find(bonename); if (found == nodeMap.end()) { - std::cerr << "Warning: addAnimSource: can't find bone '" + bonename << "' in " << model << " (referenced by " << kfname << ")" << std::endl; + std::cerr << "Warning: addAnimSource: can't find bone '" + bonename << "' in " << baseModel << " (referenced by " << kfname << ")" << std::endl; continue; } @@ -1668,7 +1668,7 @@ namespace MWRender { setObjectRoot(model, false, false, false); if (animated) - addAnimSource(model); + addAnimSource(model, model); if (!ptr.getClass().getEnchantment(ptr).empty()) addGlow(mObjectRoot, getEnchantmentColor(ptr)); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 5aec80f5d..8ac78babc 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -309,11 +309,12 @@ protected: */ void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature); - /** Adds the keyframe controllers in the specified model as a new animation source. Note that the .nif - * file extension will be replaced with .kf. + /** Adds the keyframe controllers in the specified model as a new animation source. * @note Later added animation sources have the highest priority when it comes to finding a particular animation. + * @param model The file to add the keyframes for. Note that the .nif file extension will be replaced with .kf. + * @param baseModel The filename of the mObjectRoot, only used for error messages. */ - void addAnimSource(const std::string &model); + void addAnimSource(const std::string &model, const std::string& baseModel); /** Adds an additional light to the given node using the specified ESM record. */ void addExtraLight(osg::ref_ptr parent, const ESM::Light *light); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 735c0b66d..827b576c3 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -33,8 +33,8 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, setObjectRoot(model, false, false, true); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) - addAnimSource("meshes\\xbase_anim.nif"); - addAnimSource(model); + addAnimSource("meshes\\xbase_anim.nif", model); + addAnimSource(model, model); } } @@ -51,8 +51,8 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const setObjectRoot(model, true, false, true); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) - addAnimSource("meshes\\xbase_anim.nif"); - addAnimSource(model); + addAnimSource("meshes\\xbase_anim.nif", model); + addAnimSource(model, model); mPtr.getClass().getInventoryStore(mPtr).setInvListener(this, mPtr); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index ece57c273..08e376f08 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -482,25 +482,25 @@ void NpcAnimation::updateNpcBase() { const std::string base = "meshes\\xbase_anim.nif"; if (smodel != base) - addAnimSource(base); + addAnimSource(base, smodel); - addAnimSource(smodel); + addAnimSource(smodel, smodel); if(!isWerewolf) { if(mNpc->mModel.length() > 0) - addAnimSource(Misc::ResourceHelpers::correctActorModelPath("meshes\\" + mNpc->mModel, mResourceSystem->getVFS())); + addAnimSource(Misc::ResourceHelpers::correctActorModelPath("meshes\\" + mNpc->mModel, mResourceSystem->getVFS()), smodel); if(Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos) - addAnimSource("meshes\\xargonian_swimkna.nif"); + addAnimSource("meshes\\xargonian_swimkna.nif", smodel); } } else { const std::string base = "meshes\\xbase_anim.1st.nif"; if (smodel != base) - addAnimSource(base); + addAnimSource(base, smodel); - addAnimSource(smodel); + addAnimSource(smodel, smodel); mObjectRoot->setNodeMask(Mask_FirstPerson); mObjectRoot->addCullCallback(new OverrideFieldOfViewCallback(mFirstPersonFieldOfView)); From a5adc5b018fa76a39e5a3a41aba4f5fcc8ab049d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 10 Nov 2017 22:09:24 +0100 Subject: [PATCH 409/505] Add NPC base skeleton files to the optimizer blacklist (Fixes #4159) --- components/resource/scenemanager.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 9c5a2a14e..03b850fac 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -432,13 +432,18 @@ namespace Resource bool canOptimize(const std::string& filename) { - // xmesh.nif can not be optimized because there are keyframes added in post size_t slashpos = filename.find_last_of("\\/"); if (slashpos != std::string::npos && slashpos+1 < filename.size()) { std::string basename = filename.substr(slashpos+1); + // xmesh.nif can not be optimized because there are keyframes added in post if (!basename.empty() && basename[0] == 'x') return false; + + // NPC skeleton files can not be optimized because of keyframes added in post + // (most of them are usually named like 'xbase_anim.nif' anyway, but not all of them :( ) + if (basename.compare(0, 9, "base_anim") == 0 || basename.compare(0, 4, "skin") == 0) + return false; } // For spell VFX, DummyXX nodes must remain intact. Not adding those to reservedNames to avoid being overly cautious - instead, decide on filename From f1aeb416ece36dbc37cd41138cc37bf6517cc5f4 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 10 Nov 2017 22:54:04 +0000 Subject: [PATCH 410/505] Disable Activate key when textinput is active (Bug #4151) --- apps/openmw/mwinput/inputmanagerimp.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 5aa795c10..9ef5033f0 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1113,7 +1113,10 @@ namespace MWInput void InputManager::activate() { if (MWBase::Environment::get().getWindowManager()->isGuiMode()) - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Return, 0); + { + if (!SDL_IsTextInputActive()) + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Return, 0); + } else if (mControlSwitch["playercontrols"]) mPlayer->activate(); } From a02124f884018ab23d6d78538f6b2222ebaefd6c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 5 Oct 2017 11:12:43 +0400 Subject: [PATCH 411/505] Handle item owners during pickpocketing --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 +-- apps/openmw/mwgui/pickpocketitemmodel.cpp | 11 ++++++++-- .../mwmechanics/mechanicsmanagerimp.cpp | 22 ++++++++++++++----- .../mwmechanics/mechanicsmanagerimp.hpp | 2 +- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 398439ad8..7a33d6e57 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -140,7 +140,7 @@ namespace MWBase /// Utility to check if taking this item is illegal and calling commitCrime if so /// @param container The container the item is in; may be empty for an item in the world virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, - int count) = 0; + int count, bool alarm = true) = 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. @@ -250,7 +250,6 @@ namespace MWBase virtual void cleanupSummonedCreature(const MWWorld::Ptr& caster, int creatureActorId) = 0; virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) = 0; - virtual bool isAttackPrepairing(const MWWorld::Ptr& ptr) = 0; virtual bool isRunning(const MWWorld::Ptr& ptr) = 0; virtual bool isSneaking(const MWWorld::Ptr& ptr) = 0; diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index b073ef73f..4c32eafcd 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -7,6 +7,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/pickpocket.hpp" +#include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" #include "../mwbase/environment.hpp" @@ -76,7 +77,6 @@ namespace MWGui void PickpocketItemModel::removeItem (const ItemStack &item, size_t count) { ProxyItemModel::removeItem(item, count); - /// \todo check if player is detected } bool PickpocketItemModel::allowedToInsertItems() const @@ -115,7 +115,14 @@ namespace MWGui if (mActor.getClass().getCreatureStats(mActor).getKnockedDown()) return mSourceModel->onTakeItem(item, count); - return stealItem(item, count); + bool success = stealItem(item, count); + if (success) + { + MWWorld::Ptr player = MWMechanics::getPlayer(); + MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item, mActor, count, false); + } + + return success; } bool PickpocketItemModel::stealItem(const MWWorld::Ptr &item, int count) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 2c7b6a500..a4e258ada 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1024,7 +1024,7 @@ namespace MWMechanics } void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container, - int count) + int count, bool alarm) { if (ptr != getPlayer()) return; @@ -1053,19 +1053,29 @@ namespace MWMechanics return; Owner owner; - owner.first = ownerCellRef->getOwner(); owner.second = false; - if (owner.first.empty()) + if (!container.isEmpty() && container.getClass().isActor()) { - owner.first = ownerCellRef->getFaction(); - owner.second = true; + // "container" is an actor inventory, so just take actor's ID + owner.first = ownerCellRef->getRefId(); } + else + { + owner.first = ownerCellRef->getOwner(); + if (owner.first.empty()) + { + owner.first = ownerCellRef->getFaction(); + owner.second = true; + } + } + Misc::StringUtils::lowerCaseInPlace(owner.first); if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count; - commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); + if (alarm) + 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 ee4cf28af..baee5233e 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -135,7 +135,7 @@ namespace MWMechanics /// Utility to check if taking this item is illegal and calling commitCrime if so /// @param container The container the item is in; may be empty for an item in the world virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, - int count); + int count, bool alarm = true); /// 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. From 99517d83ea2116577c5f893b723c019fc6645b5b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 10 Nov 2017 09:43:22 +0400 Subject: [PATCH 412/505] Bound items detection refactoring --- apps/openmw/mwbase/mechanicsmanager.hpp | 1 + apps/openmw/mwgui/itemmodel.cpp | 34 +--------------- .../mwmechanics/mechanicsmanagerimp.cpp | 39 +++++++++++++++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 2 + 4 files changed, 44 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 7a33d6e57..5fb3bd400 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -238,6 +238,7 @@ namespace MWBase /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; + virtual bool isBoundItem(const MWWorld::Ptr& item) = 0; virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) = 0; /// Turn actor into werewolf or normal form. diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index c59bc8bf4..834c351dc 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -9,6 +9,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" namespace MWGui { @@ -23,38 +24,7 @@ namespace MWGui if (base.getClass().getEnchantment(base) != "") mFlags |= Flag_Enchanted; - static std::set boundItemIDCache; - - // If this is empty then we haven't executed the GMST cache logic yet; or there isn't any sMagicBound* GMST's for some reason - if (boundItemIDCache.empty()) - { - // Build a list of known bound item ID's - const MWWorld::Store &gameSettings = MWBase::Environment::get().getWorld()->getStore().get(); - - for (MWWorld::Store::iterator currentIteration = gameSettings.begin(); currentIteration != gameSettings.end(); ++currentIteration) - { - const ESM::GameSetting ¤tSetting = *currentIteration; - std::string currentGMSTID = currentSetting.mId; - Misc::StringUtils::lowerCaseInPlace(currentGMSTID); - - // Don't bother checking this GMST if it's not a sMagicBound* one. - const std::string& toFind = "smagicbound"; - if (currentGMSTID.compare(0, toFind.length(), toFind) != 0) - continue; - - // All sMagicBound* GMST's should be of type string - std::string currentGMSTValue = currentSetting.getString(); - Misc::StringUtils::lowerCaseInPlace(currentGMSTValue); - - boundItemIDCache.insert(currentGMSTValue); - } - } - - // Perform bound item check and assign the Flag_Bound bit if it passes - std::string tempItemID = base.getCellRef().getRefId(); - Misc::StringUtils::lowerCaseInPlace(tempItemID); - - if (boundItemIDCache.count(tempItemID) != 0) + if (MWBase::Environment::get().getMechanicsManager()->isBoundItem(base)) mFlags |= Flag_Bound; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index a4e258ada..92031b80b 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -840,6 +840,45 @@ namespace MWMechanics mAI = true; } + bool MechanicsManager::isBoundItem(const MWWorld::Ptr& item) + { + static std::set boundItemIDCache; + + // If this is empty then we haven't executed the GMST cache logic yet; or there isn't any sMagicBound* GMST's for some reason + if (boundItemIDCache.empty()) + { + // Build a list of known bound item ID's + const MWWorld::Store &gameSettings = MWBase::Environment::get().getWorld()->getStore().get(); + + for (MWWorld::Store::iterator currentIteration = gameSettings.begin(); currentIteration != gameSettings.end(); ++currentIteration) + { + const ESM::GameSetting ¤tSetting = *currentIteration; + std::string currentGMSTID = currentSetting.mId; + Misc::StringUtils::lowerCaseInPlace(currentGMSTID); + + // Don't bother checking this GMST if it's not a sMagicBound* one. + const std::string& toFind = "smagicbound"; + if (currentGMSTID.compare(0, toFind.length(), toFind) != 0) + continue; + + // All sMagicBound* GMST's should be of type string + std::string currentGMSTValue = currentSetting.getString(); + Misc::StringUtils::lowerCaseInPlace(currentGMSTValue); + + boundItemIDCache.insert(currentGMSTValue); + } + } + + // Perform bound item check and assign the Flag_Bound bit if it passes + std::string tempItemID = item.getCellRef().getRefId(); + Misc::StringUtils::lowerCaseInPlace(tempItemID); + + if (boundItemIDCache.count(tempItemID) != 0) + return true; + + return false; + } + bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) { if (target.isEmpty()) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index baee5233e..bf3b7c79c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -204,6 +204,8 @@ namespace MWMechanics /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); + virtual bool isBoundItem(const MWWorld::Ptr& item); + /// @return is \a ptr allowed to take/use \a target or is it a crime? virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim); From 03f129b53c97a5032c5862606c0d0f93a40abc38 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 11 Nov 2017 11:54:18 +0400 Subject: [PATCH 413/505] remove redundant allowedToInsertItems() function from ItemModel --- apps/openmw/mwgui/container.cpp | 7 +++---- apps/openmw/mwgui/itemmodel.cpp | 5 ----- apps/openmw/mwgui/itemmodel.hpp | 3 --- apps/openmw/mwgui/pickpocketitemmodel.cpp | 6 ------ apps/openmw/mwgui/pickpocketitemmodel.hpp | 1 - 5 files changed, 3 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 03c7b54be..444eaff85 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -52,10 +52,9 @@ namespace MWGui void ContainerWindow::onItemSelected(int index) { - if (mDragAndDrop->mIsOnDragAndDrop) + if (mDragAndDrop->mIsOnDragAndDrop && mModel) { - if (mModel && mModel->allowedToInsertItems()) - dropItem(); + dropItem(); return; } @@ -105,7 +104,7 @@ namespace MWGui void ContainerWindow::onBackgroundSelected() { - if (mDragAndDrop->mIsOnDragAndDrop && mModel && mModel->allowedToInsertItems()) + if (mDragAndDrop->mIsOnDragAndDrop && mModel) dropItem(); } diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 834c351dc..e3f38a54c 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -94,11 +94,6 @@ namespace MWGui return true; } - bool ItemModel::allowedToInsertItems() const - { - return true; - } - bool ItemModel::onDropItem(const MWWorld::Ptr &item, int count) { return true; diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index d50718e5d..e8e348a8a 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -72,9 +72,6 @@ namespace MWGui /// Is the player allowed to use items from this item model? (default true) virtual bool allowedToUseItems() const; - - /// Is the player allowed to insert items into this model? (default true) - virtual bool allowedToInsertItems() const; virtual void onClose() { } diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index 4c32eafcd..e85715e87 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -79,12 +79,6 @@ namespace MWGui ProxyItemModel::removeItem(item, count); } - bool PickpocketItemModel::allowedToInsertItems() const - { - // don't allow "reverse pickpocket" (it will be handled by scripts after 1.0) - return false; - } - bool PickpocketItemModel::onDropItem(const MWWorld::Ptr &item, int count) { // don't allow "reverse pickpocket" (it will be handled by scripts after 1.0) diff --git a/apps/openmw/mwgui/pickpocketitemmodel.hpp b/apps/openmw/mwgui/pickpocketitemmodel.hpp index 9aa686c39..83caf2ffd 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.hpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.hpp @@ -17,7 +17,6 @@ namespace MWGui virtual size_t getItemCount(); virtual void update(); virtual void removeItem (const ItemStack& item, size_t count); - virtual bool allowedToInsertItems() const; virtual void onClose(); virtual bool onDropItem(const MWWorld::Ptr &item, int count); virtual bool onTakeItem(const MWWorld::Ptr &item, int count); From 9943bd4d745080ef20caf6fb9c12e0f282203b21 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 11 Nov 2017 12:31:18 +0400 Subject: [PATCH 414/505] AiWander fast forwarding improvements (bug #3638) --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 + apps/openmw/mwmechanics/actors.cpp | 11 +++ apps/openmw/mwmechanics/actors.hpp | 12 ++-- apps/openmw/mwmechanics/aiwander.cpp | 70 +++++++++++++++++-- apps/openmw/mwmechanics/aiwander.hpp | 2 + .../mwmechanics/mechanicsmanagerimp.cpp | 5 ++ .../mwmechanics/mechanicsmanagerimp.hpp | 3 + apps/openmw/mwmechanics/pathgrid.cpp | 10 +++ apps/openmw/mwmechanics/pathgrid.hpp | 3 + apps/openmw/mwworld/cellstore.cpp | 5 ++ apps/openmw/mwworld/cellstore.hpp | 1 + 11 files changed, 115 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 398439ad8..8ae2ae367 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -191,6 +191,9 @@ namespace MWBase virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& objects) = 0; virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector &objects) = 0; + /// Check if there are actors in selected range + virtual bool isAnyActorInRange(const osg::Vec3f &position, float radius) = 0; + ///Returns the list of actors which are siding with the given actor in fights /**ie AiFollow or AiEscort is active and the target is the actor **/ virtual std::list getActorsSidingWith(const MWWorld::Ptr& actor) = 0; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a144911c5..a47693a78 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1621,6 +1621,17 @@ namespace MWMechanics } } + bool Actors::isAnyObjectInRange(const osg::Vec3f& position, float radius) + { + for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter) + { + if ((iter->first.getRefData().getPosition().asVec3() - position).length2() <= radius*radius) + return true; + } + + return false; + } + std::list Actors::getActorsSidingWith(const MWWorld::Ptr& actor) { std::list list; diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index e433434a5..7ed89d0e4 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -115,15 +115,17 @@ namespace MWMechanics bool isRunning(const MWWorld::Ptr& ptr); bool isSneaking(const MWWorld::Ptr& ptr); - void forceStateUpdate(const MWWorld::Ptr &ptr); + void forceStateUpdate(const MWWorld::Ptr &ptr); - bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist=false); - void skipAnimation(const MWWorld::Ptr& ptr); - bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName); - void persistAnimationStates(); + bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist=false); + void skipAnimation(const MWWorld::Ptr& ptr); + bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName); + void persistAnimationStates(); void getObjectsInRange(const osg::Vec3f& position, float radius, std::vector& out); + bool isAnyObjectInRange(const osg::Vec3f& position, float radius); + void cleanupSummonedCreature (CreatureStats& casterStats, int creatureActorId); ///Returns the list of actors which are siding with the given actor in fights diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 255874d88..343e03f6c 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -799,20 +799,80 @@ namespace MWMechanics int index = Misc::Rng::rollDice(storage.mAllowedNodes.size()); ESM::Pathgrid::Point dest = storage.mAllowedNodes[index]; - state.moveIn(new AiWanderStorage()); + ESM::Pathgrid::Point worldDest = dest; + ToWorldCoordinates(worldDest, actor.getCell()->getCell()); + + bool isPathGridOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange(PathFinder::MakeOsgVec3(worldDest), 60); + + // add offset only if the selected pathgrid is occupied by another actor + if (isPathGridOccupied) + { + ESM::Pathgrid::PointList points; + getNeighbouringNodes(dest, actor.getCell(), points); + + // there are no neighbouring nodes, nowhere to move + if (points.empty()) + return; + + int initialSize = points.size(); + bool isOccupied = false; + // AI will try to move the NPC towards every neighboring node until suitable place will be found + for (int i = 0; i < initialSize; i++) + { + int randomIndex = Misc::Rng::rollDice(points.size()); + ESM::Pathgrid::Point connDest = points[randomIndex]; + + // add an offset towards random neighboring node + osg::Vec3f dir = PathFinder::MakeOsgVec3(connDest) - PathFinder::MakeOsgVec3(dest); + float length = dir.length(); + dir.normalize(); + + for (int j = 1; j <= 3; j++) + { + // move for 5-15% towards random neighboring node + dest = PathFinder::MakePathgridPoint(PathFinder::MakeOsgVec3(dest) + dir * (j * 5 * length / 100.f)); + worldDest = dest; + ToWorldCoordinates(worldDest, actor.getCell()->getCell()); + + isOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange(PathFinder::MakeOsgVec3(worldDest), 60); + + if (!isOccupied) + break; + } + + if (!isOccupied) + break; + + // Will try an another neighboring node + points.erase(points.begin()+randomIndex); + } + + // there is no free space, nowhere to move + if (isOccupied) + return; + } + + // place above to prevent moving inside objects, e.g. stairs, because a vector between pathgrids can be underground. + // Adding 20 in adjustPosition() is not enough. + dest.mZ += 60; - dest.mX += OffsetToPreventOvercrowding(); - dest.mY += OffsetToPreventOvercrowding(); ToWorldCoordinates(dest, actor.getCell()->getCell()); + state.moveIn(new AiWanderStorage()); + MWBase::Environment::get().getWorld()->moveObject(actor, static_cast(dest.mX), static_cast(dest.mY), static_cast(dest.mZ)); actor.getClass().adjustPosition(actor, false); } - int AiWander::OffsetToPreventOvercrowding() + void AiWander::getNeighbouringNodes(ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points) { - return static_cast(20 * (Misc::Rng::rollProbability() * 2.0f - 1.0f)); + const ESM::Pathgrid *pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*currentCell->getCell()); + + int index = PathFinder::GetClosestPoint(pathgrid, PathFinder::MakeOsgVec3(dest)); + + currentCell->getNeighbouringPoints(index, points); } void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 01d889e2f..6266a7708 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -104,6 +104,8 @@ namespace MWMechanics bool mHasDestination; osg::Vec3f mDestination; + void getNeighbouringNodes(ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points); + void getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage); void trimAllowedNodes(std::vector& nodes, const PathFinder& pathfinder); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index dfbcf0ea2..0ab6f0f42 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1529,6 +1529,11 @@ namespace MWMechanics mActors.getObjectsInRange(position, radius, objects); } + bool MechanicsManager::isAnyActorInRange(const osg::Vec3f &position, float radius) + { + return mActors.isAnyObjectInRange(position, radius); + } + std::list MechanicsManager::getActorsSidingWith(const MWWorld::Ptr& actor) { return mActors.getActorsSidingWith(actor); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index ee4cf28af..df7c35d97 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -158,6 +158,9 @@ namespace MWMechanics virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& objects); virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector &objects); + /// Check if there are actors in selected range + virtual bool isAnyActorInRange(const osg::Vec3f &position, float radius); + virtual std::list getActorsSidingWith(const MWWorld::Ptr& actor); virtual std::list getActorsFollowing(const MWWorld::Ptr& actor); virtual std::list getActorsFollowingIndices(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index c557beadd..85264095c 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -214,6 +214,16 @@ namespace MWMechanics return (mGraph[start].componentId == mGraph[end].componentId); } + void PathgridGraph::getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const + { + for(int i = 0; i < static_cast (mGraph[index].edges.size()); i++) + { + int neighbourIndex = mGraph[index].edges[i].index; + if (neighbourIndex != index) + nodes.push_back(mPathgrid->mPoints[neighbourIndex]); + } + } + /* * NOTE: Based on buildPath2(), please check git history if interested * Should consider using a 3rd party library version (e.g. boost) diff --git a/apps/openmw/mwmechanics/pathgrid.hpp b/apps/openmw/mwmechanics/pathgrid.hpp index d90cb47cd..84b84652c 100644 --- a/apps/openmw/mwmechanics/pathgrid.hpp +++ b/apps/openmw/mwmechanics/pathgrid.hpp @@ -28,6 +28,9 @@ namespace MWMechanics // from start point) both start and end are pathgrid point indexes bool isPointConnected(const int start, const int end) const; + // get neighbouring nodes for index node and put them to "nodes" vector + void getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const; + // the input parameters are pathgrid point indexes // the output list is in local (internal cells) or world (external // cells) coordinates diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index b4f260a25..f6e70dc94 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -942,6 +942,11 @@ namespace MWWorld return mPathgridGraph.isPointConnected(start, end); } + void CellStore::getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const + { + return mPathgridGraph.getNeighbouringPoints(index, nodes); + } + std::list CellStore::aStarSearch(const int start, const int end) const { return mPathgridGraph.aStarSearch(start, end); diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 4452ad889..2f6277aec 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -377,6 +377,7 @@ namespace MWWorld ///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded. bool isPointConnected(const int start, const int end) const; + void getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const; std::list aStarSearch(const int start, const int end) const; From f0649849b87be452acbab3307a145992c16f0101 Mon Sep 17 00:00:00 2001 From: rexelion Date: Sat, 11 Nov 2017 12:00:23 +0000 Subject: [PATCH 415/505] changed variable name to be more descriptive --- apps/openmw/mwmechanics/aicombat.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 07fb455f3..ee1013fe4 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -503,8 +503,8 @@ namespace MWMechanics targetWeapon = *weaponSlot; } - bool isRangedCombat = false; - float rangeAttackOfTarget = ActionWeapon(targetWeapon).getCombatRange(isRangedCombat); + bool targetUsesRanged = false; + float rangeAttackOfTarget = ActionWeapon(targetWeapon).getCombatRange(targetUsesRanged); if (mMovement.mPosition[0] || mMovement.mPosition[1]) { @@ -524,16 +524,17 @@ namespace MWMechanics } } - // Below behavior for backing up during ranged combat differs from vanilla. - // Vanilla is observed as backing up only as far as fCombatDistance or - // opponent's weapon range, or not backing up if opponent is also using a ranged weapon + // Backing up behaviour + // Actor backs up slightly further away than opponent's weapon range + // (in vanilla - only as far as oponent's weapon range), + // or not at all if opponent is using a ranged weapon if (isDistantCombat) { // actor should not back up into water if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.5f)) return; - if (!isRangedCombat && distToTarget <= rangeAttackOfTarget*1.5) // Don't back up if the target is wielding ranged weapon + if (!targetUsesRanged && distToTarget <= rangeAttackOfTarget*1.5) // Don't back up if the target is wielding ranged weapon mMovement.mPosition[1] = -1; } } From 8c0dcd8b2b8276f2030bd00053540febe7df6874 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 11 Nov 2017 19:46:59 +0400 Subject: [PATCH 416/505] Do not track a nearest actor during combat and pursue (bug #4179) --- apps/openmw/mwmechanics/actors.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a144911c5..ce8ad8f66 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1230,8 +1230,13 @@ namespace MWMechanics float sqrHeadTrackDistance = std::numeric_limits::max(); MWWorld::Ptr headTrackTarget; + MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first); + // Unconsious actor can not track target - if (!iter->first.getClass().getCreatureStats(iter->first).getKnockedDown()) + // Also actors in combat and pursue mode do not bother to headtrack + if (!stats.getKnockedDown() && + !stats.getAiSequence().isInCombat() && + !stats.getAiSequence().hasPackage(AiPackage::TypeIdPursue)) { for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it) { @@ -1239,8 +1244,9 @@ namespace MWMechanics continue; updateHeadTracking(iter->first, it->first, headTrackTarget, sqrHeadTrackDistance); } - iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget); } + + iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget); } if (iter->first.getClass().isNpc() && iter->first != player) From b7eda61f7a437bfd503be6227cec922be8c4e769 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 10 Nov 2017 21:47:14 +0100 Subject: [PATCH 417/505] Fix overlapping widgets in trade window layout (Fixes #4205) --- files/mygui/openmw_trade_window.layout | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index d1f31c475..ebfe9b30f 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -53,18 +53,17 @@ - - - - - + + + + - + - + From 3b9e1e8c1b8611f1a5d239734da3d8bb39a5265b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 10 Nov 2017 21:48:11 +0100 Subject: [PATCH 418/505] Make movement keys not function in text input mode --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index a5bb93b6c..5aa795c10 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -176,6 +176,8 @@ namespace MWInput void InputManager::handleGuiArrowKey(int action) { + if (SDL_IsTextInputActive()) + return; MyGUI::KeyCode key; switch (action) { From dc016059c381ecd4b277858f704b835b7240624d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 10 Nov 2017 22:54:04 +0000 Subject: [PATCH 419/505] Disable Activate key when textinput is active (Bug #4151) --- apps/openmw/mwinput/inputmanagerimp.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 5aa795c10..9ef5033f0 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1113,7 +1113,10 @@ namespace MWInput void InputManager::activate() { if (MWBase::Environment::get().getWindowManager()->isGuiMode()) - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Return, 0); + { + if (!SDL_IsTextInputActive()) + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Return, 0); + } else if (mControlSwitch["playercontrols"]) mPlayer->activate(); } From 92aaff3b788cd565d98cb40f25b125e495e6ca09 Mon Sep 17 00:00:00 2001 From: Alexander Stillich Date: Sun, 5 Nov 2017 21:40:35 +0100 Subject: [PATCH 420/505] Fixed escaping @ in boost program options filter --- components/files/escape.cpp | 3 ++- components/files/escape.hpp | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/components/files/escape.cpp b/components/files/escape.cpp index f28870c70..3c3d04d51 100644 --- a/components/files/escape.cpp +++ b/components/files/escape.cpp @@ -27,7 +27,8 @@ namespace Files std::string EscapeHashString::processString(const std::string & str) { std::string temp = boost::replace_all_copy(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#"); - boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, std::string((char)escape_hash_filter::sEscape, 1)); + auto format = std::string(1, (char)escape_hash_filter::sEscape); + boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, format); return temp; } diff --git a/components/files/escape.hpp b/components/files/escape.hpp index 2017c2ed2..64410f3ab 100644 --- a/components/files/escape.hpp +++ b/components/files/escape.hpp @@ -78,6 +78,12 @@ namespace Files mFinishLine = true; } } + else if (character == sEscape) + { + mNext.push(sEscape); + mNext.push(sEscapeIdentifier); + record = false; + } else if (mPrevious == sEscape) { mNext.push(sEscape); From 09aac227825d88470bf3cf3562d32bc2e61bbe08 Mon Sep 17 00:00:00 2001 From: Alexander Stillich Date: Tue, 7 Nov 2017 22:16:59 +0100 Subject: [PATCH 421/505] Added StringUtil::replaceAll() --- components/misc/stringops.hpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 9acd81710..12c222036 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -2,6 +2,7 @@ #define MISC_STRINGOPS_H #include +#include #include #include @@ -138,6 +139,35 @@ public: return notFound; } + + /** @brief Replaces all occurrences of a string in another string. + * + * @param str The string to operate on. + * @param what The string to replace. + * @param with The replacement string. + * @param what_len The length of the string to replace. + * @param with_len The length of the replacement string. + * + * @return A reference to the string passed in @p str. + */ + static std::string &replaceAll(std::string &str, const char *what, const char *with, + std::size_t what_len=std::string::npos, std::size_t with_len=std::string::npos) + { + if (what_len == std::string::npos) + what_len = strlen(what); + + if (with_len == std::string::npos) + with_len = strlen(with); + + std::size_t found; + std::size_t offset = 0; + while((found = str.find(what, offset, what_len)) != std::string::npos) + { + str.replace(found, what_len, with, with_len); + offset = found + with_len; + } + return str; + } }; } From 52b3507a2b63a45b96b802106b8ee89b2740de41 Mon Sep 17 00:00:00 2001 From: Alexander Stillich Date: Tue, 7 Nov 2017 23:10:58 +0100 Subject: [PATCH 422/505] Removed escape_hash_filter::mPrevious, removed usage of boost::replace_all --- components/files/escape.cpp | 15 ++++++++++----- components/files/escape.hpp | 11 ----------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/components/files/escape.cpp b/components/files/escape.cpp index 3c3d04d51..93ae9b885 100644 --- a/components/files/escape.cpp +++ b/components/files/escape.cpp @@ -1,6 +1,6 @@ #include "escape.hpp" -#include +#include namespace Files { @@ -8,7 +8,7 @@ namespace Files const int escape_hash_filter::sEscapeIdentifier = 'a'; const int escape_hash_filter::sHashIdentifier = 'h'; - escape_hash_filter::escape_hash_filter() : mNext(), mPrevious(), mSeenNonWhitespace(false), mFinishLine(false) + escape_hash_filter::escape_hash_filter() : mSeenNonWhitespace(false), mFinishLine(false) { } @@ -26,9 +26,14 @@ namespace Files std::string EscapeHashString::processString(const std::string & str) { - std::string temp = boost::replace_all_copy(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#"); - auto format = std::string(1, (char)escape_hash_filter::sEscape); - boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, format); + std::string temp = str; + + static const char hash[] = { escape_hash_filter::sEscape, escape_hash_filter::sHashIdentifier }; + Misc::StringUtils::replaceAll(temp, hash, "#", 2, 1); + + static const char escape[] = { escape_hash_filter::sEscape, escape_hash_filter::sEscapeIdentifier }; + Misc::StringUtils::replaceAll(temp, escape, "@", 2, 1); + return temp; } diff --git a/components/files/escape.hpp b/components/files/escape.hpp index 64410f3ab..d01bd8d98 100644 --- a/components/files/escape.hpp +++ b/components/files/escape.hpp @@ -30,7 +30,6 @@ namespace Files private: std::queue mNext; - int mPrevious; bool mSeenNonWhitespace; bool mFinishLine; @@ -42,11 +41,9 @@ namespace Files if (mNext.empty()) { int character = boost::iostreams::get(src); - bool record = true; if (character == boost::iostreams::WOULD_BLOCK) { mNext.push(character); - record = false; } else if (character == EOF) { @@ -79,12 +76,6 @@ namespace Files } } else if (character == sEscape) - { - mNext.push(sEscape); - mNext.push(sEscapeIdentifier); - record = false; - } - else if (mPrevious == sEscape) { mNext.push(sEscape); mNext.push(sEscapeIdentifier); @@ -95,8 +86,6 @@ namespace Files } if (!mSeenNonWhitespace && !isspace(character)) mSeenNonWhitespace = true; - if (record) - mPrevious = character; } int retval = mNext.front(); mNext.pop(); From 93e9df15c999ddb42fb2f9650cced5beed162310 Mon Sep 17 00:00:00 2001 From: Alexander Stillich Date: Tue, 7 Nov 2017 23:20:10 +0100 Subject: [PATCH 423/505] Fixed parameter naming --- components/misc/stringops.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 12c222036..9f4931d72 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -145,26 +145,26 @@ public: * @param str The string to operate on. * @param what The string to replace. * @param with The replacement string. - * @param what_len The length of the string to replace. - * @param with_len The length of the replacement string. + * @param whatLen The length of the string to replace. + * @param withLen The length of the replacement string. * * @return A reference to the string passed in @p str. */ static std::string &replaceAll(std::string &str, const char *what, const char *with, - std::size_t what_len=std::string::npos, std::size_t with_len=std::string::npos) + std::size_t whatLen=std::string::npos, std::size_t withLen=std::string::npos) { - if (what_len == std::string::npos) - what_len = strlen(what); + if (whatLen == std::string::npos) + whatLen = strlen(what); - if (with_len == std::string::npos) - with_len = strlen(with); + if (withLen == std::string::npos) + withLen = strlen(with); std::size_t found; std::size_t offset = 0; - while((found = str.find(what, offset, what_len)) != std::string::npos) + while((found = str.find(what, offset, whatLen)) != std::string::npos) { - str.replace(found, what_len, with, with_len); - offset = found + with_len; + str.replace(found, whatLen, with, withLen); + offset = found + withLen; } return str; } From 6e4f6c4bd5b5b7e8be7573693ad39f9111b7a65f Mon Sep 17 00:00:00 2001 From: Grigorii Latyshev Date: Mon, 13 Nov 2017 21:36:55 +0100 Subject: [PATCH 424/505] Change abs to std::abs --- apps/openmw/mwmechanics/aipursue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index 27d4ab0cb..fd8b5752a 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -55,7 +55,7 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte float pathTolerance = 100.0; if (pathTo(actor, dest, duration, pathTolerance) && - abs(dest.mZ - aPos.pos[2]) < pathTolerance) // check the true distance in case the target is far away in Z-direction + std::abs(dest.mZ - aPos.pos[2]) < pathTolerance) // check the true distance in case the target is far away in Z-direction { target.getClass().activate(target,actor).get()->execute(actor); //Arrest player when reached return true; From 5a93b6a324f0bcf5c4ac7a644288616bf5f35f9f Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 15 Nov 2017 16:29:01 +0100 Subject: [PATCH 425/505] Enable word-wrapping for the console history --- files/mygui/openmw_console.layout | 1 + 1 file changed, 1 insertion(+) diff --git a/files/mygui/openmw_console.layout b/files/mygui/openmw_console.layout index 103cdcf14..a58327a48 100644 --- a/files/mygui/openmw_console.layout +++ b/files/mygui/openmw_console.layout @@ -13,6 +13,7 @@ + From 7c5d2a1ac4d41720d34c51574bfd67c7c98bdba8 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 15 Nov 2017 16:29:50 +0100 Subject: [PATCH 426/505] Update dialogue topics list after result script is run Regression from 0.42. --- apps/openmw/mwgui/dialogue.cpp | 14 +++++++++++++- apps/openmw/mwgui/dialogue.hpp | 3 ++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 8a7ae85ea..14bbe81ef 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -45,6 +45,11 @@ namespace MWGui mWindow->addResponse(title, text, mNeedMargin); } + void updateTopics() + { + mWindow->updateTopics(); + } + private: DialogueWindow* mWindow; bool mNeedMargin; @@ -91,6 +96,7 @@ namespace MWGui type = MWBase::MechanicsManager::PT_Bribe1000; MWBase::Environment::get().getDialogueManager()->persuade(type, mCallback.get()); + mCallback->updateTopics(); setVisible(false); } @@ -395,6 +401,8 @@ namespace MWGui else if (topic == gmst.find("sRepair")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair, mPtr); } + else + updateTopics(); } } @@ -432,7 +440,9 @@ namespace MWGui setTitle(mPtr.getClass().getName(mPtr)); - updateTopicsPane(); + updateTopics(); + updateTopicsPane(); // force update for new services + updateDisposition(); restock(); } @@ -620,11 +630,13 @@ namespace MWGui void DialogueWindow::onTopicActivated(const std::string &topicId) { MWBase::Environment::get().getDialogueManager()->keywordSelected(topicId, mCallback.get()); + updateTopics(); } void DialogueWindow::onChoiceActivated(int id) { MWBase::Environment::get().getDialogueManager()->questionAnswered(id, mCallback.get()); + updateTopics(); } void DialogueWindow::onGoodbyeActivated() diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 277032513..2538602c6 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -131,8 +131,9 @@ namespace MWGui void onFrame(float dt); void clear() { resetReference(); } - protected: void updateTopics(); + + protected: void updateTopicsPane(); bool isCompanion(const MWWorld::Ptr& actor); bool isCompanion(); From c36d250044228b2af0b46324ccf4adbd2ff278f2 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 15 Nov 2017 16:30:21 +0100 Subject: [PATCH 427/505] Parse dialogue text for keywords after the resultscript runs (Fixes #4210) --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 88e65e535..1f6de04e5 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -77,6 +77,7 @@ namespace MWDialogue void DialogueManager::parseText (const std::string& text) { + updateActorKnownTopics(); std::vector hypertext = HyperTextParser::parseHyperText(text); for (std::vector::iterator tok = hypertext.begin(); tok != hypertext.end(); ++tok) @@ -145,18 +146,13 @@ namespace MWDialogue // TODO play sound } - // first topics update so that parseText knows the keywords to highlight - updateActorKnownTopics(); - - parseText (info->mResponse); MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); callback->addResponse("", Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript, mActor); mLastTopic = it->mId; - // update topics again to accommodate changes resulting from executeScript - updateActorKnownTopics(); + parseText (info->mResponse); return true; } @@ -252,8 +248,6 @@ namespace MWDialogue const ESM::DialInfo* info = filter.search(dialogue, true); if (info) { - parseText (info->mResponse); - std::string title; if (dialogue.mType==ESM::Dialogue::Persuasion) { @@ -292,6 +286,8 @@ namespace MWDialogue executeScript (info->mResultScript, mActor); + parseText (info->mResponse); + mLastTopic = topic; } } From 60fba7acd83f13e38465f23fec13c631818c7574 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 15 Nov 2017 16:43:36 +0100 Subject: [PATCH 428/505] Fix reorder warning --- apps/openmw/mwmechanics/character.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 6de18fe62..016d88289 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -196,8 +196,6 @@ class CharacterController : public MWRender::Animation::TextKeyListener float mSecondsOfSwimming; float mSecondsOfRunning; - float mTimeUntilWake; - MWWorld::ConstPtr mHeadTrackTarget; float mTurnAnimationThreshold; // how long to continue playing turning animation after actor stopped turning @@ -206,6 +204,8 @@ class CharacterController : public MWRender::Animation::TextKeyListener bool mAttackingOrSpell; + float mTimeUntilWake; + void setAttackTypeBasedOnMovement(); void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false); From 35d68f038d4dc7d3255e1b3feebdeba90a7249a4 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 15 Nov 2017 16:29:50 +0100 Subject: [PATCH 429/505] Update dialogue topics list after result script is run Regression from 0.42. --- apps/openmw/mwgui/dialogue.cpp | 14 +++++++++++++- apps/openmw/mwgui/dialogue.hpp | 3 ++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 8a7ae85ea..14bbe81ef 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -45,6 +45,11 @@ namespace MWGui mWindow->addResponse(title, text, mNeedMargin); } + void updateTopics() + { + mWindow->updateTopics(); + } + private: DialogueWindow* mWindow; bool mNeedMargin; @@ -91,6 +96,7 @@ namespace MWGui type = MWBase::MechanicsManager::PT_Bribe1000; MWBase::Environment::get().getDialogueManager()->persuade(type, mCallback.get()); + mCallback->updateTopics(); setVisible(false); } @@ -395,6 +401,8 @@ namespace MWGui else if (topic == gmst.find("sRepair")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair, mPtr); } + else + updateTopics(); } } @@ -432,7 +440,9 @@ namespace MWGui setTitle(mPtr.getClass().getName(mPtr)); - updateTopicsPane(); + updateTopics(); + updateTopicsPane(); // force update for new services + updateDisposition(); restock(); } @@ -620,11 +630,13 @@ namespace MWGui void DialogueWindow::onTopicActivated(const std::string &topicId) { MWBase::Environment::get().getDialogueManager()->keywordSelected(topicId, mCallback.get()); + updateTopics(); } void DialogueWindow::onChoiceActivated(int id) { MWBase::Environment::get().getDialogueManager()->questionAnswered(id, mCallback.get()); + updateTopics(); } void DialogueWindow::onGoodbyeActivated() diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 277032513..2538602c6 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -131,8 +131,9 @@ namespace MWGui void onFrame(float dt); void clear() { resetReference(); } - protected: void updateTopics(); + + protected: void updateTopicsPane(); bool isCompanion(const MWWorld::Ptr& actor); bool isCompanion(); From 36f4f0ef85ffe74ab27fabe68f02f7c569cc1559 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 16 Nov 2017 17:56:44 +0100 Subject: [PATCH 430/505] Don't increase simulationTime while the game is minimized (Fixes #4211) --- apps/openmw/engine.cpp | 23 +++++++++++------------ apps/openmw/engine.hpp | 2 +- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 3e5ab7ce6..e2b63232d 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -79,12 +79,14 @@ void OMW::Engine::executeLocalScripts() } } -void OMW::Engine::frame(float frametime) +bool OMW::Engine::frame(float frametime) { try { mStartTick = mViewer->getStartTick(); + mEnvironment.setFrameDuration(frametime); + // update input mEnvironment.getInputManager()->update(frametime, false); @@ -92,7 +94,7 @@ void OMW::Engine::frame(float frametime) // If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures (fixed in MyGUI 3.3.2), // and destroyed widgets will not be deleted (not fixed yet, https://github.com/MyGUI/mygui/issues/21) if (!mEnvironment.getInputManager()->isWindowVisible()) - return; + return false; // sound if (mUseSound) @@ -187,8 +189,9 @@ void OMW::Engine::frame(float frametime) } catch (const std::exception& e) { - std::cerr << "Error in framelistener: " << e.what() << std::endl; + std::cerr << "Error in frame: " << e.what() << std::endl; } + return true; } OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) @@ -686,17 +689,9 @@ void OMW::Engine::go() frameTimer.setStartTick(); dt = std::min(dt, 0.2); - bool guiActive = mEnvironment.getWindowManager()->isGuiMode(); - if (!guiActive) - simulationTime += dt; - mViewer->advance(simulationTime); - mEnvironment.setFrameDuration(dt); - - frame(dt); - - if (!mEnvironment.getInputManager()->isWindowVisible()) + if (!frame(dt)) { OpenThreads::Thread::microSleep(5000); continue; @@ -709,6 +704,10 @@ void OMW::Engine::go() mEnvironment.getWorld()->updateWindowManager(); mViewer->renderingTraversals(); + + bool guiActive = mEnvironment.getWindowManager()->isGuiMode(); + if (!guiActive) + simulationTime += dt; } mEnvironment.limitFrameRate(frameTimer.time_s()); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index bf144bfed..2fff91c7e 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -118,7 +118,7 @@ namespace OMW void executeLocalScripts(); - void frame (float dt); + bool frame (float dt); /// Load settings from various files, returns the path to the user settings file std::string loadSettings (Settings::Manager & settings); From 7e0662cf8196907cd015451af2c8cb1539e07102 Mon Sep 17 00:00:00 2001 From: Testman Date: Fri, 17 Nov 2017 11:14:33 +0100 Subject: [PATCH 431/505] Update scripts repo link Change repo name from PluginExamples to CoreScripts. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ba8dd4902..025618f9d 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Project Status TES3MP is now playable in most respects. Player and NPC movement, animations, combat and spell casting are properly synchronized with small exceptions, as is picking up and dropping items in the world, using doors and levers, and adding and removing items from containers. Journal entries, faction stats and dialogue topics are also synchronized, allowing the majority of quests to work fine. -[Serverside Lua scripts](https://github.com/TES3MP/PluginExamples) are used to save and load the state of most of the aforementioned. +[Serverside Lua scripts](https://github.com/TES3MP/CoreScripts) are used to save and load the state of most of the aforementioned. Contributing -------------- From ea2bbce68a6c70d3cfb3de187ba73bb99e6c9187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sat, 18 Nov 2017 19:27:09 +0100 Subject: [PATCH 432/505] Fix memory leak in WindowManager --- apps/openmw/mwgui/windowmanagerimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index ccdd6916c..4992716aa 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -530,6 +530,7 @@ namespace MWGui delete mDragAndDrop; delete mSoulgemDialog; delete mCursorManager; + delete mToolTips; cleanupGarbage(); From f896c9acb63b9d6fb1e2274baf21e5beab0057b7 Mon Sep 17 00:00:00 2001 From: jbo-85 Date: Sun, 19 Nov 2017 11:56:24 +0100 Subject: [PATCH 433/505] Fix search paths in FindSDL2.cmake to find SDL2 built from source --- cmake/FindSDL2.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake index 25105f1e2..4f2be8c42 100644 --- a/cmake/FindSDL2.cmake +++ b/cmake/FindSDL2.cmake @@ -70,10 +70,10 @@ endif() libfind_pkg_detect(SDL2 sdl2 FIND_PATH SDL.h HINTS $ENV{SDL2DIR} - PATH_SUFFIXES include SDL2 + PATH_SUFFIXES include SDL2 include/SDL2 FIND_LIBRARY SDL2 HINTS $ENV{SDL2DIR} - PATH_SUFFIXES ${_sdl_lib_suffix} + PATH_SUFFIXES lib ${_sdl_lib_suffix} ) libfind_version_n_header(SDL2 NAMES SDL_version.h DEFINES SDL_MAJOR_VERSION SDL_MINOR_VERSION SDL_PATCHLEVEL) @@ -85,7 +85,7 @@ IF(NOT SDL2_BUILDING_LIBRARY AND NOT APPLE) libfind_pkg_detect(SDL2MAIN sdl2 FIND_LIBRARY SDL2main HINTS $ENV{SDL2DIR} - PATH_SUFFIXES ${_sdl_lib_suffix} + PATH_SUFFIXES lib ${_sdl_lib_suffix} ) set(SDL2MAIN_FIND_QUIETLY TRUE) libfind_process(SDL2MAIN) From 60d0c83cca7664a5d300db0004d5b45eda1dcbc0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 20 Nov 2017 17:39:28 +0400 Subject: [PATCH 434/505] Handle 128px Tx_menubook_topics textures --- apps/openmw/mwgui/journalwindow.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 30a440b58..3fbe44f95 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -203,9 +203,20 @@ namespace int cancelLeft = getWidget(CancelBTN)->getPosition().left; int cancelRight = getWidget(CancelBTN)->getPosition().left + getWidget(CancelBTN)->getSize().width; - getWidget(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); getWidget(QuestsBTN)->setPosition(cancelRight, getWidget(QuestsBTN)->getPosition().top); + // Usually Topics, Quests, and Cancel buttons have the 64px width, so we can place the Topics left-up from the Cancel button, and the Quests right-up from the Cancel button. + // But in some installations, e.g. German one, the Topics button has the 128px width, so we should place it exactly left from the Quests button. + if (getWidget(TopicsBTN)->getSize().width == 64) + { + getWidget(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); + } + else + { + int questLeft = getWidget(QuestsBTN)->getPosition().left; + getWidget(TopicsBTN)->setPosition(questLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); + } + mQuestMode = false; mAllQuests = false; mOptionsMode = false; From 4dcaf040e670809af60a8c915b0ff113e8dd4641 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 4 Aug 2017 20:21:13 +0400 Subject: [PATCH 435/505] A Russian journal index --- apps/openmw/mwgui/journalbooks.cpp | 14 ++++++++------ apps/openmw/mwgui/journalviewmodel.cpp | 24 +++++++++++++++++++++--- apps/openmw/mwgui/journalviewmodel.hpp | 4 ++-- apps/openmw/mwgui/journalwindow.cpp | 4 ++-- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 5634eb080..19a2a9afe 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -224,20 +224,22 @@ book JournalBooks::createTopicIndexBook () BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); - for (int i = 0; i < 26; ++i) + for (int i = 0; i < 32; ++i) { - char ch = 'A' + i; - char buffer [32]; - sprintf (buffer, "( %c )", ch); + sprintf(buffer, "( %c%c )", 0xd0, 0x90 + i); // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, - textColours.journalTopicPressed, ch); + textColours.journalTopicPressed, i+1); + + // Words can not be started with these characters + if (i == 26 || i == 28) + continue; - if (i == 13) + if (i == 15) typesetter->sectionBreak (); typesetter->write (style, to_utf8_span (buffer)); diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index b5d08eec6..02103280b 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -305,18 +305,36 @@ struct JournalViewModelImpl : JournalViewModel visitor (toUtf8Span (topic.getName())); } - void visitTopicNamesStartingWith (char character, std::function < void (const std::string&) > visitor) const + void visitTopicNamesStartingWith (int index, std::function < void (const std::string&) > visitor) const { MWBase::Journal * journal = MWBase::Environment::get().getJournal(); for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { - if (i->first [0] != Misc::StringUtils::toLower(character)) + if (i->first.length() < 2) + continue; + + unsigned char byte1 = i->first[0]; + unsigned char byte2 = i->first[1]; + + // Upper case + if (byte1 == 0xd0 && byte2 >= 0xb0 && byte2 < 0xc0) + byte2 -= 32; + + if (byte1 == 0xd1 && byte2 >= 0x80 && byte2 < 0x90) + { + byte1 -= 1; + byte2 += 32; + } + + // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 + // so we can use 0xd08f + index + // (index is a position of letter in alphabet, begins from 1) + if (byte1 != 0xd0 || byte2 != 0x8f + index) continue; visitor (i->second.getName()); } - } struct TopicEntryImpl : BaseEntry diff --git a/apps/openmw/mwgui/journalviewmodel.hpp b/apps/openmw/mwgui/journalviewmodel.hpp index 3edde3d31..88f8acd55 100644 --- a/apps/openmw/mwgui/journalviewmodel.hpp +++ b/apps/openmw/mwgui/journalviewmodel.hpp @@ -75,8 +75,8 @@ namespace MWGui /// provides the name of the topic specified by its id virtual void visitTopicName (TopicId topicId, std::function visitor) const = 0; - /// walks over the topics whose names start with the specified character providing the topics name - virtual void visitTopicNamesStartingWith (char character, std::function < void (const std::string&) > visitor) const = 0; + /// walks over the topics whose names start with the character, specified by its index in the alphabet, providing the topics name + virtual void visitTopicNamesStartingWith (int index, std::function < void (const std::string&) > visitor) const = 0; /// walks over the topic entries for the topic specified by its identifier virtual void visitTopicEntries (TopicId topicId, std::function visitor) const = 0; diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 105f95085..b4279e03d 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -431,7 +431,7 @@ namespace MWBase::Environment::get().getWindowManager()->playSound("book page"); } - void notifyIndexLinkClicked (MWGui::TypesetBook::InteractiveId character) + void notifyIndexLinkClicked (MWGui::TypesetBook::InteractiveId index) { setVisible (LeftTopicIndex, false); setVisible (RightTopicIndex, false); @@ -444,7 +444,7 @@ namespace AddNamesToList add(list); - mModel->visitTopicNamesStartingWith((char) character, add); + mModel->visitTopicNamesStartingWith(index, add); list->adjustSize(); From a391990f2a52695b3c56afedaea5ffb80581f1e4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 20 Nov 2017 21:30:46 +0400 Subject: [PATCH 436/505] Provide multibyte toLower() and single chars comparator --- apps/openmw/mwgui/journalviewmodel.cpp | 46 ++++++++++++++++---------- components/misc/stringops.hpp | 30 +++++++++++++++++ 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 02103280b..33935f040 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -311,29 +311,39 @@ struct JournalViewModelImpl : JournalViewModel for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { - if (i->first.length() < 2) - continue; - unsigned char byte1 = i->first[0]; - unsigned char byte2 = i->first[1]; + // First, check for two-byte UTF-8 symbols, e.g. Cyrillic ones + // TODO: check which language journal index is using + if ((byte1 == 0xd0 || byte1 == 0xd1) && i->first.length() >= 2) + { + unsigned char byte2 = i->first[1]; - // Upper case - if (byte1 == 0xd0 && byte2 >= 0xb0 && byte2 < 0xc0) - byte2 -= 32; + std::pair symbol = Misc::StringUtils::toLower(byte1, byte2); - if (byte1 == 0xd1 && byte2 >= 0x80 && byte2 < 0x90) - { - byte1 -= 1; - byte2 += 32; - } + // CYRILLIC LETTER A - CYRILLIC LETTER PE + // index from 1 to 16 + if (symbol.first == 0xd0 && symbol.second >= (0xaf + index) && symbol.second < (0xbf + index) && symbol.second == (0xaf + index)) + { + visitor (i->second.getName()); + continue; + } - // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 - // so we can use 0xd08f + index - // (index is a position of letter in alphabet, begins from 1) - if (byte1 != 0xd0 || byte2 != 0x8f + index) - continue; + // CYRILLIC LETTERL R - CYRILLIC LETTER YA + // index from 17 to 32 + if (symbol.first == 0xd1 && symbol.second >= (0x6f + index) && symbol.second < (0x7f + index) && symbol.second == (0x6f + index)) + { + visitor (i->second.getName()); + continue; + } + } + else + { + // Otherwise check for regular Latin symbols, 0x61 = 'a' + if (i->first [0] != 0x60 + index) + continue; - visitor (i->second.getName()); + visitor (i->second.getName()); + } } } diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 9acd81710..97865a44c 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -55,6 +55,36 @@ public: }; } + static std::pair toLower(unsigned char byte1, unsigned char byte2) + { + std::pair symbol = std::make_pair(byte1, byte2); + // CYRILLIC CAPITAL IO + if (symbol.first == 0xd0 && symbol.second == 0x01) + { + symbol.first++; + symbol.second = 0x91; + } + // CYRILLIC CAPITAL A - CYRILLIC CAPITAL PE + else if (symbol.first == 0xd0 && symbol.second >= 0x90 && symbol.second < 0xa0) + { + symbol.second += 0x20; + } + // CYRILLIC CAPITAL R - CYRILLIC CAPITAL YA + else if (symbol.first == 0xd0 && symbol.second >= 0xa0 && symbol.second < 0xb0) + { + symbol.first++; + symbol.second -= 0x20; + } + // Other symbols + else + { + symbol.first = toLower(symbol.first); + symbol.second = toLower(symbol.second); + } + + return symbol; + } + static bool ciLess(const std::string &x, const std::string &y) { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end(), ci()); } From ce5bdd636183691ea7187698cb370cbf154bf522 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 20 Nov 2017 22:25:53 +0400 Subject: [PATCH 437/505] Split the JournalBooks::createTopicIndexBook() --- apps/openmw/mwgui/journalbooks.cpp | 44 ++++++++++++++++++++++++++++-- apps/openmw/mwgui/journalbooks.hpp | 2 ++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 19a2a9afe..b4f9147b5 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -217,19 +217,59 @@ book JournalBooks::createQuestBook (const std::string& questName) } book JournalBooks::createTopicIndexBook () +{ + // TODO: determine actual index alphabet + bool isRussian = true; + + BookTypesetter::Ptr typesetter = isRussian ? createCyrillicJournalIndex() : createLatinJournalIndex(); + + return typesetter->complete (); +} + +BookTypesetter::Ptr JournalBooks::createLatinJournalIndex () { BookTypesetter::Ptr typesetter = BookTypesetter::create (92, 250); typesetter->setSectionAlignment (BookTypesetter::AlignCenter); - BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); + for (int i = 0; i < 26; ++i) + { + char ch = 'A' + i; + char buffer [32]; + + sprintf (buffer, "( %c )", ch); + + // TODO: find a way to store a multibyte character in the InteractiveId (this is a intptr_t) + const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); + BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, + textColours.journalTopicOver, + textColours.journalTopicPressed, i+1); + if (i == 13) + typesetter->sectionBreak (); + + typesetter->write (style, to_utf8_span (buffer)); + typesetter->lineBreak (); + } + + return typesetter; +} + +BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () +{ + BookTypesetter::Ptr typesetter = BookTypesetter::create (92, 250); + + typesetter->setSectionAlignment (BookTypesetter::AlignCenter); + + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); for (int i = 0; i < 32; ++i) { char buffer [32]; sprintf(buffer, "( %c%c )", 0xd0, 0x90 + i); // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 + // TODO: find a way to store a multibyte character in the InteractiveId (this is a intptr_t) const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, @@ -246,7 +286,7 @@ book JournalBooks::createTopicIndexBook () typesetter->lineBreak (); } - return typesetter->complete (); + return typesetter; } BookTypesetter::Ptr JournalBooks::createTypesetter () diff --git a/apps/openmw/mwgui/journalbooks.hpp b/apps/openmw/mwgui/journalbooks.hpp index 8f87825f0..769f05823 100644 --- a/apps/openmw/mwgui/journalbooks.hpp +++ b/apps/openmw/mwgui/journalbooks.hpp @@ -24,6 +24,8 @@ namespace MWGui private: BookTypesetter::Ptr createTypesetter (); + BookTypesetter::Ptr createLatinJournalIndex (); + BookTypesetter::Ptr createCyrillicJournalIndex (); }; } From 9fda3b6db479b61a5e52c4cdce7208bdabac72a7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 20 Nov 2017 23:11:28 +0100 Subject: [PATCH 438/505] Fix NumericEditBox behavior broken by switch to std::stoi For some reason stoi doesn't throw an error for '1foo' while 'foo1' does. Now the edit box flat out rejects any non-digit key events. --- components/widgets/numericeditbox.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/widgets/numericeditbox.cpp b/components/widgets/numericeditbox.cpp index 6e884a091..ee2c30a7b 100644 --- a/components/widgets/numericeditbox.cpp +++ b/components/widgets/numericeditbox.cpp @@ -87,7 +87,7 @@ namespace Gui setValue(std::max(mValue-1, mMinValue)); eventValueChanged(mValue); } - else + else if (character == 0 || (character >= '0' && character <= '9')) Base::onKeyButtonPressed(key, character); } From a3f821cdcd60cf7ad333c3b0af0042424e7c27e1 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 20 Nov 2017 23:28:51 +0100 Subject: [PATCH 439/505] Disable keyboard for trade +/- buttons For one, because their RepeatClick handler breaks the keyboard function, and because its redundant anyway (just press Up/Down arrow with the edit box focused to do the same thing) --- files/mygui/openmw_trade_window.layout | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index ebfe9b30f..4e2fc6e6d 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -43,9 +43,11 @@ + + From cc3c27f2418cd50ad7930d701c793d0d2bfda679 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 20 Nov 2017 23:55:15 +0100 Subject: [PATCH 440/505] Clean up layout files to use Spacer class --- files/mygui/openmw_alchemy_window.layout | 4 +--- files/mygui/openmw_chargen_birth.layout | 4 +--- files/mygui/openmw_chargen_class.layout | 4 +--- files/mygui/openmw_chargen_create_class.layout | 4 +--- files/mygui/openmw_chargen_race.layout | 4 +--- files/mygui/openmw_chargen_review.layout | 4 +--- files/mygui/openmw_edit_effect.layout | 4 +--- files/mygui/openmw_edit_note.layout | 4 +--- files/mygui/openmw_enchanting_dialog.layout | 8 ++------ files/mygui/openmw_levelup_dialog.layout | 4 +--- files/mygui/openmw_recharge_dialog.layout | 4 +--- files/mygui/openmw_repair.layout | 4 +--- files/mygui/openmw_spellcreation_dialog.layout | 4 +--- files/mygui/openmw_tooltips.layout | 8 ++------ files/mygui/openmw_wait_dialog.layout | 4 +--- 15 files changed, 17 insertions(+), 51 deletions(-) diff --git a/files/mygui/openmw_alchemy_window.layout b/files/mygui/openmw_alchemy_window.layout index 8a1bf1347..a8e5431fb 100644 --- a/files/mygui/openmw_alchemy_window.layout +++ b/files/mygui/openmw_alchemy_window.layout @@ -76,9 +76,7 @@ - - - + diff --git a/files/mygui/openmw_chargen_birth.layout b/files/mygui/openmw_chargen_birth.layout index d93249c03..a137d83d1 100644 --- a/files/mygui/openmw_chargen_birth.layout +++ b/files/mygui/openmw_chargen_birth.layout @@ -17,9 +17,7 @@ - - - + diff --git a/files/mygui/openmw_chargen_class.layout b/files/mygui/openmw_chargen_class.layout index d875fae22..98c8e4fde 100644 --- a/files/mygui/openmw_chargen_class.layout +++ b/files/mygui/openmw_chargen_class.layout @@ -74,9 +74,7 @@ - - - + diff --git a/files/mygui/openmw_chargen_create_class.layout b/files/mygui/openmw_chargen_create_class.layout index e2920c742..c04cfe064 100644 --- a/files/mygui/openmw_chargen_create_class.layout +++ b/files/mygui/openmw_chargen_create_class.layout @@ -75,9 +75,7 @@ - - - + diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index 04bd9cc53..31f0436d5 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -76,9 +76,7 @@ - - - + diff --git a/files/mygui/openmw_chargen_review.layout b/files/mygui/openmw_chargen_review.layout index 1099fcd3b..927296fad 100644 --- a/files/mygui/openmw_chargen_review.layout +++ b/files/mygui/openmw_chargen_review.layout @@ -112,9 +112,7 @@ - - - + diff --git a/files/mygui/openmw_edit_effect.layout b/files/mygui/openmw_edit_effect.layout index 376e87efa..c2429d24b 100644 --- a/files/mygui/openmw_edit_effect.layout +++ b/files/mygui/openmw_edit_effect.layout @@ -94,9 +94,7 @@ - - - + diff --git a/files/mygui/openmw_edit_note.layout b/files/mygui/openmw_edit_note.layout index 7039c719e..edf53bde7 100644 --- a/files/mygui/openmw_edit_note.layout +++ b/files/mygui/openmw_edit_note.layout @@ -16,9 +16,7 @@ - - - + diff --git a/files/mygui/openmw_enchanting_dialog.layout b/files/mygui/openmw_enchanting_dialog.layout index 6a08e6fd0..ed3cfb03e 100644 --- a/files/mygui/openmw_enchanting_dialog.layout +++ b/files/mygui/openmw_enchanting_dialog.layout @@ -36,9 +36,7 @@ - - - + @@ -141,9 +139,7 @@ - - - + diff --git a/files/mygui/openmw_levelup_dialog.layout b/files/mygui/openmw_levelup_dialog.layout index 66855373a..7849d507f 100644 --- a/files/mygui/openmw_levelup_dialog.layout +++ b/files/mygui/openmw_levelup_dialog.layout @@ -156,9 +156,7 @@ - - - + diff --git a/files/mygui/openmw_recharge_dialog.layout b/files/mygui/openmw_recharge_dialog.layout index 200d345e3..626039065 100644 --- a/files/mygui/openmw_recharge_dialog.layout +++ b/files/mygui/openmw_recharge_dialog.layout @@ -27,9 +27,7 @@ - - - + diff --git a/files/mygui/openmw_repair.layout b/files/mygui/openmw_repair.layout index abc429594..bf58b6c81 100644 --- a/files/mygui/openmw_repair.layout +++ b/files/mygui/openmw_repair.layout @@ -34,9 +34,7 @@ - - - + diff --git a/files/mygui/openmw_spellcreation_dialog.layout b/files/mygui/openmw_spellcreation_dialog.layout index e14674ad6..e7c27655d 100644 --- a/files/mygui/openmw_spellcreation_dialog.layout +++ b/files/mygui/openmw_spellcreation_dialog.layout @@ -68,9 +68,7 @@ - - - + diff --git a/files/mygui/openmw_tooltips.layout b/files/mygui/openmw_tooltips.layout index c038066f1..bdc224ecd 100644 --- a/files/mygui/openmw_tooltips.layout +++ b/files/mygui/openmw_tooltips.layout @@ -103,9 +103,7 @@ - - - + @@ -122,9 +120,7 @@ - - - + diff --git a/files/mygui/openmw_wait_dialog.layout b/files/mygui/openmw_wait_dialog.layout index 4bc60ceb4..b02db3764 100644 --- a/files/mygui/openmw_wait_dialog.layout +++ b/files/mygui/openmw_wait_dialog.layout @@ -26,9 +26,7 @@ - - - + From a83a43e37613667b956752be5f1fff049ca959ce Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 21 Nov 2017 09:32:35 +0400 Subject: [PATCH 441/505] Determine when need to use the Cyrillic journal index --- apps/openmw/mwbase/windowmanager.hpp | 3 +++ apps/openmw/mwgui/journalbooks.cpp | 6 ++++-- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 416a7ad87..ffcbe0502 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -9,6 +9,8 @@ #include "../mwgui/mode.hpp" +#include + namespace Loading { class Listener; @@ -365,6 +367,7 @@ namespace MWBase virtual void writeFog(MWWorld::CellStore* cell) = 0; virtual const MWGui::TextColours& getTextColours() = 0; + virtual ToUTF8::FromType getEncoding() = 0; }; } diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index b4f9147b5..73796c381 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -5,6 +5,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include + #include "textcolours.hpp" @@ -218,8 +220,8 @@ book JournalBooks::createQuestBook (const std::string& questName) book JournalBooks::createTopicIndexBook () { - // TODO: determine actual index alphabet - bool isRussian = true; + ToUTF8::FromType encoding = MWBase::Environment::get().getWindowManager()->getEncoding(); + bool isRussian = (encoding == ToUTF8::WINDOWS_1251); BookTypesetter::Ptr typesetter = isRussian ? createCyrillicJournalIndex() : createLatinJournalIndex(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 97aedab81..920b8c1ac 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -205,6 +205,7 @@ namespace MWGui , mRestAllowed(true) , mFallbackMap(fallbackMap) , mShowOwned(0) + , mEncoding(encoding) , mVersionDescription(versionDescription) { float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); @@ -2174,4 +2175,8 @@ namespace MWGui return mTextColours; } + ToUTF8::FromType WindowManager::getEncoding() + { + return mEncoding; + } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index f74ba21a3..a1ec7cdb4 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -393,6 +393,7 @@ namespace MWGui void writeFog(MWWorld::CellStore* cell); virtual const MWGui::TextColours& getTextColours(); + virtual ToUTF8::FromType getEncoding(); private: const MWWorld::ESMStore* mStore; @@ -515,6 +516,8 @@ namespace MWGui int mShowOwned; + ToUTF8::FromType mEncoding; + std::string mVersionDescription; MWGui::TextColours mTextColours; From ea36956ff11b7d81f06d219da9e6370275a50bba Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 21 Nov 2017 10:00:53 +0400 Subject: [PATCH 442/505] Reworked trade window --- files/mygui/openmw_trade_window.layout | 45 ++++++++++++++------------ 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index 4e2fc6e6d..71dc04c55 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -3,7 +3,7 @@ - + @@ -34,34 +34,37 @@ - - - - - - - - - - - - - - + + + + + + + + + + + - - - + + + + + + + + + + + - - - + From ba91cd658b019dbf1ee93c4185333687c3e086a7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 21 Nov 2017 12:31:23 +0400 Subject: [PATCH 443/505] Convert topic name to Unicode --- apps/openmw/mwgui/journalbooks.cpp | 19 +++++++++--- apps/openmw/mwgui/journalviewmodel.cpp | 41 ++++++-------------------- apps/openmw/mwgui/journalviewmodel.hpp | 4 +-- components/misc/stringops.hpp | 39 ++++++++---------------- 4 files changed, 39 insertions(+), 64 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 49c1aa972..3b1463b45 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -6,10 +6,10 @@ #include "../mwbase/windowmanager.hpp" #include +#include #include "textcolours.hpp" - namespace { struct AddContent @@ -242,11 +242,17 @@ BookTypesetter::Ptr JournalBooks::createLatinJournalIndex () sprintf (buffer, "( %c )", ch); + char buffer2 [32]; + sprintf(buffer2, "%c", ch); + const char * c = buffer2; + Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + uint32_t first = stream.peek(); + // TODO: find a way to store a multibyte character in the InteractiveId (this is a intptr_t) const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, - textColours.journalTopicPressed, i+1); + textColours.journalTopicPressed, first); if (i == 13) typesetter->sectionBreak (); @@ -271,11 +277,16 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () sprintf(buffer, "( %c%c )", 0xd0, 0x90 + i); // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 - // TODO: find a way to store a multibyte character in the InteractiveId (this is a intptr_t) + char buffer2 [32]; + sprintf(buffer2, "%c%c", 0xd0, 0x90 + i); + const char * c = buffer2; + Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + uint32_t first = stream.peek(); + const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, - textColours.journalTopicPressed, i+1); + textColours.journalTopicPressed, first); // Words can not be started with these characters if (i == 26 || i == 28) diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 33935f040..3f8992e31 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -6,6 +6,8 @@ #include #include +#include +#include #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" @@ -305,45 +307,20 @@ struct JournalViewModelImpl : JournalViewModel visitor (toUtf8Span (topic.getName())); } - void visitTopicNamesStartingWith (int index, std::function < void (const std::string&) > visitor) const + void visitTopicNamesStartingWith (uint32_t character, std::function < void (const std::string&) > visitor) const { MWBase::Journal * journal = MWBase::Environment::get().getJournal(); for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { - unsigned char byte1 = i->first[0]; - // First, check for two-byte UTF-8 symbols, e.g. Cyrillic ones - // TODO: check which language journal index is using - if ((byte1 == 0xd0 || byte1 == 0xd1) && i->first.length() >= 2) - { - unsigned char byte2 = i->first[1]; - - std::pair symbol = Misc::StringUtils::toLower(byte1, byte2); - - // CYRILLIC LETTER A - CYRILLIC LETTER PE - // index from 1 to 16 - if (symbol.first == 0xd0 && symbol.second >= (0xaf + index) && symbol.second < (0xbf + index) && symbol.second == (0xaf + index)) - { - visitor (i->second.getName()); - continue; - } + const char * c = i->first.c_str(); + Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + uint32_t first = Misc::StringUtils::toUpper(stream.peek()); - // CYRILLIC LETTERL R - CYRILLIC LETTER YA - // index from 17 to 32 - if (symbol.first == 0xd1 && symbol.second >= (0x6f + index) && symbol.second < (0x7f + index) && symbol.second == (0x6f + index)) - { - visitor (i->second.getName()); - continue; - } - } - else - { - // Otherwise check for regular Latin symbols, 0x61 = 'a' - if (i->first [0] != 0x60 + index) - continue; + if (first != character) + continue; - visitor (i->second.getName()); - } + visitor (i->second.getName()); } } diff --git a/apps/openmw/mwgui/journalviewmodel.hpp b/apps/openmw/mwgui/journalviewmodel.hpp index 88f8acd55..01dcb49de 100644 --- a/apps/openmw/mwgui/journalviewmodel.hpp +++ b/apps/openmw/mwgui/journalviewmodel.hpp @@ -75,8 +75,8 @@ namespace MWGui /// provides the name of the topic specified by its id virtual void visitTopicName (TopicId topicId, std::function visitor) const = 0; - /// walks over the topics whose names start with the character, specified by its index in the alphabet, providing the topics name - virtual void visitTopicNamesStartingWith (int index, std::function < void (const std::string&) > visitor) const = 0; + /// walks over the topics whose names start with the character + virtual void visitTopicNamesStartingWith (uint32_t character, std::function < void (const std::string&) > visitor) const = 0; /// walks over the topic entries for the topic specified by its identifier virtual void visitTopicEntries (TopicId topicId, std::function visitor) const = 0; diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 0d9c2489f..5ce5360d1 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -56,34 +56,21 @@ public: }; } - static std::pair toLower(unsigned char byte1, unsigned char byte2) + static uint32_t toUpper(uint32_t ch) { - std::pair symbol = std::make_pair(byte1, byte2); - // CYRILLIC CAPITAL IO - if (symbol.first == 0xd0 && symbol.second == 0x01) - { - symbol.first++; - symbol.second = 0x91; - } - // CYRILLIC CAPITAL A - CYRILLIC CAPITAL PE - else if (symbol.first == 0xd0 && symbol.second >= 0x90 && symbol.second < 0xa0) - { - symbol.second += 0x20; - } - // CYRILLIC CAPITAL R - CYRILLIC CAPITAL YA - else if (symbol.first == 0xd0 && symbol.second >= 0xa0 && symbol.second < 0xb0) - { - symbol.first++; - symbol.second -= 0x20; - } - // Other symbols - else - { - symbol.first = toLower(symbol.first); - symbol.second = toLower(symbol.second); - } + // Russian alphabete + if (ch >= 0x0430 && ch < 0x0450) + ch -= 0x20; + + // Cyrillic YO character + if (ch == 0x0451) + ch -= 0x50; + + // Latin alphabete + if (ch >= 0x61 && ch < 0x80) + ch -= 0x20; - return symbol; + return ch; } static bool ciLess(const std::string &x, const std::string &y) { From 5f41f7c48df215f160a9418dd39595c954370cf8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 21 Nov 2017 12:59:47 +0400 Subject: [PATCH 444/505] Clean code up a bit --- apps/openmw/mwgui/journalbooks.cpp | 10 +++------- apps/openmw/mwgui/journalviewmodel.cpp | 3 +-- components/misc/stringops.hpp | 4 ++-- components/misc/utf8stream.hpp | 5 +++++ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 3b1463b45..68b1d8403 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -239,16 +239,13 @@ BookTypesetter::Ptr JournalBooks::createLatinJournalIndex () { char ch = 'A' + i; char buffer [32]; - sprintf (buffer, "( %c )", ch); char buffer2 [32]; sprintf(buffer2, "%c", ch); - const char * c = buffer2; - Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + Utf8Stream stream (buffer2); uint32_t first = stream.peek(); - // TODO: find a way to store a multibyte character in the InteractiveId (this is a intptr_t) const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, @@ -274,13 +271,12 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () for (int i = 0; i < 32; ++i) { char buffer [32]; - sprintf(buffer, "( %c%c )", 0xd0, 0x90 + i); // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 char buffer2 [32]; sprintf(buffer2, "%c%c", 0xd0, 0x90 + i); - const char * c = buffer2; - Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + + Utf8Stream stream (buffer2); uint32_t first = stream.peek(); const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 3f8992e31..d7b233ff3 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -313,8 +313,7 @@ struct JournalViewModelImpl : JournalViewModel for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { - const char * c = i->first.c_str(); - Utf8Stream stream ((unsigned char*) c,(unsigned char*) c + strlen(c)); + Utf8Stream stream (i->first.c_str()); uint32_t first = Misc::StringUtils::toUpper(stream.peek()); if (first != character) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 5ce5360d1..cec2a34a4 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -58,7 +58,7 @@ public: static uint32_t toUpper(uint32_t ch) { - // Russian alphabete + // Russian alphabet if (ch >= 0x0430 && ch < 0x0450) ch -= 0x20; @@ -66,7 +66,7 @@ public: if (ch == 0x0451) ch -= 0x50; - // Latin alphabete + // Latin alphabet if (ch >= 0x61 && ch < 0x80) ch -= 0x20; diff --git a/components/misc/utf8stream.hpp b/components/misc/utf8stream.hpp index 760015902..368374a64 100644 --- a/components/misc/utf8stream.hpp +++ b/components/misc/utf8stream.hpp @@ -18,6 +18,11 @@ public: { } + Utf8Stream (const char * str) : + cur ((unsigned char*) str), nxt ((unsigned char*) str), end ((unsigned char*) str + strlen(str)), val(Utf8Stream::sBadChar()) + { + } + Utf8Stream (std::pair range) : cur (range.first), nxt (range.first), end (range.second), val(Utf8Stream::sBadChar()) { From 67acb83b62861e865c0fd04ff19f8922ed74c8e7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 21 Nov 2017 13:27:33 +0400 Subject: [PATCH 445/505] Add missing include --- components/misc/stringops.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index cec2a34a4..1edb5ea61 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -1,6 +1,7 @@ #ifndef MISC_STRINGOPS_H #define MISC_STRINGOPS_H +#include #include #include #include From 2136003e1c32ff4f49be9f28f4d313d871430ba2 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 21 Nov 2017 22:43:56 +0000 Subject: [PATCH 446/505] Reapply commit a3f821cdc which got lost in a merge --- files/mygui/openmw_trade_window.layout | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index 71dc04c55..0af9d59fe 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -37,6 +37,7 @@ + @@ -50,6 +51,7 @@ + From 3571f7f41379833848467c50c0ef1879c105a68c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 22 Nov 2017 08:32:38 +0400 Subject: [PATCH 447/505] Remove getEncoding() from WindowManager --- apps/openmw/mwbase/windowmanager.hpp | 1 - apps/openmw/mwgui/journalbooks.cpp | 7 +++---- apps/openmw/mwgui/journalbooks.hpp | 6 +++++- apps/openmw/mwgui/journalwindow.cpp | 8 ++++---- apps/openmw/mwgui/journalwindow.hpp | 4 +++- apps/openmw/mwgui/windowmanagerimp.cpp | 7 +------ apps/openmw/mwgui/windowmanagerimp.hpp | 1 - 7 files changed, 16 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4a346a14f..6c866fbc2 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -351,7 +351,6 @@ namespace MWBase virtual void writeFog(MWWorld::CellStore* cell) = 0; virtual const MWGui::TextColours& getTextColours() = 0; - virtual ToUTF8::FromType getEncoding() = 0; virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text) = 0; }; } diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 68b1d8403..07dacd0c2 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -156,8 +156,8 @@ MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text) typedef TypesetBook::Ptr book; -JournalBooks::JournalBooks (JournalViewModel::Ptr model) : - mModel (model) +JournalBooks::JournalBooks (JournalViewModel::Ptr model, ToUTF8::FromType encoding) : + mModel (model), mEncoding(encoding) { } @@ -220,8 +220,7 @@ book JournalBooks::createQuestBook (const std::string& questName) book JournalBooks::createTopicIndexBook () { - ToUTF8::FromType encoding = MWBase::Environment::get().getWindowManager()->getEncoding(); - bool isRussian = (encoding == ToUTF8::WINDOWS_1251); + bool isRussian = (mEncoding == ToUTF8::WINDOWS_1251); BookTypesetter::Ptr typesetter = isRussian ? createCyrillicJournalIndex() : createLatinJournalIndex(); diff --git a/apps/openmw/mwgui/journalbooks.hpp b/apps/openmw/mwgui/journalbooks.hpp index 769f05823..aa36eecdf 100644 --- a/apps/openmw/mwgui/journalbooks.hpp +++ b/apps/openmw/mwgui/journalbooks.hpp @@ -4,6 +4,8 @@ #include "bookpage.hpp" #include "journalviewmodel.hpp" +#include + namespace MWGui { MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text); @@ -13,7 +15,7 @@ namespace MWGui typedef TypesetBook::Ptr Book; JournalViewModel::Ptr mModel; - JournalBooks (JournalViewModel::Ptr model); + JournalBooks (JournalViewModel::Ptr model, ToUTF8::FromType encoding); Book createEmptyJournalBook (); Book createJournalBook (); @@ -22,6 +24,8 @@ namespace MWGui Book createQuestBook (const std::string& questName); Book createTopicIndexBook (); + ToUTF8::FromType mEncoding; + private: BookTypesetter::Ptr createTypesetter (); BookTypesetter::Ptr createLatinJournalIndex (); diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 3c3205d91..a26f8d4ec 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -100,8 +100,8 @@ namespace return getWidget (name); } - JournalWindowImpl (MWGui::JournalViewModel::Ptr Model, bool questList) - : JournalBooks (Model), JournalWindow() + JournalWindowImpl (MWGui::JournalViewModel::Ptr Model, bool questList, ToUTF8::FromType encoding) + : JournalBooks (Model, encoding), JournalWindow() { center(); @@ -643,9 +643,9 @@ namespace } // glue the implementation to the interface -MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model, bool questList) +MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model, bool questList, ToUTF8::FromType encoding) { - return new JournalWindowImpl (Model, questList); + return new JournalWindowImpl (Model, questList, encoding); } MWGui::JournalWindow::JournalWindow() diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index c9bf0ef0a..62080f72e 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -3,6 +3,8 @@ #include "windowbase.hpp" +#include + #include namespace MWBase { class WindowManager; } @@ -16,7 +18,7 @@ namespace MWGui JournalWindow(); /// construct a new instance of the one JournalWindow implementation - static JournalWindow * create (std::shared_ptr Model, bool questList); + static JournalWindow * create (std::shared_ptr Model, bool questList, ToUTF8::FromType encoding); /// destroy this instance of the JournalWindow implementation virtual ~JournalWindow () {}; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c302313f2..2084786b3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -347,7 +347,7 @@ namespace MWGui mGuiModeStates[GM_Console] = GuiModeState(mConsole); bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds"); - JournalWindow* journal = JournalWindow::create(JournalViewModel::create (), questList); + JournalWindow* journal = JournalWindow::create(JournalViewModel::create (), questList, mEncoding); mWindows.push_back(journal); mGuiModeStates[GM_Journal] = GuiModeState(journal); mGuiModeStates[GM_Journal].mCloseSound = "book close"; @@ -2034,11 +2034,6 @@ namespace MWGui return mTextColours; } - ToUTF8::FromType WindowManager::getEncoding() - { - return mEncoding; - } - bool WindowManager::injectKeyPress(MyGUI::KeyCode key, unsigned int text) { if (!mKeyboardNavigation->injectKeyPress(key, text)) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index a264128b3..1d250f6d4 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -378,7 +378,6 @@ namespace MWGui void writeFog(MWWorld::CellStore* cell); virtual const MWGui::TextColours& getTextColours(); - virtual ToUTF8::FromType getEncoding(); virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text); From 86a17b1e3ed68cab4114bb14ea8307774f646f12 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 22 Nov 2017 09:06:54 +0400 Subject: [PATCH 448/505] Get rid of the redundant Utf8Stream when during journal index creation --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/journalbooks.cpp | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 6c866fbc2..f2b4a526d 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -351,6 +351,7 @@ namespace MWBase virtual void writeFog(MWWorld::CellStore* cell) = 0; virtual const MWGui::TextColours& getTextColours() = 0; + virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text) = 0; }; } diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 07dacd0c2..f3ee8162e 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -233,28 +233,26 @@ BookTypesetter::Ptr JournalBooks::createLatinJournalIndex () typesetter->setSectionAlignment (BookTypesetter::AlignCenter); + char ch = 'A'; + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); for (int i = 0; i < 26; ++i) { - char ch = 'A' + i; char buffer [32]; sprintf (buffer, "( %c )", ch); - char buffer2 [32]; - sprintf(buffer2, "%c", ch); - Utf8Stream stream (buffer2); - uint32_t first = stream.peek(); - const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, textColours.journalTopicOver, - textColours.journalTopicPressed, first); + textColours.journalTopicPressed, (uint32_t) ch); if (i == 13) typesetter->sectionBreak (); typesetter->write (style, to_utf8_span (buffer)); typesetter->lineBreak (); + + ch++; } return typesetter; @@ -267,15 +265,15 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () typesetter->setSectionAlignment (BookTypesetter::AlignCenter); BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); + + unsigned char ch[2] = {0xd0, 0x90}; // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 + for (int i = 0; i < 32; ++i) { char buffer [32]; - sprintf(buffer, "( %c%c )", 0xd0, 0x90 + i); // CYRILLIC CAPITAL A is a 0xd090 in UTF-8 + sprintf(buffer, "( %c%c )", ch[0], ch[1]); - char buffer2 [32]; - sprintf(buffer2, "%c%c", 0xd0, 0x90 + i); - - Utf8Stream stream (buffer2); + Utf8Stream stream ((char*) ch); uint32_t first = stream.peek(); const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); @@ -292,6 +290,8 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () typesetter->write (style, to_utf8_span (buffer)); typesetter->lineBreak (); + + ch[1]++; } return typesetter; From de42aa9d03842bc1c84acd76985a36261afd339d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 00:32:22 +0100 Subject: [PATCH 449/505] Make thrown projectiles rotate --- apps/openmw/mwworld/projectilemanager.cpp | 17 ++++++++++++++++- apps/openmw/mwworld/projectilemanager.hpp | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index ede8c34c4..1d53c1909 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -316,6 +316,8 @@ namespace MWWorld state.mIdArrow = projectile.getCellRef().getRefId(); state.mCasterHandle = actor; state.mAttackStrength = attackStrength; + state.mThrown = projectile.get()->mBase->mData.mType == ESM::Weapon::MarksmanThrown; + state.mTime = 0.0; MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); @@ -453,12 +455,25 @@ namespace MWWorld // gravity constant - must be way lower than the gravity affecting actors, since we're not // simulating aerodynamics at all it->mVelocity -= osg::Vec3f(0, 0, 627.2f * 0.1f) * duration; + it->mTime += duration; osg::Vec3f pos(it->mNode->getPosition()); osg::Vec3f newPos = pos + it->mVelocity * duration; osg::Quat orient; - orient.makeRotate(osg::Vec3f(0,1,0), it->mVelocity); + + orient.set( + osg::Matrixd::rotate(it->mThrown ? -1 * it->mTime : 0.0,osg::Vec3f(0,0,1)) * + osg::Matrixd::rotate(osg::PI / 2.0,osg::Vec3f(0,1,0)) * + osg::Matrixd::rotate(-1 * osg::PI / 2.0,osg::Vec3f(1,0,0)) * + osg::Matrixd::inverse( + osg::Matrixd::lookAt( + osg::Vec3f(0,0,0), + it->mVelocity, + osg::Vec3f(0,0,1)) + ) + ); + it->mNode->setAttitude(orient); it->mNode->setPosition(newPos); diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 0dfbf6080..1e0de4dbe 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -112,6 +112,8 @@ namespace MWWorld osg::Vec3f mVelocity; float mAttackStrength; + float mTime; + bool mThrown; }; std::vector mMagicBolts; From 4d384889af728c2ba76b3ef1aeb589bbbe29f999 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 23 Nov 2017 10:14:45 +0400 Subject: [PATCH 450/505] Fix the Topics button position if the Tribunal is not installed --- apps/openmw/mwgui/journalwindow.cpp | 52 +++++++++++++++-------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 3fbe44f95..3dc583ac2 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -161,6 +161,15 @@ namespace Gui::ImageButton* showActiveButton = getWidget(ShowActiveBTN); Gui::ImageButton* showAllButton = getWidget(ShowAllBTN); Gui::ImageButton* questsButton = getWidget(QuestsBTN); + + Gui::ImageButton* nextButton = getWidget(NextPageBTN); + if (nextButton->getSize().width == 64) + { + // english button has a 7 pixel wide strip of garbage on its right edge + nextButton->setSize(64-7, nextButton->getSize().height); + nextButton->setImageCoord(MyGUI::IntCoord(0,0,64-7,nextButton->getSize().height)); + } + if (!questList) { // If tribunal is not installed (-> no options button), we still want the Topics button available, @@ -176,6 +185,8 @@ namespace showActiveButton->setVisible(false); showAllButton->setVisible(false); questsButton->setVisible(false); + + adjustButton(TopicsBTN); } else { @@ -188,33 +199,24 @@ namespace adjustButton(ShowActiveBTN); adjustButton(OptionsBTN); adjustButton(QuestsBTN); - } - - Gui::ImageButton* nextButton = getWidget(NextPageBTN); - if (nextButton->getSize().width == 64) - { - // english button has a 7 pixel wide strip of garbage on its right edge - nextButton->setSize(64-7, nextButton->getSize().height); - nextButton->setImageCoord(MyGUI::IntCoord(0,0,64-7,nextButton->getSize().height)); - } - - adjustButton(TopicsBTN); - int topicsWidth = getWidget(TopicsBTN)->getSize().width; - int cancelLeft = getWidget(CancelBTN)->getPosition().left; - int cancelRight = getWidget(CancelBTN)->getPosition().left + getWidget(CancelBTN)->getSize().width; + adjustButton(TopicsBTN); + int topicsWidth = getWidget(TopicsBTN)->getSize().width; + int cancelLeft = getWidget(CancelBTN)->getPosition().left; + int cancelRight = getWidget(CancelBTN)->getPosition().left + getWidget(CancelBTN)->getSize().width; - getWidget(QuestsBTN)->setPosition(cancelRight, getWidget(QuestsBTN)->getPosition().top); + getWidget(QuestsBTN)->setPosition(cancelRight, getWidget(QuestsBTN)->getPosition().top); - // Usually Topics, Quests, and Cancel buttons have the 64px width, so we can place the Topics left-up from the Cancel button, and the Quests right-up from the Cancel button. - // But in some installations, e.g. German one, the Topics button has the 128px width, so we should place it exactly left from the Quests button. - if (getWidget(TopicsBTN)->getSize().width == 64) - { - getWidget(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); - } - else - { - int questLeft = getWidget(QuestsBTN)->getPosition().left; - getWidget(TopicsBTN)->setPosition(questLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); + // Usually Topics, Quests, and Cancel buttons have the 64px width, so we can place the Topics left-up from the Cancel button, and the Quests right-up from the Cancel button. + // But in some installations, e.g. German one, the Topics button has the 128px width, so we should place it exactly left from the Quests button. + if (topicsWidth == 64) + { + getWidget(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); + } + else + { + int questLeft = getWidget(QuestsBTN)->getPosition().left; + getWidget(TopicsBTN)->setPosition(questLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); + } } mQuestMode = false; From 4f190bf7f494435aefe6d678f711bf6c4bfc27b0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 23 Nov 2017 14:58:20 +0400 Subject: [PATCH 451/505] Do not show carriage return characters (bug #3696) --- apps/openmw/mwgui/bookpage.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 137594076..5a9237cea 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -16,6 +16,7 @@ class BookPageImpl; static bool ucsSpace (int codePoint); static bool ucsLineBreak (int codePoint); +static bool ucsCarriageReturn (int codePoint); static bool ucsBreakingSpace (int codePoint); struct BookTypesetter::Style { virtual ~Style () {} }; @@ -280,7 +281,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter style.mActiveColour = fontColour; style.mNormalColour = fontColour; style.mInteractiveId = 0; - + return &style; } @@ -342,7 +343,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter writeImpl (static_cast (style), begin_, end_); } - + void lineBreak (float margin) { assert (margin == 0); //TODO: figure out proper behavior here... @@ -352,7 +353,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter mRun = NULL; mLine = NULL; } - + void sectionBreak (int margin) { add_partial_text(); @@ -1188,6 +1189,9 @@ public: { Utf8Stream::UnicodeChar code_point = stream.consume (); + if (ucsCarriageReturn (code_point)) + continue; + if (!ucsSpace (code_point)) glyphStream.emitGlyph (code_point); else @@ -1331,6 +1335,11 @@ static bool ucsLineBreak (int codePoint) return codePoint == '\n'; } +static bool ucsCarriageReturn (int codePoint) +{ + return codePoint == '\r'; +} + static bool ucsSpace (int codePoint) { switch (codePoint) From 2b9a0a77328d69b215cf4ad0fb51f28944407b98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 12:11:26 +0100 Subject: [PATCH 452/505] Save new projectile state --- apps/openmw/mwworld/projectilemanager.cpp | 5 +++++ components/esm/projectilestate.cpp | 8 ++++++++ components/esm/projectilestate.hpp | 2 ++ 3 files changed, 15 insertions(+) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 1d53c1909..1c080aec1 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -567,6 +567,9 @@ namespace MWWorld state.mVelocity = it->mVelocity; state.mAttackStrength = it->mAttackStrength; + state.mThrown = it->mThrown; + state.mTime = it->mTime; + state.save(writer); writer.endRecord(ESM::REC_PROJ); @@ -604,6 +607,8 @@ namespace MWWorld state.mVelocity = esm.mVelocity; state.mIdArrow = esm.mId; state.mAttackStrength = esm.mAttackStrength; + state.mThrown = esm.mThrown; + state.mTime = esm.mTime; std::string model; try diff --git a/components/esm/projectilestate.cpp b/components/esm/projectilestate.cpp index 8ade9d5b2..1c8a10bcb 100644 --- a/components/esm/projectilestate.cpp +++ b/components/esm/projectilestate.cpp @@ -52,6 +52,8 @@ namespace ESM esm.writeHNString ("BOW_", mBowId); esm.writeHNT ("VEL_", mVelocity); esm.writeHNT ("STR_", mAttackStrength); + esm.writeHNT ("THR_", mThrown); + esm.writeHNT ("TIM_", mTime); } void ProjectileState::load(ESMReader &esm) @@ -63,6 +65,12 @@ namespace ESM mAttackStrength = 1.f; esm.getHNOT(mAttackStrength, "STR_"); + + mThrown = false; + esm.getHNOT (mThrown, "THR_"); + + mTime = 0.f; + esm.getHNOT (mTime, "TIM_"); } } diff --git a/components/esm/projectilestate.hpp b/components/esm/projectilestate.hpp index 67ec89bb6..625d34b6a 100644 --- a/components/esm/projectilestate.hpp +++ b/components/esm/projectilestate.hpp @@ -42,6 +42,8 @@ namespace ESM std::string mBowId; Vector3 mVelocity; float mAttackStrength; + float mTime; + bool mThrown; void load (ESMReader &esm); void save (ESMWriter &esm) const; From 3dbcda6686deb5fd31d0a1992eb36884b4b369ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 15:14:15 +0100 Subject: [PATCH 453/505] Make use of mEffectAnimationTime for projectile rotation --- apps/openmw/mwworld/projectilemanager.cpp | 6 +----- apps/openmw/mwworld/projectilemanager.hpp | 1 - components/esm/projectilestate.cpp | 4 ---- components/esm/projectilestate.hpp | 1 - 4 files changed, 1 insertion(+), 11 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 1c080aec1..d38931700 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -317,7 +317,6 @@ namespace MWWorld state.mCasterHandle = actor; state.mAttackStrength = attackStrength; state.mThrown = projectile.get()->mBase->mData.mType == ESM::Weapon::MarksmanThrown; - state.mTime = 0.0; MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); @@ -455,7 +454,6 @@ namespace MWWorld // gravity constant - must be way lower than the gravity affecting actors, since we're not // simulating aerodynamics at all it->mVelocity -= osg::Vec3f(0, 0, 627.2f * 0.1f) * duration; - it->mTime += duration; osg::Vec3f pos(it->mNode->getPosition()); osg::Vec3f newPos = pos + it->mVelocity * duration; @@ -463,7 +461,7 @@ namespace MWWorld osg::Quat orient; orient.set( - osg::Matrixd::rotate(it->mThrown ? -1 * it->mTime : 0.0,osg::Vec3f(0,0,1)) * + osg::Matrixd::rotate(it->mThrown ? -1 * it->mEffectAnimationTime->getTime() * 10.0 : 0.0,osg::Vec3f(0,0,1)) * osg::Matrixd::rotate(osg::PI / 2.0,osg::Vec3f(0,1,0)) * osg::Matrixd::rotate(-1 * osg::PI / 2.0,osg::Vec3f(1,0,0)) * osg::Matrixd::inverse( @@ -568,7 +566,6 @@ namespace MWWorld state.mAttackStrength = it->mAttackStrength; state.mThrown = it->mThrown; - state.mTime = it->mTime; state.save(writer); @@ -608,7 +605,6 @@ namespace MWWorld state.mIdArrow = esm.mId; state.mAttackStrength = esm.mAttackStrength; state.mThrown = esm.mThrown; - state.mTime = esm.mTime; std::string model; try diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 1e0de4dbe..ba2fe7a74 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -112,7 +112,6 @@ namespace MWWorld osg::Vec3f mVelocity; float mAttackStrength; - float mTime; bool mThrown; }; diff --git a/components/esm/projectilestate.cpp b/components/esm/projectilestate.cpp index 1c8a10bcb..7b6c419f2 100644 --- a/components/esm/projectilestate.cpp +++ b/components/esm/projectilestate.cpp @@ -53,7 +53,6 @@ namespace ESM esm.writeHNT ("VEL_", mVelocity); esm.writeHNT ("STR_", mAttackStrength); esm.writeHNT ("THR_", mThrown); - esm.writeHNT ("TIM_", mTime); } void ProjectileState::load(ESMReader &esm) @@ -68,9 +67,6 @@ namespace ESM mThrown = false; esm.getHNOT (mThrown, "THR_"); - - mTime = 0.f; - esm.getHNOT (mTime, "TIM_"); } } diff --git a/components/esm/projectilestate.hpp b/components/esm/projectilestate.hpp index 625d34b6a..c89bb7683 100644 --- a/components/esm/projectilestate.hpp +++ b/components/esm/projectilestate.hpp @@ -42,7 +42,6 @@ namespace ESM std::string mBowId; Vector3 mVelocity; float mAttackStrength; - float mTime; bool mThrown; void load (ESMReader &esm); From a8bf4cdd98fea8bbb05925cc737c8c9e3eb3a63b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 23 Nov 2017 19:29:40 +0400 Subject: [PATCH 454/505] Remove redundant include --- apps/openmw/mwbase/windowmanager.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index f2b4a526d..d454067c8 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -11,8 +11,6 @@ #include "../mwgui/mode.hpp" -#include - namespace Loading { class Listener; From 94c0e3ed10dd58b122ddecb4192b19365e8befe8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 23 Nov 2017 19:37:45 +0400 Subject: [PATCH 455/505] Move toUpper() from StringUtils to the JournalViewModel --- apps/openmw/mwgui/journalviewmodel.cpp | 19 ++++++++++++++++++- components/misc/stringops.hpp | 18 ------------------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index d7b233ff3..6ff68c9c5 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -314,7 +314,7 @@ struct JournalViewModelImpl : JournalViewModel for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) { Utf8Stream stream (i->first.c_str()); - uint32_t first = Misc::StringUtils::toUpper(stream.peek()); + uint32_t first = toUpper(stream.peek()); if (first != character) continue; @@ -323,6 +323,23 @@ struct JournalViewModelImpl : JournalViewModel } } + static uint32_t toUpper(uint32_t ch) + { + // Russian alphabet + if (ch >= 0x0430 && ch < 0x0450) + ch -= 0x20; + + // Cyrillic IO character + if (ch == 0x0451) + ch -= 0x50; + + // Latin alphabet + if (ch >= 0x61 && ch < 0x80) + ch -= 0x20; + + return ch; + } + struct TopicEntryImpl : BaseEntry { MWDialogue::Topic const & mTopic; diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 1edb5ea61..9f4931d72 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -1,7 +1,6 @@ #ifndef MISC_STRINGOPS_H #define MISC_STRINGOPS_H -#include #include #include #include @@ -57,23 +56,6 @@ public: }; } - static uint32_t toUpper(uint32_t ch) - { - // Russian alphabet - if (ch >= 0x0430 && ch < 0x0450) - ch -= 0x20; - - // Cyrillic YO character - if (ch == 0x0451) - ch -= 0x50; - - // Latin alphabet - if (ch >= 0x61 && ch < 0x80) - ch -= 0x20; - - return ch; - } - static bool ciLess(const std::string &x, const std::string &y) { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end(), ci()); } From 38bda3bd710a7cabb8168d1c9785c561d1ad4aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 18:00:10 +0100 Subject: [PATCH 456/505] Do not save thrown state for projectiles --- apps/openmw/mwworld/projectilemanager.cpp | 4 +--- components/esm/projectilestate.cpp | 4 ---- components/esm/projectilestate.hpp | 1 - 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index d38931700..707e8b193 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -565,8 +565,6 @@ namespace MWWorld state.mVelocity = it->mVelocity; state.mAttackStrength = it->mAttackStrength; - state.mThrown = it->mThrown; - state.save(writer); writer.endRecord(ESM::REC_PROJ); @@ -604,7 +602,6 @@ namespace MWWorld state.mVelocity = esm.mVelocity; state.mIdArrow = esm.mId; state.mAttackStrength = esm.mAttackStrength; - state.mThrown = esm.mThrown; std::string model; try @@ -612,6 +609,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), esm.mId); MWWorld::Ptr ptr = ref.getPtr(); model = ptr.getClass().getModel(ptr); + state.mThrown = ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanThrown; } catch(...) { diff --git a/components/esm/projectilestate.cpp b/components/esm/projectilestate.cpp index 7b6c419f2..8ade9d5b2 100644 --- a/components/esm/projectilestate.cpp +++ b/components/esm/projectilestate.cpp @@ -52,7 +52,6 @@ namespace ESM esm.writeHNString ("BOW_", mBowId); esm.writeHNT ("VEL_", mVelocity); esm.writeHNT ("STR_", mAttackStrength); - esm.writeHNT ("THR_", mThrown); } void ProjectileState::load(ESMReader &esm) @@ -64,9 +63,6 @@ namespace ESM mAttackStrength = 1.f; esm.getHNOT(mAttackStrength, "STR_"); - - mThrown = false; - esm.getHNOT (mThrown, "THR_"); } } diff --git a/components/esm/projectilestate.hpp b/components/esm/projectilestate.hpp index c89bb7683..67ec89bb6 100644 --- a/components/esm/projectilestate.hpp +++ b/components/esm/projectilestate.hpp @@ -42,7 +42,6 @@ namespace ESM std::string mBowId; Vector3 mVelocity; float mAttackStrength; - bool mThrown; void load (ESMReader &esm); void save (ESMWriter &esm) const; From d0a299caabc3feef0d8009189d0ec25fa51b89f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 20:02:12 +0100 Subject: [PATCH 457/505] Rotate thrown projectiles around the bb center --- apps/openmw/mwworld/projectilemanager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 707e8b193..73b8d4d49 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -202,6 +203,12 @@ namespace MWWorld osg::ref_ptr projectile = mResourceSystem->getSceneManager()->getInstance(model, attachTo); + osg::ref_ptr boundVisitor = new osg::ComputeBoundsVisitor(); + projectile->accept(*boundVisitor.get()); + osg::BoundingBox bb = boundVisitor->getBoundingBox(); + + state.mNode->setPivotPoint(bb.center()); + if (state.mIdMagic.size() > 1) for (size_t iter = 1; iter != state.mIdMagic.size(); ++iter) { From 4373fea21e008375b974447f48c84844ac690bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 23 Nov 2017 20:27:22 +0100 Subject: [PATCH 458/505] Correct projectile rotation --- apps/openmw/mwworld/projectilemanager.cpp | 28 ++++++++++++----------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 73b8d4d49..a4a22ea4a 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -386,7 +386,6 @@ namespace MWWorld static float fTargetSpellMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get() .find("fTargetSpellMaxSpeed")->getFloat(); float speed = fTargetSpellMaxSpeed * it->mSpeed; - osg::Vec3f direction = orient * osg::Vec3f(0,1,0); direction.normalize(); osg::Vec3f pos(it->mNode->getPosition()); @@ -466,18 +465,21 @@ namespace MWWorld osg::Vec3f newPos = pos + it->mVelocity * duration; osg::Quat orient; - - orient.set( - osg::Matrixd::rotate(it->mThrown ? -1 * it->mEffectAnimationTime->getTime() * 10.0 : 0.0,osg::Vec3f(0,0,1)) * - osg::Matrixd::rotate(osg::PI / 2.0,osg::Vec3f(0,1,0)) * - osg::Matrixd::rotate(-1 * osg::PI / 2.0,osg::Vec3f(1,0,0)) * - osg::Matrixd::inverse( - osg::Matrixd::lookAt( - osg::Vec3f(0,0,0), - it->mVelocity, - osg::Vec3f(0,0,1)) - ) - ); + + if (it->mThrown) + orient.set( + osg::Matrixd::rotate(it->mEffectAnimationTime->getTime() * -10.0,osg::Vec3f(0,0,1)) * + osg::Matrixd::rotate(osg::PI / 2.0,osg::Vec3f(0,1,0)) * + osg::Matrixd::rotate(-1 * osg::PI / 2.0,osg::Vec3f(1,0,0)) * + osg::Matrixd::inverse( + osg::Matrixd::lookAt( + osg::Vec3f(0,0,0), + it->mVelocity, + osg::Vec3f(0,0,1)) + ) + ); + else + orient.makeRotate(osg::Vec3f(0,1,0), it->mVelocity); it->mNode->setAttitude(orient); it->mNode->setPosition(newPos); From a7c953b3180e962af2c22458b2407800039faa80 Mon Sep 17 00:00:00 2001 From: Grigorii Latyshev Date: Fri, 24 Nov 2017 15:06:07 +0100 Subject: [PATCH 459/505] Display 0 chance for spell if player does not have enought magic energy --- apps/openmw/mwgui/spellmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index 6953d682b..c4112513a 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -60,7 +60,7 @@ namespace MWGui { newSpell.mType = Spell::Type_Spell; std::string cost = std::to_string(spell->mData.mCost); - std::string chance = std::to_string(int(MWMechanics::getSpellSuccessChance(spell, mActor))); + std::string chance = std::to_string((stats.getMagicka().getCurrent() >= spell->mData.mCost) ? int(MWMechanics::getSpellSuccessChance(spell, mActor)) : 0); newSpell.mCostColumn = cost + "/" + chance; } else From 32096ae0cc19f2b6c8eabd31a2732c49a337d567 Mon Sep 17 00:00:00 2001 From: Grigorii Latyshev Date: Sat, 25 Nov 2017 01:46:04 +0100 Subject: [PATCH 460/505] Fix displayed spell success chance in God Mode --- apps/openmw/mwgui/spellmodel.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index c4112513a..9d71d9247 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -8,6 +8,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/actorutil.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" @@ -60,7 +61,11 @@ namespace MWGui { newSpell.mType = Spell::Type_Spell; std::string cost = std::to_string(spell->mData.mCost); - std::string chance = std::to_string((stats.getMagicka().getCurrent() >= spell->mData.mCost) ? int(MWMechanics::getSpellSuccessChance(spell, mActor)) : 0); + std::string chance = std::to_string( + (stats.getMagicka().getCurrent() >= spell->mData.mCost || + (mActor == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState()) + ) ? int(MWMechanics::getSpellSuccessChance(spell, mActor)) : 0 + ); newSpell.mCostColumn = cost + "/" + chance; } else From 55db3c2712a112d9b978bffacf903cb803edc0a6 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 25 Nov 2017 11:35:29 +0400 Subject: [PATCH 461/505] Set default values for class and birthsign select menus (bug #4226) --- apps/openmw/mwgui/birth.cpp | 10 +++++++++- apps/openmw/mwgui/class.cpp | 13 ++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 92f29e3ef..c1867541b 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -8,7 +8,9 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" + #include "../mwworld/esmstore.hpp" +#include "../mwworld/player.hpp" #include "widgets.hpp" @@ -70,8 +72,14 @@ namespace MWGui updateBirths(); updateSpells(); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mBirthList); - } + // Show the current birthsign by default + const std::string &signId = + MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); + + if (!signId.empty()) + setBirthId(signId); + } void BirthDialog::setBirthId(const std::string &birthId) { diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 33daa0ad1..4d2a15c82 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -7,6 +7,9 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" + +#include "../mwmechanics/actorutil.hpp" + #include "../mwworld/esmstore.hpp" #include "tooltips.hpp" @@ -131,8 +134,16 @@ namespace MWGui updateClasses(); updateStats(); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mClassList); - } + // Show the current class by default + MWWorld::Ptr player = MWMechanics::getPlayer(); + + const std::string &classId = + player.get()->mBase->mClass; + + if (!classId.empty()) + setClassId(classId); + } void PickClassDialog::setClassId(const std::string &classId) { From c8f79ea8382797ef47b8eb3989a1afaeb58f884a Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 25 Nov 2017 20:46:14 -0500 Subject: [PATCH 462/505] Adjust rotation markers --- apps/opencs/view/render/object.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index c5da094e6..2e9f03719 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -307,11 +307,11 @@ osg::ref_ptr CSVRender::Object::makeRotateMarker (int axis) { const float Pi = 3.14159265f; - const float InnerRadius = mBaseNode->getBound().radius(); + const float InnerRadius = std::max(MarkerShaftBaseLength, mBaseNode->getBound().radius()); const float OuterRadius = InnerRadius + MarkerShaftWidth; const float SegmentDistance = 100.f; - const size_t SegmentCount = std::min(64, std::max(8, (int)(OuterRadius * 2 * Pi / SegmentDistance))); + const size_t SegmentCount = std::min(64, std::max(24, (int)(OuterRadius * 2 * Pi / SegmentDistance))); const size_t VerticesPerSegment = 4; const size_t IndicesPerSegment = 24; From dea7d0beff41d06356befbb34eb3ec4d6d23e602 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 24 Nov 2017 18:25:57 +0400 Subject: [PATCH 463/505] Do not interrupt swim and sneak idle animations during attack (bug #4122) --- apps/openmw/mwinput/inputmanagerimp.cpp | 5 ++++- apps/openmw/mwmechanics/character.cpp | 19 ++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 9ef5033f0..eba0d8191 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -232,7 +232,10 @@ namespace MWInput if (mControlSwitch["playercontrols"]) { if (action == A_Use) - mPlayer->setAttackingOrSpell(currentValue != 0); + { + MWMechanics::DrawState_ state = MWBase::Environment::get().getWorld()->getPlayer().getDrawState(); + mPlayer->setAttackingOrSpell(currentValue != 0 && state != MWMechanics::DrawState_Nothing); + } else if (action == A_Jump) mAttemptJump = (currentValue == 1.0 && previousValue == 0.0); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6cea0e9b4..d9e2cc292 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1278,7 +1278,16 @@ bool CharacterController::updateWeaponState() bool animPlaying; if(mAttackingOrSpell) { - mIdleState = CharState_None; + MWWorld::Ptr player = getPlayer(); + + // We should reset player's idle animation in the first-person mode. + if (mPtr == player && MWBase::Environment::get().getWorld()->isFirstPerson()) + mIdleState = CharState_None; + + // In other cases we should not break swim and sneak animations + if (mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim) + mIdleState = CharState_None; + if(mUpperBodyState == UpperCharState_WeapEquiped && (mHitState == CharState_None || mHitState == CharState_Block)) { MWBase::Environment::get().getWorld()->breakInvisibility(mPtr); @@ -1288,7 +1297,7 @@ bool CharacterController::updateWeaponState() // Unset casting flag, otherwise pressing the mouse button down would // continue casting every frame if there is no animation mAttackingOrSpell = false; - if (mPtr == getPlayer()) + if (mPtr == player) { MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false); } @@ -1298,7 +1307,7 @@ bool CharacterController::updateWeaponState() // For the player, set the spell we want to cast // This has to be done at the start of the casting animation, // *not* when selecting a spell in the GUI (otherwise you could change the spell mid-animation) - if (mPtr == getPlayer()) + if (mPtr == player) { std::string selectedSpell = MWBase::Environment::get().getWindowManager()->getSelectedSpell(); stats.getSpells().setSelectedSpell(selectedSpell); @@ -1310,7 +1319,7 @@ bool CharacterController::updateWeaponState() MWMechanics::CastSpell cast(mPtr, NULL); cast.playSpellCastingEffects(spellid); - const ESM::Spell *spell = store.get().find(spellid); + const ESM::Spell *spell = store.get().find(spellid); const ESM::ENAMstruct &lastEffect = spell->mEffects.mList.back(); const ESM::MagicEffect *effect; @@ -1639,7 +1648,7 @@ void CharacterController::update(float duration) float speed = 0.f; updateMagicEffects(); - + if (isKnockedOut()) mTimeUntilWake -= duration; From ce324623587bc261a8b6c6e81e63766fd80a0be2 Mon Sep 17 00:00:00 2001 From: Grigorii Latyshev Date: Sat, 25 Nov 2017 17:27:04 +0100 Subject: [PATCH 464/505] Move code to apps/openmw/mwmechanics/spellcasting.cpp, move reduce mana code to CastSpell::cast(const ESM::Spell*) --- apps/openmw/mwgui/spellmodel.cpp | 7 +------ apps/openmw/mwmechanics/spellcasting.cpp | 18 ++++++++++++------ apps/openmw/mwworld/worldimp.cpp | 7 ------- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index 9d71d9247..6953d682b 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -8,7 +8,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellcasting.hpp" -#include "../mwmechanics/actorutil.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" @@ -61,11 +60,7 @@ namespace MWGui { newSpell.mType = Spell::Type_Spell; std::string cost = std::to_string(spell->mData.mCost); - std::string chance = std::to_string( - (stats.getMagicka().getCurrent() >= spell->mData.mCost || - (mActor == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState()) - ) ? int(MWMechanics::getSpellSuccessChance(spell, mActor)) : 0 - ); + std::string chance = std::to_string(int(MWMechanics::getSpellSuccessChance(spell, mActor))); newSpell.mCostColumn = cost + "/" + chance; } else diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index a09436d14..19afc11ec 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -126,7 +126,10 @@ namespace MWMechanics float castChance = calcSpellBaseSuccessChance(spell, actor, effectiveSchool) + castBonus; castChance *= stats.getFatigueTerm(); - if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude()&& !godmode) + if (godmode) + return 100; + + if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude()) return 0; if (spell->mData.mType == ESM::Spell::ST_Power) @@ -135,13 +138,11 @@ namespace MWMechanics if (spell->mData.mType != ESM::Spell::ST_Spell) return 100; - if (spell->mData.mFlags & ESM::Spell::F_Always) - return 100; + if (stats.getMagicka().getCurrent() < spell->mData.mCost) + return 0; - if (godmode) - { + if (spell->mData.mFlags & ESM::Spell::F_Always) return 100; - } if (!cap) return std::max(0.f, castChance); @@ -888,6 +889,11 @@ namespace MWMechanics MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); fail = true; } + + // Reduce mana + MWMechanics::DynamicStat magicka = stats.getMagicka(); + magicka.setCurrent(magicka.getCurrent() - spell->mData.mCost); + stats.setMagicka(magicka); } if (fail) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9c7fba9fa..83971eadf 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2718,13 +2718,6 @@ namespace MWWorld message = "#{sPowerAlreadyUsed}"; fail = true; } - - // Reduce mana - if (!fail && !godmode) - { - magicka.setCurrent(magicka.getCurrent() - spell->mData.mCost); - stats.setMagicka(magicka); - } } if (isPlayer && fail) From eb23367175b28cb07fe5f9449d54b05aed4f5533 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 26 Nov 2017 17:39:57 -0500 Subject: [PATCH 465/505] Fix rendering depth/order issues --- apps/opencs/view/render/object.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 2e9f03719..df7283b1a 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -336,6 +336,9 @@ osg::ref_ptr CSVRender::Object::makeRotateMarker (int axis) osg::ref_ptr primitives = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, IndexCount); + // prevent some depth collision issues from overlaps + osg::Vec3f offset = getMarkerPosition(0, MarkerShaftWidth/4, 0, axis); + for (size_t i = 0; i < SegmentCount; ++i) { size_t index = i * VerticesPerSegment; @@ -346,10 +349,10 @@ osg::ref_ptr CSVRender::Object::makeRotateMarker (int axis) float outerX = OuterRadius * std::cos(i * Angle); float outerY = OuterRadius * std::sin(i * Angle); - vertices->at(index++) = getMarkerPosition(innerX, innerY, MarkerShaftWidth / 2, axis); - vertices->at(index++) = getMarkerPosition(innerX, innerY, -MarkerShaftWidth / 2, axis); - vertices->at(index++) = getMarkerPosition(outerX, outerY, MarkerShaftWidth / 2, axis); - vertices->at(index++) = getMarkerPosition(outerX, outerY, -MarkerShaftWidth / 2, axis); + vertices->at(index++) = getMarkerPosition(innerX, innerY, MarkerShaftWidth / 2, axis) + offset; + vertices->at(index++) = getMarkerPosition(innerX, innerY, -MarkerShaftWidth / 2, axis) + offset; + vertices->at(index++) = getMarkerPosition(outerX, outerY, MarkerShaftWidth / 2, axis) + offset; + vertices->at(index++) = getMarkerPosition(outerX, outerY, -MarkerShaftWidth / 2, axis) + offset; } colors->at(0) = osg::Vec4f ( @@ -390,17 +393,11 @@ osg::ref_ptr CSVRender::Object::makeRotateMarker (int axis) void CSVRender::Object::setupCommonMarkerState(osg::ref_ptr geometry) { - const int RenderBin = osg::StateSet::TRANSPARENT_BIN; - osg::ref_ptr state = geometry->getOrCreateStateSet(); state->setMode(GL_LIGHTING, osg::StateAttribute::OFF); state->setMode(GL_BLEND, osg::StateAttribute::ON); - osg::ref_ptr depth(new osg::Depth); - depth->setWriteMask(false); - state->setAttributeAndModes(depth, osg::StateAttribute::ON); - - state->setRenderBinDetails(RenderBin, "RenderBin"); + state->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } osg::Vec3f CSVRender::Object::getMarkerPosition (float x, float y, float z, int axis) From c50b18b3bbb9ac335cf6cb0f248d84edd4154551 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 27 Nov 2017 18:30:31 +0100 Subject: [PATCH 466/505] Move PathgridGraph out of CellStore By definition this is not 'Mutable state of a cell' and does not belong in CellStore. This change should improve startup times (graph is now loaded on demand) and edits to 'pathgrid.hpp' no longer cause the entirety of OpenMW to be rebuilt. --- apps/openmw/mwmechanics/aicombat.cpp | 3 ++- apps/openmw/mwmechanics/aipackage.cpp | 17 +++++++++++++++- apps/openmw/mwmechanics/aipackage.hpp | 3 +++ apps/openmw/mwmechanics/aiwander.cpp | 13 ++++++------ apps/openmw/mwmechanics/pathfinding.cpp | 27 +++++++++++++------------ apps/openmw/mwmechanics/pathfinding.hpp | 6 ++++-- apps/openmw/mwmechanics/pathgrid.cpp | 8 +++++++- apps/openmw/mwmechanics/pathgrid.hpp | 4 +++- apps/openmw/mwworld/cellstore.cpp | 19 ----------------- apps/openmw/mwworld/cellstore.hpp | 10 +-------- 10 files changed, 57 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index ee1013fe4..83ebc67d9 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -13,6 +13,7 @@ #include "../mwrender/animation.hpp" +#include "pathgrid.hpp" #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" @@ -372,7 +373,7 @@ namespace MWMechanics int closestPointIndex = PathFinder::GetClosestPoint(pathgrid, localPos); for (int i = 0; i < static_cast(pathgrid->mPoints.size()); i++) { - if (i != closestPointIndex && storage.mCell->isPointConnected(closestPointIndex, i)) + if (i != closestPointIndex && getPathGridGraph(storage.mCell).isPointConnected(closestPointIndex, i)) { points.push_back(pathgrid->mPoints[static_cast(i)]); } diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index f837ad2ee..198c8fc4b 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -14,6 +14,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/inventorystore.hpp" +#include "pathgrid.hpp" #include "creaturestats.hpp" #include "movement.hpp" #include "steering.hpp" @@ -107,7 +108,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const ESM::Pathgr { if (wasShortcutting || doesPathNeedRecalc(dest, actor.getCell())) // if need to rebuild path { - mPathFinder.buildSyncedPath(start, dest, actor.getCell()); + mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell())); mRotateOnTheRunChecks = 3; // give priority to go directly on target if there is minimal opportunity @@ -220,6 +221,20 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur } } +const MWMechanics::PathgridGraph& MWMechanics::AiPackage::getPathGridGraph(const MWWorld::CellStore *cell) +{ + const ESM::CellId& id = cell->getCell()->getCellId(); + // static cache is OK for now, pathgrids can never change during runtime + typedef std::map > CacheMap; + static CacheMap cache; + CacheMap::iterator found = cache.find(id); + if (found == cache.end()) + { + cache.insert(std::make_pair(id, std::unique_ptr(new MWMechanics::PathgridGraph(cell)))); + } + return *cache[id].get(); +} + bool MWMechanics::AiPackage::shortcutPath(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor, bool *destInLOS) { const MWWorld::Class& actorClass = actor.getClass(); diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index acbd87908..a9c69ad7f 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -27,6 +27,7 @@ namespace MWMechanics const float AI_REACTION_TIME = 0.25f; class CharacterController; + class PathgridGraph; /// \brief Base class for AI packages class AiPackage @@ -119,6 +120,8 @@ namespace MWMechanics void evadeObstacles(const MWWorld::Ptr& actor, float duration, const ESM::Position& pos); + const PathgridGraph& getPathGridGraph(const MWWorld::CellStore* cell); + // TODO: all this does not belong here, move into temporary storage PathFinder mPathFinder; ObstacleCheck mObstacleCheck; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 343e03f6c..7bdb3a11d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -17,6 +17,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "pathgrid.hpp" #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" @@ -217,7 +218,7 @@ namespace MWMechanics ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mDestination)); ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); - mPathFinder.buildSyncedPath(start, dest, actor.getCell()); + mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell())); if (mPathFinder.isPathConstructed()) storage.setState(Wander_Walking); @@ -349,7 +350,7 @@ namespace MWMechanics ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); // don't take shortcuts for wandering - mPathFinder.buildSyncedPath(start, dest, actor.getCell()); + mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell())); if (mPathFinder.isPathConstructed()) { @@ -383,7 +384,7 @@ namespace MWMechanics // Check if land creature will walk onto water or if water creature will swim onto land if ((!isWaterCreature && !destinationIsAtWater(actor, mDestination)) || (isWaterCreature && !destinationThroughGround(currentPositionVec3f, mDestination))) { - mPathFinder.buildSyncedPath(currentPosition, destinationPosition, actor.getCell()); + mPathFinder.buildSyncedPath(currentPosition, destinationPosition, actor.getCell(), getPathGridGraph(actor.getCell())); mPathFinder.addPointToPath(destinationPosition); if (mPathFinder.isPathConstructed()) @@ -666,7 +667,7 @@ namespace MWMechanics ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actorPos)); // don't take shortcuts for wandering - mPathFinder.buildSyncedPath(start, dest, actor.getCell()); + mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell())); if (mPathFinder.isPathConstructed()) { @@ -872,7 +873,7 @@ namespace MWMechanics int index = PathFinder::GetClosestPoint(pathgrid, PathFinder::MakeOsgVec3(dest)); - currentCell->getNeighbouringPoints(index, points); + getPathGridGraph(currentCell).getNeighbouringPoints(index, points); } void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage) @@ -913,7 +914,7 @@ namespace MWMechanics { osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter])); if((npcPos - nodePos).length2() <= mDistance * mDistance && - cellStore->isPointConnected(closestPointIndex, counter)) + getPathGridGraph(cellStore).isPointConnected(closestPointIndex, counter)) { storage.mAllowedNodes.push_back(pathgrid->mPoints[counter]); pointIndex = counter; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 5c0456096..1dccb6c9a 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -5,16 +5,16 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" -#include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "pathgrid.hpp" #include "coordinateconverter.hpp" namespace { // Chooses a reachable end pathgrid point. start is assumed reachable. std::pair getClosestReachablePoint(const ESM::Pathgrid* grid, - const MWWorld::CellStore *cell, + const MWMechanics::PathgridGraph *graph, const osg::Vec3f& pos, int start) { assert(grid && !grid->mPoints.empty()); @@ -31,7 +31,7 @@ namespace if (potentialDistBetween < closestDistanceReachable) { // found a closer one - if (cell->isPointConnected(start, counter)) + if (graph->isPointConnected(start, counter)) { closestDistanceReachable = potentialDistBetween; closestReachableIndex = counter; @@ -45,7 +45,7 @@ namespace } // post-condition: start and endpoint must be connected - assert(cell->isPointConnected(start, closestReachableIndex)); + assert(graph->isPointConnected(start, closestReachableIndex)); // AiWander has logic that depends on whether a path was created, deleting // allowed nodes if not. Hence a path needs to be created even if the start @@ -120,8 +120,8 @@ namespace MWMechanics } PathFinder::PathFinder() - : mPathgrid(NULL), - mCell(NULL) + : mPathgrid(NULL) + , mCell(NULL) { } @@ -169,14 +169,15 @@ namespace MWMechanics */ void PathFinder::buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, - const MWWorld::CellStore* cell) + const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph) { mPath.clear(); + // TODO: consider removing mCell / mPathgrid in favor of mPathgridGraph if(mCell != cell || !mPathgrid) { mCell = cell; - mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*mCell->getCell()); + mPathgrid = pathgridGraph.getPathgrid(); } // Refer to AiWander reseach topic on openmw forums for some background. @@ -200,7 +201,7 @@ namespace MWMechanics int startNode = GetClosestPoint(mPathgrid, startPointInLocalCoords); osg::Vec3f endPointInLocalCoords(converter.toLocalVec3(endPoint)); - std::pair endNode = getClosestReachablePoint(mPathgrid, cell, + std::pair endNode = getClosestReachablePoint(mPathgrid, &pathgridGraph, endPointInLocalCoords, startNode); @@ -228,7 +229,7 @@ namespace MWMechanics } else { - mPath = mCell->aStarSearch(startNode, endNode.first); + mPath = pathgridGraph.aStarSearch(startNode, endNode.first); // convert supplied path to world coordinates for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) @@ -301,18 +302,18 @@ namespace MWMechanics // see header for the rationale void PathFinder::buildSyncedPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, - const MWWorld::CellStore* cell) + const MWWorld::CellStore* cell, const MWMechanics::PathgridGraph& pathgridGraph) { if (mPath.size() < 2) { // if path has one point, then it's the destination. // don't need to worry about bad path for this case - buildPath(startPoint, endPoint, cell); + buildPath(startPoint, endPoint, cell, pathgridGraph); } else { const ESM::Pathgrid::Point oldStart(*getPath().begin()); - buildPath(startPoint, endPoint, cell); + buildPath(startPoint, endPoint, cell, pathgridGraph); if (mPath.size() >= 2) { // if 2nd waypoint of new path == 1st waypoint of old, diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 945a7f927..ebc22f10d 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -14,6 +14,8 @@ namespace MWWorld namespace MWMechanics { + class PathgridGraph; + float distance(const ESM::Pathgrid::Point& point, float x, float y, float); float distance(const ESM::Pathgrid::Point& a, const ESM::Pathgrid::Point& b); float getZAngleToDir(const osg::Vec3f& dir); @@ -54,7 +56,7 @@ namespace MWMechanics void clearPath(); void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, - const MWWorld::CellStore* cell); + const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph); bool checkPathCompleted(float x, float y, float tolerance = PathTolerance); ///< \Returns true if we are within \a tolerance units of the last path point. @@ -89,7 +91,7 @@ namespace MWMechanics Which results in NPC "running in a circle" back to the just passed waypoint. */ void buildSyncedPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, - const MWWorld::CellStore* cell); + const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph); void addPointToPath(const ESM::Pathgrid::Point &point) { diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 85264095c..c0122a861 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -49,7 +49,7 @@ namespace namespace MWMechanics { - PathgridGraph::PathgridGraph() + PathgridGraph::PathgridGraph(const MWWorld::CellStore *cell) : mCell(NULL) , mPathgrid(NULL) , mIsExterior(0) @@ -58,6 +58,7 @@ namespace MWMechanics , mSCCId(0) , mSCCIndex(0) { + load(cell); } /* @@ -130,6 +131,11 @@ namespace MWMechanics return true; } + const ESM::Pathgrid *PathgridGraph::getPathgrid() const + { + return mPathgrid; + } + // v is the pathgrid point index (some call them vertices) void PathgridGraph::recursiveStrongConnect(int v) { diff --git a/apps/openmw/mwmechanics/pathgrid.hpp b/apps/openmw/mwmechanics/pathgrid.hpp index 84b84652c..0c71c4561 100644 --- a/apps/openmw/mwmechanics/pathgrid.hpp +++ b/apps/openmw/mwmechanics/pathgrid.hpp @@ -20,10 +20,12 @@ namespace MWMechanics class PathgridGraph { public: - PathgridGraph(); + PathgridGraph(const MWWorld::CellStore* cell); bool load(const MWWorld::CellStore *cell); + const ESM::Pathgrid* getPathgrid() const; + // returns true if end point is strongly connected (i.e. reachable // from start point) both start and end are pathgrid point indexes bool isPointConnected(const int start, const int end) const; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index f6e70dc94..f33c7bb67 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -445,10 +445,6 @@ namespace MWWorld loadRefs (); mState = State_Loaded; - - // TODO: the pathgrid graph only needs to be loaded for active cells, so move this somewhere else. - // In a simple test, loading the graph for all cells in MW + expansions took 200 ms - mPathgridGraph.load(this); } } @@ -937,21 +933,6 @@ namespace MWWorld return !(left==right); } - bool CellStore::isPointConnected(const int start, const int end) const - { - return mPathgridGraph.isPointConnected(start, end); - } - - void CellStore::getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const - { - return mPathgridGraph.getNeighbouringPoints(index, nodes); - } - - std::list CellStore::aStarSearch(const int start, const int end) const - { - return mPathgridGraph.aStarSearch(start, end); - } - void CellStore::setFog(ESM::FogState *fog) { mFogState.reset(fog); diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 2f6277aec..dd54bdd6a 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -32,13 +32,12 @@ #include #include -#include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld - #include "timestamp.hpp" #include "ptr.hpp" namespace ESM { + struct Cell; struct CellState; struct FogState; struct CellId; @@ -376,11 +375,6 @@ namespace MWWorld void respawn (); ///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded. - bool isPointConnected(const int start, const int end) const; - void getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const; - - std::list aStarSearch(const int start, const int end) const; - private: /// Run through references and store IDs @@ -392,8 +386,6 @@ namespace MWWorld ///< Make case-adjustments to \a ref and insert it into the respective container. /// /// Invalid \a ref objects are silently dropped. - - MWMechanics::PathgridGraph mPathgridGraph; }; template<> From f7f8dfaf2aaf541983e193c0e2f8dfff75256aa7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 28 Nov 2017 18:03:13 +0400 Subject: [PATCH 467/505] AiWander: do not allow flying/swimming creatures to use pathgrid --- apps/openmw/mwmechanics/aipackage.cpp | 28 +++++++++++++-------------- apps/openmw/mwmechanics/aipackage.hpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 16 +++++++++++++-- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 198c8fc4b..398e84448 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -101,8 +101,17 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const ESM::Pathgr { bool wasShortcutting = mIsShortcutting; bool destInLOS = false; - if (getTypeId() != TypeIdWander) // prohibit shortcuts for AiWander - mIsShortcutting = shortcutPath(start, dest, actor, &destInLOS); // try to shortcut first + + const MWWorld::Class& actorClass = actor.getClass(); + MWBase::World* world = MWBase::Environment::get().getWorld(); + + // check if actor can move along z-axis + bool actorCanMoveByZ = (actorClass.canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(actor)) + || world->isFlying(actor); + + // Prohibit shortcuts for AiWander, if the actor can not move in 3 dimensions. + if (actorCanMoveByZ || getTypeId() != TypeIdWander) + mIsShortcutting = shortcutPath(start, dest, actor, &destInLOS, actorCanMoveByZ); // try to shortcut first if (!mIsShortcutting) { @@ -235,20 +244,9 @@ const MWMechanics::PathgridGraph& MWMechanics::AiPackage::getPathGridGraph(const return *cache[id].get(); } -bool MWMechanics::AiPackage::shortcutPath(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor, bool *destInLOS) +bool MWMechanics::AiPackage::shortcutPath(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor, bool *destInLOS, bool isPathClear) { - const MWWorld::Class& actorClass = actor.getClass(); - MWBase::World* world = MWBase::Environment::get().getWorld(); - - // check if actor can move along z-axis - bool actorCanMoveByZ = (actorClass.canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(actor)) - || world->isFlying(actor); - - // don't use pathgrid when actor can move in 3 dimensions - bool isPathClear = actorCanMoveByZ; - - if (!isPathClear - && (!mShortcutProhibited || (PathFinder::MakeOsgVec3(mShortcutFailPos) - PathFinder::MakeOsgVec3(startPoint)).length() >= PATHFIND_SHORTCUT_RETRY_DIST)) + if (!mShortcutProhibited || (PathFinder::MakeOsgVec3(mShortcutFailPos) - PathFinder::MakeOsgVec3(startPoint)).length() >= PATHFIND_SHORTCUT_RETRY_DIST) { // check if target is clearly visible isPathClear = !MWBase::Environment::get().getWorld()->castRay( diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index a9c69ad7f..06b4adf61 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -111,7 +111,7 @@ namespace MWMechanics /// If a shortcut is possible then path will be cleared and filled with the destination point. /// \param destInLOS If not NULL function will return ray cast check result /// \return If can shortcut the path - bool shortcutPath(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor, bool *destInLOS); + bool shortcutPath(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor, bool *destInLOS, bool isPathClear); /// Check if the way to the destination is clear, taking into account actor speed bool checkWayIsClearForActor(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 7bdb3a11d..8199170dc 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -265,9 +265,20 @@ namespace MWMechanics getAllowedNodes(actor, currentCell->getCell(), storage); } + bool actorCanMoveByZ = (actor.getClass().canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(actor)) + || MWBase::Environment::get().getWorld()->isFlying(actor); + + if(actorCanMoveByZ && mDistance > 0) { + // Typically want to idle for a short time before the next wander + if (Misc::Rng::rollDice(100) >= 92 && storage.mState != Wander_Walking) { + wanderNearStart(actor, storage, mDistance); + } + + storage.mCanWanderAlongPathGrid = false; + } // If the package has a wander distance but no pathgrid is available, // randomly idle or wander near spawn point - if(storage.mAllowedNodes.empty() && mDistance > 0 && !storage.mIsWanderingManually) { + else if(storage.mAllowedNodes.empty() && mDistance > 0 && !storage.mIsWanderingManually) { // Typically want to idle for a short time before the next wander if (Misc::Rng::rollDice(100) >= 96) { wanderNearStart(actor, storage, mDistance); @@ -373,7 +384,7 @@ namespace MWMechanics do { // Determine a random location within radius of original position const float pi = 3.14159265359f; - const float wanderRadius = Misc::Rng::rollClosedProbability() * wanderDistance; + const float wanderRadius = (0.2f + Misc::Rng::rollClosedProbability() * 0.8f) * wanderDistance; const float randomDirection = Misc::Rng::rollClosedProbability() * 2.0f * pi; const float destinationX = mInitialActorPosition.x() + wanderRadius * std::cos(randomDirection); const float destinationY = mInitialActorPosition.y() + wanderRadius * std::sin(randomDirection); @@ -661,6 +672,7 @@ namespace MWMechanics { unsigned int randNode = Misc::Rng::rollDice(storage.mAllowedNodes.size()); ESM::Pathgrid::Point dest(storage.mAllowedNodes[randNode]); + ToWorldCoordinates(dest, storage.mCell->getCell()); // actor position is already in world coordinates From b9d9660efdca3f51c043eec2284b7ebf4ca84ee4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 28 Nov 2017 20:49:48 +0400 Subject: [PATCH 468/505] Update music state in the menu mode (bug #3664) --- apps/openmw/mwmechanics/actors.cpp | 61 ++++++++++++++++++++---------- apps/openmw/mwmechanics/actors.hpp | 3 ++ 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ea34881fa..20955f22a 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1148,6 +1148,46 @@ namespace MWMechanics } } + void Actors::updateCombatMusic () + { + MWWorld::Ptr player = getPlayer(); + int hostilesCount = 0; // need to know this to play Battle music + + for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + { + if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) + { + bool inProcessingRange = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2() + <= sqrAiProcessingDistance; + + if (MWBase::Environment::get().getMechanicsManager()->isAIActive() && inProcessingRange) + { + if (iter->first != player) + { + MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first); + if (stats.getAiSequence().isInCombat() && !stats.isDead()) hostilesCount++; + } + } + } + } + + // check if we still have any player enemies to switch music + static int currentMusic = 0; + + if (currentMusic != 1 && hostilesCount == 0 && !(player.getClass().getCreatureStats(player).isDead() && + MWBase::Environment::get().getSoundManager()->isMusicPlaying())) + { + MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); + currentMusic = 1; + } + else if (currentMusic != 2 && hostilesCount > 0) + { + MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle")); + currentMusic = 2; + } + + } + void Actors::update (float duration, bool paused) { if(!paused) @@ -1165,8 +1205,6 @@ namespace MWMechanics MWWorld::Ptr player = getPlayer(); - int hostilesCount = 0; // need to know this to play Battle music - /// \todo move update logic to Actor class where appropriate std::map > cachedAllies; // will be filled as engageCombat iterates @@ -1257,8 +1295,6 @@ namespace MWMechanics CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); if (isConscious(iter->first)) stats.getAiSequence().execute(iter->first, *iter->second->getCharacterController(), iter->second->getAiState(), duration); - - if (stats.getAiSequence().isInCombat() && !stats.isDead()) hostilesCount++; } } @@ -1331,21 +1367,6 @@ namespace MWMechanics killDeadActors(); - // check if we still have any player enemies to switch music - static int currentMusic = 0; - - if (currentMusic != 1 && hostilesCount == 0 && !(player.getClass().getCreatureStats(player).isDead() && - MWBase::Environment::get().getSoundManager()->isMusicPlaying())) - { - MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); - currentMusic = 1; - } - else if (currentMusic != 2 && hostilesCount > 0) - { - MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle")); - currentMusic = 2; - } - static float sneakTimer = 0.f; // times update of sneak icon // if player is in sneak state see if anyone detects him @@ -1412,6 +1433,8 @@ namespace MWMechanics MWBase::Environment::get().getWindowManager()->setSneakVisibility(false); } } + + updateCombatMusic(); } void Actors::killDeadActors() diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 7ed89d0e4..13641abf4 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -81,6 +81,9 @@ namespace MWMechanics void dropActors (const MWWorld::CellStore *cellStore, const MWWorld::Ptr& ignore); ///< Deregister all actors (except for \a ignore) in the given cell. + void updateCombatMusic(); + ///< Update combat music state + void update (float duration, bool paused); ///< Update actor stats and store desired velocity vectors in \a movement From dab72b45db77e9fbbb6f51d64ac61f38c9f734bb Mon Sep 17 00:00:00 2001 From: Grigorii Latyshev Date: Tue, 28 Nov 2017 23:14:57 +0100 Subject: [PATCH 469/505] Move mana reducing code back --- apps/openmw/mwmechanics/spellcasting.cpp | 5 ----- apps/openmw/mwworld/worldimp.cpp | 7 +++++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 19afc11ec..5cab750db 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -889,11 +889,6 @@ namespace MWMechanics MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); fail = true; } - - // Reduce mana - MWMechanics::DynamicStat magicka = stats.getMagicka(); - magicka.setCurrent(magicka.getCurrent() - spell->mData.mCost); - stats.setMagicka(magicka); } if (fail) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 83971eadf..9c7fba9fa 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2718,6 +2718,13 @@ namespace MWWorld message = "#{sPowerAlreadyUsed}"; fail = true; } + + // Reduce mana + if (!fail && !godmode) + { + magicka.setCurrent(magicka.getCurrent() - spell->mData.mCost); + stats.setMagicka(magicka); + } } if (isPlayer && fail) From 9fe5a4d236d5f3e5d3f3214be6beb2e400b9e43e Mon Sep 17 00:00:00 2001 From: Grigorii Latyshev Date: Tue, 28 Nov 2017 17:04:37 +0100 Subject: [PATCH 470/505] Revert condition changes --- apps/openmw/mwmechanics/spellcasting.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 5cab750db..63fe3fa3c 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -126,10 +126,7 @@ namespace MWMechanics float castChance = calcSpellBaseSuccessChance(spell, actor, effectiveSchool) + castBonus; castChance *= stats.getFatigueTerm(); - if (godmode) - return 100; - - if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude()) + if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude()&& !godmode) return 0; if (spell->mData.mType == ESM::Spell::ST_Power) @@ -138,12 +135,17 @@ namespace MWMechanics if (spell->mData.mType != ESM::Spell::ST_Spell) return 100; - if (stats.getMagicka().getCurrent() < spell->mData.mCost) + if (stats.getMagicka().getCurrent() < spell->mData.mCost && !godmode) return 0; if (spell->mData.mFlags & ESM::Spell::F_Always) return 100; + if (godmode) + { + return 100; + } + if (!cap) return std::max(0.f, castChance); else From 2abb1a2ec27c35cbef25ae031a50e46dd5c0caea Mon Sep 17 00:00:00 2001 From: Grigorii Latyshev Date: Tue, 28 Nov 2017 23:10:07 +0100 Subject: [PATCH 471/505] Added checkMagicka parameter --- apps/openmw/mwgui/spellmodel.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 8 ++++---- apps/openmw/mwmechanics/spellcasting.hpp | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index 6953d682b..f83b72096 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -60,7 +60,7 @@ namespace MWGui { newSpell.mType = Spell::Type_Spell; std::string cost = std::to_string(spell->mData.mCost); - std::string chance = std::to_string(int(MWMechanics::getSpellSuccessChance(spell, mActor))); + std::string chance = std::to_string(int(MWMechanics::getSpellSuccessChance(spell, mActor, NULL, true, true))); newSpell.mCostColumn = cost + "/" + chance; } else diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 63fe3fa3c..8fbf67535 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -115,7 +115,7 @@ namespace MWMechanics return castChance; } - float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap) + float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap, bool checkMagicka) { bool godmode = actor == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); @@ -135,7 +135,7 @@ namespace MWMechanics if (spell->mData.mType != ESM::Spell::ST_Spell) return 100; - if (stats.getMagicka().getCurrent() < spell->mData.mCost && !godmode) + if (checkMagicka && stats.getMagicka().getCurrent() < spell->mData.mCost && !godmode) return 0; if (spell->mData.mFlags & ESM::Spell::F_Always) @@ -152,11 +152,11 @@ namespace MWMechanics return std::max(0.f, std::min(100.f, castChance)); } - float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap) + float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap, bool checkMagicka) { const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - return getSpellSuccessChance(spell, actor, effectiveSchool, cap); + return getSpellSuccessChance(spell, actor, effectiveSchool, cap, checkMagicka); } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 2e368afcf..1f5ef45bd 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -31,11 +31,12 @@ namespace MWMechanics * @param actor calculate spell success chance for this actor (depends on actor's skills) * @param effectiveSchool the spell's effective school (relevant for skill progress) will be written here * @param cap cap the result to 100%? + * @param checkMagicka check magicka? * @note actor can be an NPC or a creature * @return success chance from 0 to 100 (in percent), if cap=false then chance above 100 may be returned. */ - float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool = NULL, bool cap=true); - float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor, int* effectiveSchool = NULL, bool cap=true); + float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool = NULL, bool cap=true, bool checkMagicka=false); + float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor, int* effectiveSchool = NULL, bool cap=true, bool checkMagicka=false); int getSpellSchool(const std::string& spellId, const MWWorld::Ptr& actor); int getSpellSchool(const ESM::Spell* spell, const MWWorld::Ptr& actor); From bb7ca055d03345d9ed961ece215e8eee5fc67103 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 29 Nov 2017 22:13:42 +0000 Subject: [PATCH 472/505] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index c4190343d..155d017f3 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -153,6 +153,7 @@ Programmers Sylvain Thesnieres (Garvek) t6 terrorfisch + thegriglat Thomas Luppi (Digmaster) Will Herrmann (Thunderforge) Tom Mason (wheybags) From 50deed126b0d63a65423b1648c454e5d94b3e40f Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sat, 2 Dec 2017 21:48:57 +0100 Subject: [PATCH 473/505] Update SDL to 2.0.7 --- CI/before_script.msvc.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 9f6051863..ee48c1f68 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -350,9 +350,9 @@ if [ -z $SKIP_DOWNLOAD ]; then fi # SDL2 - download "SDL 2.0.4" \ - "https://www.libsdl.org/release/SDL2-devel-2.0.4-VC.zip" \ - "SDL2-2.0.4.zip" + download "SDL 2.0.7" \ + "https://www.libsdl.org/release/SDL2-devel-2.0.7-VC.zip" \ + "SDL2-2.0.7.zip" fi cd .. #/.. @@ -632,18 +632,18 @@ cd $DEPS echo # SDL2 -printf "SDL 2.0.4... " +printf "SDL 2.0.7... " { - if [ -d SDL2-2.0.4 ]; then + if [ -d SDL2-2.0.7 ]; then printf "Exists. " elif [ -z $SKIP_EXTRACT ]; then - rm -rf SDL2-2.0.4 - eval 7z x -y SDL2-2.0.4.zip $STRIP + rm -rf SDL2-2.0.7 + eval 7z x -y SDL2-2.0.7.zip $STRIP fi - export SDL2DIR="$(real_pwd)/SDL2-2.0.4" + export SDL2DIR="$(real_pwd)/SDL2-2.0.7" - add_runtime_dlls "$(pwd)/SDL2-2.0.4/lib/x${ARCHSUFFIX}/SDL2.dll" + add_runtime_dlls "$(pwd)/SDL2-2.0.7/lib/x${ARCHSUFFIX}/SDL2.dll" echo Done. } From 8decd356079a13dcd0f4b18dec2ca6acffaf907a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 3 Dec 2017 21:49:13 +0400 Subject: [PATCH 474/505] Fixes crash on quickload from the container menu (bug #4239) --- apps/openmw/mwgui/container.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 444eaff85..9222f1d02 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -154,7 +154,8 @@ namespace MWGui { WindowBase::onClose(); - mModel->onClose(); + if (mModel) + mModel->onClose(); } void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) From 441420225f47fb7af3555c45fcf19f614b6c8d8f Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 4 Dec 2017 17:00:02 +0000 Subject: [PATCH 475/505] Contributing.md: referencing issues in commit messages --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b5a7423d2..6c82d1dfd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,6 +33,7 @@ Furthermore, we advise to: * Feel free to submit incomplete pull requests. Even if the work can not be merged yet, pull requests are a great place to collect early feedback. Just make sure to mark it as *[Incomplete]* or *[Do not merge yet]* in the title. * If you plan on contributing often, please read the [Developer Reference](https://wiki.openmw.org/index.php?title=Developer_Reference) on our wiki, especially the [Policies and Standards](https://wiki.openmw.org/index.php?title=Policies_and_Standards). * Make sure each of your changes has a clear objective. Unnecessary changes may lead to merge conflicts, clutter the commit history and slow down review. Code formatting 'fixes' should be avoided, unless you were already changing that particular line anyway. +* Reference the bug / feature ticket(s) in your commit message (e.g. 'Bug #123') to make it easier to keep track of what we changed for what reason. Our bugtracker will show those commits next to the ticket. If your commit message includes 'Fixes #123', that bug/feature will automatically be set to 'Closed' when your commit is merged. Guidelines for original engine "fixes" ================================= From b6ae7f3cc8106fb9b1c1b7791ad243e36fd06ddd Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 4 Dec 2017 22:01:57 +0400 Subject: [PATCH 476/505] Do not add greetings to the journal index (bug #4342) --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 1f6de04e5..de9ca83ca 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -146,7 +146,6 @@ namespace MWDialogue // TODO play sound } - MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); callback->addResponse("", Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript, mActor); @@ -387,7 +386,7 @@ namespace MWDialogue { Filter filter (mActor, mChoice, mTalkedTo); - if (dialogue->mType == ESM::Dialogue::Topic || dialogue->mType == ESM::Dialogue::Greeting) + if (dialogue->mType == ESM::Dialogue::Topic || dialogue->mType == ESM::Dialogue::Greeting) { if (const ESM::DialInfo *info = filter.search (*dialogue, true)) { @@ -401,15 +400,18 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); callback->addResponse("", Interpreter::fixDefinesDialog(text, interpreterContext)); - // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, - // in which case it should not be added to the journal. - for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue->mInfo.begin(); - iter!=dialogue->mInfo.end(); ++iter) + if (dialogue->mType == ESM::Dialogue::Topic) { - if (iter->mId == info->mId) + // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, + // in which case it should not be added to the journal + for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue->mInfo.begin(); + iter!=dialogue->mInfo.end(); ++iter) { - MWBase::Environment::get().getJournal()->addTopic (Misc::StringUtils::lowerCase(mLastTopic), info->mId, mActor); - break; + if (iter->mId == info->mId) + { + MWBase::Environment::get().getJournal()->addTopic (Misc::StringUtils::lowerCase(mLastTopic), info->mId, mActor); + break; + } } } From 29b2308b2c64510e787a526793abe65065624bb6 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 4 Dec 2017 22:10:22 +0400 Subject: [PATCH 477/505] Do not display cyrillic soft/hard signs in the journal index --- apps/openmw/mwgui/journalbooks.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index f3ee8162e..e8aa23158 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -281,6 +281,8 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () textColours.journalTopicOver, textColours.journalTopicPressed, first); + ch[1]++; + // Words can not be started with these characters if (i == 26 || i == 28) continue; @@ -290,8 +292,6 @@ BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex () typesetter->write (style, to_utf8_span (buffer)); typesetter->lineBreak (); - - ch[1]++; } return typesetter; From a28cc37501c729930bb935cc305696e413a75c4e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 5 Dec 2017 10:24:58 +0400 Subject: [PATCH 478/505] Do not sell ingredients from organic containers --- 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 9c7fba9fa..2d38f1518 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2446,6 +2446,11 @@ namespace MWWorld if (ptr.getRefData().isDeleted()) return true; + // we should not sell ingrediends from owned organic containers + MWWorld::LiveCellRef* ref = ptr.get(); + if (ref && (ref->mBase->mFlags & ESM::Container::Organic)) + return true; + if (Misc::StringUtils::ciEqual(ptr.getCellRef().getOwner(), mOwner.getCellRef().getRefId())) mOut.push_back(ptr); From e0c54b3f396d53c13cd83bf3f9806cc4104fa47e Mon Sep 17 00:00:00 2001 From: Allofich Date: Tue, 5 Dec 2017 23:41:08 +0900 Subject: [PATCH 479/505] Stop guards trying to arrest player when calm (Fixes #3863) --- apps/openmw/mwmechanics/actors.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 20955f22a..d685967da 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1009,7 +1009,8 @@ namespace MWMechanics if (player.getClass().getNpcStats(player).isWerewolf()) return; - if (ptr.getClass().isClass(ptr, "Guard") && creatureStats.getAiSequence().getTypeId() != AiPackage::TypeIdPursue && !creatureStats.getAiSequence().isInCombat()) + if (ptr.getClass().isClass(ptr, "Guard") && creatureStats.getAiSequence().getTypeId() != AiPackage::TypeIdPursue && !creatureStats.getAiSequence().isInCombat() + && creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid).getMagnitude() == 0) { const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); static const int cutoff = esmStore.get().find("iCrimeThreshold")->getInt(); From 7e87ce878760022c2c875336b7802aac0b18dc9c Mon Sep 17 00:00:00 2001 From: Allofich Date: Wed, 6 Dec 2017 00:31:48 +0900 Subject: [PATCH 480/505] Prevent combat on/off cycling for calmed actors --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 2b6236ecb..b51b55421 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1653,6 +1653,12 @@ namespace MWMechanics bool MechanicsManager::isAggressive(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) { + // Don't become aggressive if a calm effect is active, since it would cause combat to cycle on/off as + // combat is activated here and then canceled by the calm effect + if ((ptr.getClass().isNpc() && ptr.getClass().getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::CalmHumanoid).getMagnitude() > 0) + || (!ptr.getClass().isNpc() && ptr.getClass().getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::CalmCreature).getMagnitude() > 0)) + return false; + int disposition = 50; if (ptr.getClass().isNpc()) disposition = getDerivedDisposition(ptr, true); From 744859f32715a1244930f049b9d4933e27f2b34f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 7 Dec 2017 22:43:32 +0400 Subject: [PATCH 481/505] Take in account armor condition in the armor rating calculation (bug #4246) --- apps/openmw/mwclass/npc.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index e7085bfbc..134bbf943 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1129,6 +1129,15 @@ namespace MWClass else { ratings[i] = it->getClass().getEffectiveArmorRating(*it, ptr); + + // Take in account armor condition + const bool hasHealth = it->getClass().hasItemHealth(*it); + if (hasHealth) + { + int armorHealth = it->getClass().getItemHealth(*it); + int armorMaxHealth = it->getClass().getItemMaxHealth(*it); + ratings[i] *= (float(armorHealth) / armorMaxHealth); + } } } From 360d786ff2a203c7363675d432697ff42e39374a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 7 Dec 2017 23:48:34 +0100 Subject: [PATCH 482/505] CS: Add rendering prefs and camera FOV --- apps/opencs/model/prefs/state.cpp | 3 +++ apps/opencs/view/prefs/dialogue.cpp | 1 - apps/opencs/view/render/scenewidget.cpp | 6 +++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 1f84c5a87..be6534089 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -192,6 +192,9 @@ void CSMPrefs::State::declare() setRange (0.001, 100.0); declareDouble ("rotate-factor", "Free rotation factor", 0.007).setPrecision(4).setRange(0.0001, 0.1); + declareCategory ("Rendering"); + declareDouble ("camera-fov", "Camera FOV", 90.).setPrecision(5).setRange(10.0, 160.0); + declareCategory ("Tooltips"); declareBool ("scene", "Show Tooltips in 3D scenes", true); declareBool ("scene-hide-basic", "Hide basic 3D scenes tooltips", false); diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp index 960ca74bc..1f5772f18 100644 --- a/apps/opencs/view/prefs/dialogue.cpp +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -84,7 +84,6 @@ CSVPrefs::Dialogue::~Dialogue() void CSVPrefs::Dialogue::closeEvent (QCloseEvent *event) { QMainWindow::closeEvent (event); - CSMPrefs::State::get().save(); } diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 11c7f5926..46bbb29dd 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -66,7 +66,11 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) mView->getCamera()->setGraphicsContext(window); mView->getCamera()->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) ); mView->getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); - mView->getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast(traits->width)/static_cast(traits->height), 1.0f, 10000.0f ); + + mView->getCamera()->setProjectionMatrixAsPerspective( + CSMPrefs::get()["Rendering"]["camera-fov"].toDouble(), + static_cast(traits->width)/static_cast(traits->height), + 1.0f, 10000.0f); SceneUtil::LightManager* lightMgr = new SceneUtil::LightManager; lightMgr->setStartLight(1); From 7d36dd68dcc4e3b245a119a948959b9f91f37752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 7 Dec 2017 23:52:05 +0100 Subject: [PATCH 483/505] CS: Make orbit camera not change roll --- apps/opencs/view/render/cameracontroller.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index 7b802b0ef..cb1278805 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -673,6 +673,7 @@ namespace CSVRender { osg::Vec3d eye, center, up; getCamera()->getViewMatrixAsLookAt(eye, center, up); + up = osg::Vec3(0,0,1); osg::Quat rotation = osg::Quat(value, up); osg::Vec3d oldOffset = eye - mCenter; @@ -685,6 +686,7 @@ namespace CSVRender { osg::Vec3d eye, center, up; getCamera()->getViewMatrixAsLookAt(eye, center, up); + up = osg::Vec3(0,0,1); osg::Vec3d forward = center - eye; osg::Quat rotation = osg::Quat(value, up ^ forward); From cfdc6c788ed33d9a5dc5f3b7c2a2b687769f3f94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 8 Dec 2017 00:05:50 +0100 Subject: [PATCH 484/505] CS: Make camera FOV change dynamically --- apps/opencs/view/render/scenewidget.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 46bbb29dd..7d3ac3f1c 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -374,6 +374,13 @@ void SceneWidget::settingChanged (const CSMPrefs::Setting *setting) { mOrbitCamControl->setOrbitSpeedMultiplier(setting->toDouble()); } + else if (*setting=="Rendering/camera-fov") + { + mView->getCamera()->setProjectionMatrixAsPerspective( + setting->toDouble(), + static_cast(width())/static_cast(height()), + 1.0f, 10000.0f); + } } void SceneWidget::selectNavigationMode (const std::string& mode) From 5e076ee01519cf06f79cc59a717a8acd3298a9d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 8 Dec 2017 00:19:05 +0100 Subject: [PATCH 485/505] CS: Fix camera orbit with arbitrary roll --- apps/opencs/view/render/cameracontroller.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index cb1278805..f0158fe28 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -673,12 +673,13 @@ namespace CSVRender { osg::Vec3d eye, center, up; getCamera()->getViewMatrixAsLookAt(eye, center, up); - up = osg::Vec3(0,0,1); + osg::Vec3 absoluteUp = osg::Vec3(0,0,1); - osg::Quat rotation = osg::Quat(value, up); + osg::Quat rotation = osg::Quat(value, absoluteUp); osg::Vec3d oldOffset = eye - mCenter; osg::Vec3d newOffset = rotation * oldOffset; + up = rotation * up; getCamera()->setViewMatrixAsLookAt(mCenter + newOffset, mCenter, up); } @@ -686,13 +687,14 @@ namespace CSVRender { osg::Vec3d eye, center, up; getCamera()->getViewMatrixAsLookAt(eye, center, up); - up = osg::Vec3(0,0,1); + osg::Vec3 absoluteUp = osg::Vec3(0,0,1); osg::Vec3d forward = center - eye; - osg::Quat rotation = osg::Quat(value, up ^ forward); + osg::Quat rotation = osg::Quat(value, absoluteUp ^ forward); osg::Vec3d oldOffset = eye - mCenter; osg::Vec3d newOffset = rotation * oldOffset; + up = rotation * up; getCamera()->setViewMatrixAsLookAt(mCenter + newOffset, mCenter, up); } From aecf74e7bbeca9dae1d19444535b511f3df7f473 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 8 Dec 2017 07:00:04 -0800 Subject: [PATCH 486/505] Don't throw exceptions from the audio decoder --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 190 ++++++++++++---------- apps/openmw/mwsound/ffmpeg_decoder.hpp | 18 +- apps/openmw/mwsound/movieaudiofactory.cpp | 32 ++-- apps/openmw/mwsound/openal_output.cpp | 14 +- apps/openmw/mwsound/sound_decoder.hpp | 4 +- 5 files changed, 146 insertions(+), 112 deletions(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 1f1834761..12ea84a42 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include @@ -11,11 +11,6 @@ namespace MWSound { -void FFmpeg_Decoder::fail(const std::string &msg) -{ - throw std::runtime_error("FFmpeg exception: "+msg); -} - int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size) { try @@ -33,7 +28,8 @@ int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size) int FFmpeg_Decoder::writePacket(void *, uint8_t *, int) { - throw std::runtime_error("can't write to read-only stream"); + std::cerr<< "can't write to read-only stream" <get(fname); + try + { + mDataStream = mResourceMgr->get(fname); - if((mFormatCtx=avformat_alloc_context()) == NULL) - fail("Failed to allocate context"); + if((mFormatCtx=avformat_alloc_context()) == NULL) + throw std::runtime_error("Failed to allocate context"); - mFormatCtx->pb = avio_alloc_context(NULL, 0, 0, this, readPacket, writePacket, seek); - if(!mFormatCtx->pb || avformat_open_input(&mFormatCtx, fname.c_str(), NULL, NULL) != 0) - { - // "Note that a user-supplied AVFormatContext will be freed on failure". - if (mFormatCtx) + mFormatCtx->pb = avio_alloc_context(NULL, 0, 0, this, readPacket, writePacket, seek); + if(!mFormatCtx->pb || avformat_open_input(&mFormatCtx, fname.c_str(), NULL, NULL) != 0) { - if (mFormatCtx->pb != NULL) + // "Note that a user-supplied AVFormatContext will be freed on failure". + if (mFormatCtx) { - if (mFormatCtx->pb->buffer != NULL) + if (mFormatCtx->pb != NULL) { - av_free(mFormatCtx->pb->buffer); - mFormatCtx->pb->buffer = NULL; + if (mFormatCtx->pb->buffer != NULL) + { + av_free(mFormatCtx->pb->buffer); + mFormatCtx->pb->buffer = NULL; + } + av_free(mFormatCtx->pb); + mFormatCtx->pb = NULL; } - av_free(mFormatCtx->pb); - mFormatCtx->pb = NULL; + avformat_free_context(mFormatCtx); } - avformat_free_context(mFormatCtx); + mFormatCtx = NULL; + throw std::runtime_error("Failed to allocate input stream"); } - mFormatCtx = NULL; - fail("Failed to allocate input stream"); - } - try - { if(avformat_find_stream_info(mFormatCtx, NULL) < 0) - fail("Failed to find stream info in "+fname); + throw std::runtime_error("Failed to find stream info in "+fname); for(size_t j = 0;j < mFormatCtx->nb_streams;j++) { @@ -224,23 +220,45 @@ void FFmpeg_Decoder::open(const std::string &fname) } } if(!mStream) - fail("No audio streams in "+fname); + throw std::runtime_error("No audio streams in "+fname); (*mStream)->codec->request_sample_fmt = (*mStream)->codec->sample_fmt; AVCodec *codec = avcodec_find_decoder((*mStream)->codec->codec_id); if(!codec) { - std::stringstream ss("No codec found for id "); - ss << (*mStream)->codec->codec_id; - fail(ss.str()); + std::string ss = "No codec found for id " + + std::to_string((*mStream)->codec->codec_id); + throw std::runtime_error(ss); } if(avcodec_open2((*mStream)->codec, codec, NULL) < 0) - fail("Failed to open audio codec " + std::string(codec->long_name)); + throw std::runtime_error(std::string("Failed to open audio codec ") + + codec->long_name); mFrame = av_frame_alloc(); + + if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLT || + (*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) + mOutputSampleFormat = AV_SAMPLE_FMT_S16; // FIXME: Check for AL_EXT_FLOAT32 support + else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_U8P) + mOutputSampleFormat = AV_SAMPLE_FMT_U8; + else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16P) + mOutputSampleFormat = AV_SAMPLE_FMT_S16; + else + mOutputSampleFormat = AV_SAMPLE_FMT_S16; + + mOutputChannelLayout = (*mStream)->codec->channel_layout; + if(mOutputChannelLayout == 0) + mOutputChannelLayout = av_get_default_channel_layout((*mStream)->codec->channels); + + return true; } - catch(std::exception&) + catch(std::exception &e) + { + std::cerr<< "Could not open audio file: "<codec); @@ -248,15 +266,15 @@ void FFmpeg_Decoder::open(const std::string &fname) if (mFormatCtx->pb->buffer != NULL) { - av_free(mFormatCtx->pb->buffer); - mFormatCtx->pb->buffer = NULL; + av_free(mFormatCtx->pb->buffer); + mFormatCtx->pb->buffer = NULL; } av_free(mFormatCtx->pb); mFormatCtx->pb = NULL; avformat_close_input(&mFormatCtx); - throw; } + return false; } void FFmpeg_Decoder::close() @@ -274,18 +292,18 @@ void FFmpeg_Decoder::close() { if (mFormatCtx->pb != NULL) { - // mFormatCtx->pb->buffer must be freed by hand, - // if not, valgrind will show memleak, see: - // - // https://trac.ffmpeg.org/ticket/1357 - // - if (mFormatCtx->pb->buffer != NULL) - { - av_free(mFormatCtx->pb->buffer); - mFormatCtx->pb->buffer = NULL; - } - av_free(mFormatCtx->pb); - mFormatCtx->pb = NULL; + // mFormatCtx->pb->buffer must be freed by hand, + // if not, valgrind will show memleak, see: + // + // https://trac.ffmpeg.org/ticket/1357 + // + if (mFormatCtx->pb->buffer != NULL) + { + av_free(mFormatCtx->pb->buffer); + mFormatCtx->pb->buffer = NULL; + } + av_free(mFormatCtx->pb); + mFormatCtx->pb = NULL; } avformat_close_input(&mFormatCtx); } @@ -298,19 +316,13 @@ std::string FFmpeg_Decoder::getName() return mFormatCtx->filename; } -void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) +bool FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) { if(!mStream) - fail("No audio stream info"); - - if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLT || (*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) - mOutputSampleFormat = AV_SAMPLE_FMT_S16; // FIXME: Check for AL_EXT_FLOAT32 support - else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_U8P) - mOutputSampleFormat = AV_SAMPLE_FMT_U8; - else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16P) - mOutputSampleFormat = AV_SAMPLE_FMT_S16; - else - mOutputSampleFormat = AV_SAMPLE_FMT_S16; + { + std::cerr<< "No audio stream info" <codec->channel_layout; - - if(ch_layout == 0) - ch_layout = av_get_default_channel_layout((*mStream)->codec->channels); - - mOutputChannelLayout = ch_layout; - if (ch_layout == AV_CH_LAYOUT_5POINT1 || ch_layout == AV_CH_LAYOUT_7POINT1 - || ch_layout == AV_CH_LAYOUT_QUAD) // FIXME: check for AL_EXT_MCFORMATS support - mOutputChannelLayout = AV_CH_LAYOUT_STEREO; - else if (ch_layout != AV_CH_LAYOUT_MONO - && ch_layout != AV_CH_LAYOUT_STEREO) - mOutputChannelLayout = AV_CH_LAYOUT_STEREO; - if(mOutputChannelLayout == AV_CH_LAYOUT_MONO) *chans = ChannelConfig_Mono; else if(mOutputChannelLayout == AV_CH_LAYOUT_STEREO) @@ -347,13 +346,27 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * char str[1024]; av_get_channel_layout_string(str, sizeof(str), (*mStream)->codec->channels, (*mStream)->codec->channel_layout); - fail(std::string("Unsupported channel layout: ")+str); + std::cerr<< "Unsupported channel layout: "<codec->channels == 1) + { + mOutputChannelLayout = AV_CH_LAYOUT_MONO; + *chans = ChannelConfig_Mono; + } + else + { + mOutputChannelLayout = AV_CH_LAYOUT_STEREO; + *chans = ChannelConfig_Stereo; + } } *samplerate = (*mStream)->codec->sample_rate; + int64_t ch_layout = (*mStream)->codec->channel_layout; + if(ch_layout == 0) + ch_layout = av_get_default_channel_layout((*mStream)->codec->channels); - if(mOutputSampleFormat != (*mStream)->codec->sample_fmt - || mOutputChannelLayout != ch_layout) + if(mOutputSampleFormat != (*mStream)->codec->sample_fmt || + mOutputChannelLayout != ch_layout) { mSwr = swr_alloc_set_opts(mSwr, // SwrContext mOutputChannelLayout, // output ch layout @@ -365,24 +378,37 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * 0, // logging level offset NULL); // log context if(!mSwr) - fail(std::string("Couldn't allocate SwrContext")); + { + std::cerr<< "Couldn't allocate SwrContext" < &output) { if(!mStream) - fail("No audio stream"); + { + std::cerr<< "No audio stream" < &output); - virtual size_t getSampleOffset(); - - void fail(const std::string &msg); + size_t read(char *buffer, size_t bytes) override; + void readAll(std::vector &output) override; + size_t getSampleOffset() override; FFmpeg_Decoder& operator=(const FFmpeg_Decoder &rhs); FFmpeg_Decoder(const FFmpeg_Decoder &rhs); diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index f54ab5c06..188514f85 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -1,5 +1,7 @@ #include "movieaudiofactory.hpp" +#include + #include #include @@ -13,7 +15,7 @@ namespace MWSound { class MovieAudioDecoder; - class MWSoundDecoderBridge : public Sound_Decoder + class MWSoundDecoderBridge final : public Sound_Decoder { public: MWSoundDecoderBridge(MWSound::MovieAudioDecoder* decoder) @@ -25,12 +27,12 @@ namespace MWSound private: MWSound::MovieAudioDecoder* mDecoder; - virtual void open(const std::string &fname); - virtual void close(); - virtual std::string getName(); - virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); - virtual size_t read(char *buffer, size_t bytes); - virtual size_t getSampleOffset(); + bool open(const std::string &fname) override; + void close() override; + std::string getName() override; + bool getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) override; + size_t read(char *buffer, size_t bytes) override; + size_t getSampleOffset() override; }; class MovieAudioDecoder : public Video::MovieAudioDecoder @@ -96,9 +98,9 @@ namespace MWSound }; - void MWSoundDecoderBridge::open(const std::string &fname) + bool MWSoundDecoderBridge::open(const std::string &fname) { - throw std::runtime_error("unimplemented"); + return false; } void MWSoundDecoderBridge::close() {} @@ -107,7 +109,7 @@ namespace MWSound return mDecoder->getStreamName(); } - void MWSoundDecoderBridge::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) + bool MWSoundDecoderBridge::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) { *samplerate = mDecoder->getOutputSampleRate(); @@ -124,9 +126,8 @@ namespace MWSound *chans = ChannelConfig_Quad; else { - std::stringstream error; - error << "Unsupported channel layout: " << outputChannelLayout; - throw std::runtime_error(error.str()); + std::cerr<< "Unsupported channel layout: "<getOutputSampleFormat(); @@ -140,8 +141,11 @@ namespace MWSound { char str[1024]; av_get_sample_fmt_string(str, sizeof(str), outputSampleFormat); - throw std::runtime_error(std::string("Unsupported sample format: ") + str); + std::cerr<< "Unsupported sample format: "<getInfo(&mSampleRate, &chans, &type); + if(!mDecoder->getInfo(&mSampleRate, &chans, &type)) + return false; mFormat = getALFormat(chans, type); if(!mFormat) return false; @@ -948,14 +949,18 @@ std::pair OpenAL_Output::loadSound(const std::string &fname DecoderPtr decoder = mManager.getDecoder(); // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. if(decoder->mResourceMgr->exists(fname)) - decoder->open(fname); + { + if(!decoder->open(fname)) + return std::make_pair(nullptr, 0); + } else { std::string file = fname; std::string::size_type pos = file.rfind('.'); if(pos != std::string::npos) file = file.substr(0, pos)+".mp3"; - decoder->open(file); + if(!decoder->open(file)) + return std::make_pair(nullptr, 0); } std::vector data; @@ -964,7 +969,8 @@ std::pair OpenAL_Output::loadSound(const std::string &fname ALenum format; int srate; - decoder->getInfo(&srate, &chans, &type); + if(!decoder->getInfo(&srate, &chans, &type)) + return std::make_pair(nullptr, 0); format = getALFormat(chans, type); if(!format) return std::make_pair(nullptr, 0); diff --git a/apps/openmw/mwsound/sound_decoder.hpp b/apps/openmw/mwsound/sound_decoder.hpp index 34bae87d7..57edb1393 100644 --- a/apps/openmw/mwsound/sound_decoder.hpp +++ b/apps/openmw/mwsound/sound_decoder.hpp @@ -34,11 +34,11 @@ namespace MWSound { const VFS::Manager* mResourceMgr; - virtual void open(const std::string &fname) = 0; + virtual bool open(const std::string &fname) = 0; virtual void close() = 0; virtual std::string getName() = 0; - virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0; + virtual bool getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0; virtual size_t read(char *buffer, size_t bytes) = 0; virtual void readAll(std::vector &output); From bfad5ebde451bb0cab4bcb137621d3cf61197024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 8 Dec 2017 17:42:20 +0100 Subject: [PATCH 487/505] CS: Fix camera orbit control with keys --- apps/opencs/view/render/cameracontroller.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index f0158fe28..abf68ef93 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -690,7 +690,9 @@ namespace CSVRender osg::Vec3 absoluteUp = osg::Vec3(0,0,1); osg::Vec3d forward = center - eye; - osg::Quat rotation = osg::Quat(value, absoluteUp ^ forward); + + osg::Vec3d axis = absoluteUp ^ forward * (up.z() < 0.0 ? -1.0 : 1.0); + osg::Quat rotation = osg::Quat(value,axis); osg::Vec3d oldOffset = eye - mCenter; osg::Vec3d newOffset = rotation * oldOffset; From 1b77e3ed627afb917d6d4d5ad219dcb6d2587675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 8 Dec 2017 18:18:27 +0100 Subject: [PATCH 488/505] CS: Add ortho camera setting --- apps/opencs/model/prefs/state.cpp | 2 ++ apps/opencs/view/render/scenewidget.cpp | 33 +++++++++++++++++++------ apps/opencs/view/render/scenewidget.hpp | 2 ++ 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index be6534089..f4ba134d0 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -194,6 +194,8 @@ void CSMPrefs::State::declare() declareCategory ("Rendering"); declareDouble ("camera-fov", "Camera FOV", 90.).setPrecision(5).setRange(10.0, 160.0); + declareBool ("camera-ortho", "Orthographic projection for camera", false); + declareDouble ("camera-ortho-size", "Orthographic projection size parameter", 100.0).setPrecision(5).setRange(0.0, 1000.0); declareCategory ("Tooltips"); declareBool ("scene", "Show Tooltips in 3D scenes", true); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 7d3ac3f1c..a151c638e 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -67,10 +67,7 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) mView->getCamera()->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) ); mView->getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); - mView->getCamera()->setProjectionMatrixAsPerspective( - CSMPrefs::get()["Rendering"]["camera-fov"].toDouble(), - static_cast(traits->width)/static_cast(traits->height), - 1.0f, 10000.0f); + updateCameraParameters(); SceneUtil::LightManager* lightMgr = new SceneUtil::LightManager; lightMgr->setStartLight(1); @@ -374,12 +371,34 @@ void SceneWidget::settingChanged (const CSMPrefs::Setting *setting) { mOrbitCamControl->setOrbitSpeedMultiplier(setting->toDouble()); } - else if (*setting=="Rendering/camera-fov") + else if (*setting=="Rendering/camera-fov" || + *setting=="Rendering/camera-ortho" || + *setting=="Rendering/camera-ortho-size") { + updateCameraParameters(); + } +} + +void RenderWidget::updateCameraParameters() +{ + const float near = 1.0; + const float far = 1000.0; + + if (CSMPrefs::get()["Rendering"]["camera-ortho"].isTrue()) + { + const float size = CSMPrefs::get()["Rendering"]["camera-ortho-size"].toDouble(); + const float half_w = size / 100.0 * static_cast(width()); + const float half_h = size / 100.0 * static_cast(height()); + + mView->getCamera()->setProjectionMatrixAsOrtho( + -half_w, half_w, -half_h, half_h, near, far); + } + else + { mView->getCamera()->setProjectionMatrixAsPerspective( - setting->toDouble(), + CSMPrefs::get()["Rendering"]["camera-fov"].toDouble(), static_cast(width())/static_cast(height()), - 1.0f, 10000.0f); + near, far); } } diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index cc3191c81..af7a6f1ec 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -64,6 +64,8 @@ namespace CSVRender osg::ref_ptr mView; osg::ref_ptr mRootNode; + void updateCameraParameters(); + QTimer mTimer; protected slots: From d85f8deaa3b0fd802da2e3713d9d829ab700bd9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 8 Dec 2017 20:51:40 +0100 Subject: [PATCH 489/505] CS: Add fixed roll setting, plus ortho fix --- apps/opencs/model/prefs/state.cpp | 3 ++- apps/opencs/view/render/cameracontroller.cpp | 25 +++++++++++++++----- apps/opencs/view/render/cameracontroller.hpp | 4 ++++ apps/opencs/view/render/scenewidget.cpp | 16 +++++++++---- apps/opencs/view/render/scenewidget.hpp | 2 +- 5 files changed, 37 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index f4ba134d0..9463ae081 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -180,6 +180,7 @@ void CSMPrefs::State::declare() declareDouble ("navi-free-speed-mult", "Free Camera Speed Multiplier (from Modifier)", 8).setRange(0.001, 1000.0); declareDouble ("navi-orbit-rot-speed", "Orbital Camera Rotational Speed", 3.14 / 4).setRange(0.001, 6.28); declareDouble ("navi-orbit-speed-mult", "Orbital Camera Speed Multiplier (from Modifier)", 4).setRange(0.001, 1000.0); + declareBool ("navi-orbit-const-roll", "Keep camera roll constant for orbital camera", true); declareSeparator(); declareBool ("context-select", "Context Sensitive Selection", false); declareDouble ("drag-factor", "Mouse sensitivity during drag operations", 1.0). @@ -191,7 +192,7 @@ void CSMPrefs::State::declare() setTooltip ("Acceleration factor during drag operations while holding down shift"). setRange (0.001, 100.0); declareDouble ("rotate-factor", "Free rotation factor", 0.007).setPrecision(4).setRange(0.0001, 0.1); - + declareCategory ("Rendering"); declareDouble ("camera-fov", "Camera FOV", 90.).setPrecision(5).setRange(10.0, 160.0); declareBool ("camera-ortho", "Orthographic projection for camera", false); diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index abf68ef93..ca80ed34f 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -668,18 +668,25 @@ namespace CSVRender mInitialized = true; } + + void OrbitCameraController::setConstRoll(bool enabled) + { + mConstRoll = enabled; + } void OrbitCameraController::rotateHorizontal(double value) { osg::Vec3d eye, center, up; getCamera()->getViewMatrixAsLookAt(eye, center, up); - osg::Vec3 absoluteUp = osg::Vec3(0,0,1); + osg::Vec3d absoluteUp = osg::Vec3(0,0,1); - osg::Quat rotation = osg::Quat(value, absoluteUp); + osg::Quat rotation = osg::Quat(value, mConstRoll ? absoluteUp : up); osg::Vec3d oldOffset = eye - mCenter; osg::Vec3d newOffset = rotation * oldOffset; - up = rotation * up; + if (mConstRoll) + up = rotation * up; + getCamera()->setViewMatrixAsLookAt(mCenter + newOffset, mCenter, up); } @@ -687,16 +694,22 @@ namespace CSVRender { osg::Vec3d eye, center, up; getCamera()->getViewMatrixAsLookAt(eye, center, up); - osg::Vec3 absoluteUp = osg::Vec3(0,0,1); + osg::Vec3d absoluteUp = osg::Vec3(0,0,1); osg::Vec3d forward = center - eye; - osg::Vec3d axis = absoluteUp ^ forward * (up.z() < 0.0 ? -1.0 : 1.0); + osg::Vec3d axis = absoluteUp ^ forward; + + if (mConstRoll && up.z() < 0.0) + axis *= -1.0; + osg::Quat rotation = osg::Quat(value,axis); osg::Vec3d oldOffset = eye - mCenter; osg::Vec3d newOffset = rotation * oldOffset; + + if (mConstRoll) + up = rotation * up; - up = rotation * up; getCamera()->setViewMatrixAsLookAt(mCenter + newOffset, mCenter, up); } diff --git a/apps/opencs/view/render/cameracontroller.hpp b/apps/opencs/view/render/cameracontroller.hpp index a2ebba51a..658e572c5 100644 --- a/apps/opencs/view/render/cameracontroller.hpp +++ b/apps/opencs/view/render/cameracontroller.hpp @@ -160,6 +160,8 @@ namespace CSVRender /// \brief Flag controller to be re-initialized. void reset(); + void setConstRoll(bool enable); + private: void initialize(); @@ -181,6 +183,8 @@ namespace CSVRender double mOrbitSpeed; double mOrbitSpeedMult; + bool mConstRoll; + private slots: void naviPrimary(bool active); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index a151c638e..a67a38eb3 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -56,6 +56,7 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) traits->vsync = false; mView = new osgViewer::View; + updateCameraParameters( traits->width / static_cast(traits->height) ); osg::ref_ptr window = new osgQt::GraphicsWindowQt(traits.get()); QLayout* layout = new QHBoxLayout(this); @@ -67,8 +68,6 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) mView->getCamera()->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) ); mView->getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); - updateCameraParameters(); - SceneUtil::LightManager* lightMgr = new SceneUtil::LightManager; lightMgr->setStartLight(1); lightMgr->setLightingMask(Mask_Lighting); @@ -189,6 +188,8 @@ SceneWidget::SceneWidget(std::shared_ptr resourceSyste mOrbitCamControl->setPickingMask(Mask_Reference | Mask_Terrain); + mOrbitCamControl->setConstRoll( CSMPrefs::get()["3D Scene Input"]["navi-orbit-const-roll"].isTrue() ); + // we handle lighting manually mView->setLightingMode(osgViewer::View::NO_LIGHT); @@ -371,6 +372,10 @@ void SceneWidget::settingChanged (const CSMPrefs::Setting *setting) { mOrbitCamControl->setOrbitSpeedMultiplier(setting->toDouble()); } + else if (*setting=="3D Scene Input/navi-orbit-const-roll") + { + mOrbitCamControl->setConstRoll(setting->isTrue()); + } else if (*setting=="Rendering/camera-fov" || *setting=="Rendering/camera-ortho" || *setting=="Rendering/camera-ortho-size") @@ -379,7 +384,7 @@ void SceneWidget::settingChanged (const CSMPrefs::Setting *setting) } } -void RenderWidget::updateCameraParameters() +void RenderWidget::updateCameraParameters(double overrideAspect) { const float near = 1.0; const float far = 1000.0; @@ -387,8 +392,9 @@ void RenderWidget::updateCameraParameters() if (CSMPrefs::get()["Rendering"]["camera-ortho"].isTrue()) { const float size = CSMPrefs::get()["Rendering"]["camera-ortho-size"].toDouble(); - const float half_w = size / 100.0 * static_cast(width()); - const float half_h = size / 100.0 * static_cast(height()); + const float aspect = overrideAspect >= 0.0 ? overrideAspect : (width() / static_cast(height())); + const float half_h = size * 10.0; + const float half_w = half_h * aspect; mView->getCamera()->setProjectionMatrixAsOrtho( -half_w, half_w, -half_h, half_h, near, far); diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index af7a6f1ec..13a109a9b 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -64,7 +64,7 @@ namespace CSVRender osg::ref_ptr mView; osg::ref_ptr mRootNode; - void updateCameraParameters(); + void updateCameraParameters(double overrideAspect = -1.0); QTimer mTimer; From e309dfd234526bb4d3dc0ed9df0b18a08ca64a0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 8 Dec 2017 22:06:03 +0100 Subject: [PATCH 490/505] CS: Rename variables (AppVeyor fix) --- apps/opencs/view/render/scenewidget.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index a67a38eb3..ecf27e04d 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -386,25 +386,25 @@ void SceneWidget::settingChanged (const CSMPrefs::Setting *setting) void RenderWidget::updateCameraParameters(double overrideAspect) { - const float near = 1.0; - const float far = 1000.0; + const float nearDist = 1.0; + const float farDist = 1000.0; if (CSMPrefs::get()["Rendering"]["camera-ortho"].isTrue()) { const float size = CSMPrefs::get()["Rendering"]["camera-ortho-size"].toDouble(); const float aspect = overrideAspect >= 0.0 ? overrideAspect : (width() / static_cast(height())); - const float half_h = size * 10.0; - const float half_w = half_h * aspect; + const float halfH = size * 10.0; + const float halfW = halfH * aspect; mView->getCamera()->setProjectionMatrixAsOrtho( - -half_w, half_w, -half_h, half_h, near, far); + -halfW, halfW, -halfH, halfH, nearDist, farDist); } else { mView->getCamera()->setProjectionMatrixAsPerspective( CSMPrefs::get()["Rendering"]["camera-fov"].toDouble(), static_cast(width())/static_cast(height()), - near, far); + nearDist, farDist); } } From 06ae61479a95fbad45ff38c4ef3f62e7988c5cbb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 8 Dec 2017 22:10:09 -0800 Subject: [PATCH 491/505] If a sound effect fails to load, substitute silence. --- apps/openmw/mwsound/openal_output.cpp | 35 ++++++++++++++++----------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 009c019e7..89475ea48 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -948,35 +948,42 @@ std::pair OpenAL_Output::loadSound(const std::string &fname DecoderPtr decoder = mManager.getDecoder(); // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. + bool succeeded; if(decoder->mResourceMgr->exists(fname)) - { - if(!decoder->open(fname)) - return std::make_pair(nullptr, 0); - } + succeeded = decoder->open(fname); else { std::string file = fname; std::string::size_type pos = file.rfind('.'); if(pos != std::string::npos) file = file.substr(0, pos)+".mp3"; - if(!decoder->open(file)) - return std::make_pair(nullptr, 0); + succeeded = decoder->open(file); } std::vector data; - ChannelConfig chans; - SampleType type; ALenum format; int srate; - if(!decoder->getInfo(&srate, &chans, &type)) - return std::make_pair(nullptr, 0); - format = getALFormat(chans, type); - if(!format) return std::make_pair(nullptr, 0); - - decoder->readAll(data); + if(succeeded) + { + ChannelConfig chans; + SampleType type; + if(decoder->getInfo(&srate, &chans, &type)) + { + format = getALFormat(chans, type); + if(format) decoder->readAll(data); + } + } decoder->close(); + if(data.empty()) + { + // If we failed to get any usable audio, substitute with silence. + format = AL_FORMAT_MONO8; + srate = 8000; + data.assign(8000, -128); + } + ALint size; ALuint buf = 0; alGenBuffers(1, &buf); From 08e947319a99021eaa3d16813c97905644a71cbf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 9 Dec 2017 11:00:56 -0800 Subject: [PATCH 492/505] Restore exception throwing to the decoder --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 48 ++++++++------------- apps/openmw/mwsound/ffmpeg_decoder.hpp | 4 +- apps/openmw/mwsound/movieaudiofactory.cpp | 21 ++++----- apps/openmw/mwsound/openal_output.cpp | 52 ++++++++++++----------- apps/openmw/mwsound/sound_decoder.hpp | 4 +- 5 files changed, 56 insertions(+), 73 deletions(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 12ea84a42..e2d54876f 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -176,16 +176,16 @@ size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length) return dec; } -bool FFmpeg_Decoder::open(const std::string &fname) +void FFmpeg_Decoder::open(const std::string &fname) { close(); - try - { - mDataStream = mResourceMgr->get(fname); + mDataStream = mResourceMgr->get(fname); - if((mFormatCtx=avformat_alloc_context()) == NULL) - throw std::runtime_error("Failed to allocate context"); + if((mFormatCtx=avformat_alloc_context()) == NULL) + throw std::runtime_error("Failed to allocate context"); + try + { mFormatCtx->pb = avio_alloc_context(NULL, 0, 0, this, readPacket, writePacket, seek); if(!mFormatCtx->pb || avformat_open_input(&mFormatCtx, fname.c_str(), NULL, NULL) != 0) { @@ -250,16 +250,8 @@ bool FFmpeg_Decoder::open(const std::string &fname) mOutputChannelLayout = (*mStream)->codec->channel_layout; if(mOutputChannelLayout == 0) mOutputChannelLayout = av_get_default_channel_layout((*mStream)->codec->channels); - - return true; - } - catch(std::exception &e) - { - std::cerr<< "Could not open audio file: "<codec); mStream = NULL; @@ -273,8 +265,8 @@ bool FFmpeg_Decoder::open(const std::string &fname) mFormatCtx->pb = NULL; avformat_close_input(&mFormatCtx); + throw; } - return false; } void FFmpeg_Decoder::close() @@ -316,13 +308,10 @@ std::string FFmpeg_Decoder::getName() return mFormatCtx->filename; } -bool FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) +void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) { if(!mStream) - { - std::cerr<< "No audio stream info" < &output) override; diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 188514f85..497562516 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -27,10 +27,10 @@ namespace MWSound private: MWSound::MovieAudioDecoder* mDecoder; - bool open(const std::string &fname) override; + void open(const std::string &fname) override; void close() override; std::string getName() override; - bool getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) override; + void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) override; size_t read(char *buffer, size_t bytes) override; size_t getSampleOffset() override; }; @@ -98,9 +98,9 @@ namespace MWSound }; - bool MWSoundDecoderBridge::open(const std::string &fname) + void MWSoundDecoderBridge::open(const std::string &fname) { - return false; + throw std::runtime_error("Method not implemented"); } void MWSoundDecoderBridge::close() {} @@ -109,7 +109,7 @@ namespace MWSound return mDecoder->getStreamName(); } - bool MWSoundDecoderBridge::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) + void MWSoundDecoderBridge::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) { *samplerate = mDecoder->getOutputSampleRate(); @@ -125,10 +125,8 @@ namespace MWSound else if (outputChannelLayout == AV_CH_LAYOUT_QUAD) *chans = ChannelConfig_Quad; else - { - std::cerr<< "Unsupported channel layout: "<getOutputSampleFormat(); if (outputSampleFormat == AV_SAMPLE_FMT_U8) @@ -141,11 +139,8 @@ namespace MWSound { char str[1024]; av_get_sample_fmt_string(str, sizeof(str), outputSampleFormat); - std::cerr<< "Unsupported sample format: "<getInfo(&mSampleRate, &chans, &type)) + try { + mDecoder->getInfo(&mSampleRate, &chans, &type); + mFormat = getALFormat(chans, type); + } + catch(std::exception &e) { + std::cerr<< "Failed to get stream info: "< OpenAL_Output::loadSound(const std::string &fname { getALError(); - DecoderPtr decoder = mManager.getDecoder(); - // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. - bool succeeded; - if(decoder->mResourceMgr->exists(fname)) - succeeded = decoder->open(fname); - else - { - std::string file = fname; - std::string::size_type pos = file.rfind('.'); - if(pos != std::string::npos) - file = file.substr(0, pos)+".mp3"; - succeeded = decoder->open(file); - } - std::vector data; ALenum format; int srate; - if(succeeded) - { - ChannelConfig chans; - SampleType type; - if(decoder->getInfo(&srate, &chans, &type)) + try { + DecoderPtr decoder = mManager.getDecoder(); + // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. + if(decoder->mResourceMgr->exists(fname)) + decoder->open(fname); + else { - format = getALFormat(chans, type); - if(format) decoder->readAll(data); + std::string file = fname; + std::string::size_type pos = file.rfind('.'); + if(pos != std::string::npos) + file = file.substr(0, pos)+".mp3"; + decoder->open(file); } + + ChannelConfig chans; + SampleType type; + decoder->getInfo(&srate, &chans, &type); + format = getALFormat(chans, type); + if(format) decoder->readAll(data); + } + catch(std::exception &e) { + std::cerr<< "Failed to load audio from "<close(); if(data.empty()) { diff --git a/apps/openmw/mwsound/sound_decoder.hpp b/apps/openmw/mwsound/sound_decoder.hpp index 57edb1393..34bae87d7 100644 --- a/apps/openmw/mwsound/sound_decoder.hpp +++ b/apps/openmw/mwsound/sound_decoder.hpp @@ -34,11 +34,11 @@ namespace MWSound { const VFS::Manager* mResourceMgr; - virtual bool open(const std::string &fname) = 0; + virtual void open(const std::string &fname) = 0; virtual void close() = 0; virtual std::string getName() = 0; - virtual bool getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0; + virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0; virtual size_t read(char *buffer, size_t bytes) = 0; virtual void readAll(std::vector &output); From c908ad2fba38a7260f41d480ad26343622f13ae1 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 10 Dec 2017 14:38:02 +0400 Subject: [PATCH 493/505] Do not allow to place actors underground via SetPos (bug #3783) --- apps/openmw/mwscript/transformationextensions.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index c876d4cf7..208a1f46f 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -227,6 +227,17 @@ namespace MWScript } else if(axis == "z") { + // We should not place actors under ground + if (ptr.getClass().isActor()) + { + float terrainHeight = -std::numeric_limits::max(); + if (ptr.getCell()->isExterior()) + terrainHeight = MWBase::Environment::get().getWorld()->getTerrainHeightAt(osg::Vec3f(ax, ay, az)); + + if (pos < terrainHeight) + pos = terrainHeight; + } + updated = MWBase::Environment::get().getWorld()->moveObject(ptr,ax,ay,pos); } else From 0e04a26ef6d3a5453f69073d9f3351a0cd2b5c34 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 10 Dec 2017 16:10:44 +0400 Subject: [PATCH 494/505] Set duration of magic effects from ingredients (bug #4261) --- apps/openmw/mwmechanics/spellcasting.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 8fbf67535..d864dc619 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -968,9 +968,9 @@ namespace MWMechanics float y = roll / std::min(x, 100.f); y *= 0.25f * x; if (magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) - effect.mDuration = static_cast(y); - else effect.mDuration = 1; + else + effect.mDuration = static_cast(y); if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) { if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) From ba46473038f68e6e0c1a0235b518e293668d9bfa Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 13 Dec 2017 10:53:23 +0400 Subject: [PATCH 495/505] Do not skip weather transitions from SetPos script command (bug #3603) --- apps/openmw/mwscript/transformationextensions.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 208a1f46f..68b1063e4 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -202,11 +202,6 @@ namespace MWScript if (!ptr.isInCell()) return; - if (ptr == MWMechanics::getPlayer()) - { - MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); - } - std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); Interpreter::Type_Float pos = runtime[0].mFloat; @@ -216,6 +211,8 @@ namespace MWScript float ay = ptr.getRefData().getPosition().pos[1]; float az = ptr.getRefData().getPosition().pos[2]; + // Note: SetPos does not skip weather transitions in vanilla engine, so we do not call setTeleported(true) here. + MWWorld::Ptr updated = ptr; if(axis == "x") { From 269c3227eaca6cf4a2a647e3f3f281950b09d853 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 13 Dec 2017 10:44:06 +0000 Subject: [PATCH 496/505] Make sure we have cmake for the before_install step --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d173ef6f2..02cc7cf20 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,7 +24,7 @@ addons: - llvm-toolchain-precise-3.6 packages: [ # Dev - clang-3.6, libunshield-dev, libtinyxml-dev, + cmake, clang-3.6, libunshield-dev, libtinyxml-dev, # Tests libgtest-dev, google-mock, # Boost From b246580c6389bfe2786804ff454884b3e426e929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Wed, 13 Dec 2017 20:08:38 +0100 Subject: [PATCH 497/505] Fix orbit camera axis --- apps/opencs/view/render/cameracontroller.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index ca80ed34f..57032f5ad 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -697,11 +697,7 @@ namespace CSVRender osg::Vec3d absoluteUp = osg::Vec3(0,0,1); osg::Vec3d forward = center - eye; - - osg::Vec3d axis = absoluteUp ^ forward; - - if (mConstRoll && up.z() < 0.0) - axis *= -1.0; + osg::Vec3d axis = up ^ forward; osg::Quat rotation = osg::Quat(value,axis); osg::Vec3d oldOffset = eye - mCenter; From 79527b746a9e80fb59e73e3507fa69aad9e5b6af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 14 Dec 2017 17:29:24 +0100 Subject: [PATCH 498/505] Remove unused variable --- apps/opencs/view/render/cameracontroller.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index 57032f5ad..37f439fd3 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -694,7 +694,6 @@ namespace CSVRender { osg::Vec3d eye, center, up; getCamera()->getViewMatrixAsLookAt(eye, center, up); - osg::Vec3d absoluteUp = osg::Vec3(0,0,1); osg::Vec3d forward = center - eye; osg::Vec3d axis = up ^ forward; From f2777f72424bdd2318f88f0ef184635d629fb23d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 15 Dec 2017 14:36:12 +0100 Subject: [PATCH 499/505] CS: Mover object-marker-alpha under Rendering --- apps/opencs/model/prefs/state.cpp | 2 +- apps/opencs/view/render/object.cpp | 2 +- apps/opencs/view/render/worldspacewidget.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 509d977c4..311615aec 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -192,12 +192,12 @@ void CSMPrefs::State::declare() setTooltip ("Acceleration factor during drag operations while holding down shift"). setRange (0.001, 100.0); declareDouble ("rotate-factor", "Free rotation factor", 0.007).setPrecision(4).setRange(0.0001, 0.1); - declareDouble ("object-marker-alpha", "Object Marker Transparency", 0.5).setPrecision(2).setRange(0,1); declareCategory ("Rendering"); declareDouble ("camera-fov", "Camera FOV", 90.).setPrecision(5).setRange(10.0, 160.0); declareBool ("camera-ortho", "Orthographic projection for camera", false); declareDouble ("camera-ortho-size", "Orthographic projection size parameter", 100.0).setPrecision(5).setRange(0.0, 1000.0); + declareDouble ("object-marker-alpha", "Object Marker Transparency", 0.5).setPrecision(2).setRange(0,1); declareCategory ("Tooltips"); declareBool ("scene", "Show Tooltips in 3D scenes", true); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index df7283b1a..dae6467c5 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -471,7 +471,7 @@ void CSVRender::Object::setSelected(bool selected) else mRootNode->addChild(mBaseNode); - mMarkerTransparency = CSMPrefs::get()["3D Scene Input"]["object-marker-alpha"].toDouble(); + mMarkerTransparency = CSMPrefs::get()["Rendering"]["object-marker-alpha"].toDouble(); updateMarker(); } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index a80a61a79..af53c86f0 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -131,7 +131,7 @@ void CSVRender::WorldspaceWidget::settingChanged (const CSMPrefs::Setting *setti mDragWheelFactor = setting->toDouble(); else if (*setting=="3D Scene Input/drag-shift-factor") mDragShiftFactor = setting->toDouble(); - else if (*setting=="3D Scene Input/object-marker-alpha" && !mInConstructor) + else if (*setting=="Rendering/object-marker-alpha" && !mInConstructor) { float alpha = setting->toDouble(); // getSelection is virtual, thus this can not be called from the constructor From 1f5feeddb98e4f1c280bc306f839b539afdb925a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 15 Dec 2017 14:46:23 +0100 Subject: [PATCH 500/505] CS: Change camera parameter types to int --- apps/opencs/model/prefs/state.cpp | 4 ++-- apps/opencs/view/render/scenewidget.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 311615aec..7dfd3543b 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -194,9 +194,9 @@ void CSMPrefs::State::declare() declareDouble ("rotate-factor", "Free rotation factor", 0.007).setPrecision(4).setRange(0.0001, 0.1); declareCategory ("Rendering"); - declareDouble ("camera-fov", "Camera FOV", 90.).setPrecision(5).setRange(10.0, 160.0); + declareInt ("camera-fov", "Camera FOV", 90).setRange(10, 170); declareBool ("camera-ortho", "Orthographic projection for camera", false); - declareDouble ("camera-ortho-size", "Orthographic projection size parameter", 100.0).setPrecision(5).setRange(0.0, 1000.0); + declareInt ("camera-ortho-size", "Orthographic projection size parameter", 100).setRange(10, 10000); declareDouble ("object-marker-alpha", "Object Marker Transparency", 0.5).setPrecision(2).setRange(0,1); declareCategory ("Tooltips"); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index ecf27e04d..f24a9de50 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -391,7 +391,7 @@ void RenderWidget::updateCameraParameters(double overrideAspect) if (CSMPrefs::get()["Rendering"]["camera-ortho"].isTrue()) { - const float size = CSMPrefs::get()["Rendering"]["camera-ortho-size"].toDouble(); + const float size = CSMPrefs::get()["Rendering"]["camera-ortho-size"].toInt(); const float aspect = overrideAspect >= 0.0 ? overrideAspect : (width() / static_cast(height())); const float halfH = size * 10.0; const float halfW = halfH * aspect; @@ -402,7 +402,7 @@ void RenderWidget::updateCameraParameters(double overrideAspect) else { mView->getCamera()->setProjectionMatrixAsPerspective( - CSMPrefs::get()["Rendering"]["camera-fov"].toDouble(), + CSMPrefs::get()["Rendering"]["camera-fov"].toInt(), static_cast(width())/static_cast(height()), nearDist, farDist); } From 13dc1bd41e03c48555624e2f525a98ae56bdda66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 15 Dec 2017 14:56:03 +0100 Subject: [PATCH 501/505] CS: Add tooltip to camera-ortho-size preference --- apps/opencs/model/prefs/state.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 7dfd3543b..34519dcab 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -196,7 +196,9 @@ void CSMPrefs::State::declare() declareCategory ("Rendering"); declareInt ("camera-fov", "Camera FOV", 90).setRange(10, 170); declareBool ("camera-ortho", "Orthographic projection for camera", false); - declareInt ("camera-ortho-size", "Orthographic projection size parameter", 100).setRange(10, 10000); + declareInt ("camera-ortho-size", "Orthographic projection size parameter", 100). + setTooltip("Size of the orthographic frustum, greater value will allow the camera to see more of the world."). + setRange(10, 10000); declareDouble ("object-marker-alpha", "Object Marker Transparency", 0.5).setPrecision(2).setRange(0,1); declareCategory ("Tooltips"); From 01f9d90315877930d6ec16a936a07bd122d8feed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 15 Dec 2017 17:22:32 +0100 Subject: [PATCH 502/505] CS: Reorder 3D input menu --- apps/opencs/model/prefs/state.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 34519dcab..8a9dad7f3 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -169,19 +169,25 @@ void CSMPrefs::State::declare() "list go to the first/last item"); declareCategory ("3D Scene Input"); + + declareDouble ("navi-wheel-factor", "Camera Zoom Sensitivity", 8).setRange(-100.0, 100.0); + declareDouble ("s-navi-sensitivity", "Secondary Camera Movement Sensitivity", 50.0).setRange(-1000.0, 1000.0); + declareSeparator(); + declareDouble ("p-navi-free-sensitivity", "Free Camera Sensitivity", 1/650.).setPrecision(5).setRange(0.0, 1.0); declareBool ("p-navi-free-invert", "Invert Free Camera Mouse Input", false); - declareDouble ("p-navi-orbit-sensitivity", "Orbit Camera Sensitivity", 1/650.).setPrecision(5).setRange(0.0, 1.0); - declareBool ("p-navi-orbit-invert", "Invert Orbit Camera Mouse Input", false); - declareDouble ("s-navi-sensitivity", "Secondary Camera Movement Sensitivity", 50.0).setRange(-1000.0, 1000.0); - declareDouble ("navi-wheel-factor", "Camera Zoom Sensitivity", 8).setRange(-100.0, 100.0); declareDouble ("navi-free-lin-speed", "Free Camera Linear Speed", 1000.0).setRange(1.0, 10000.0); - declareDouble ("navi-free-rot-speed", "Free Camera Rotational Speed", 3.14 / 2).setRange(0.001, 6.28); + declareDouble ("navi-free-rot-speed", "Free Camera Rotational Speed", 3.14 / 2).setRange(0.001, 6.28); declareDouble ("navi-free-speed-mult", "Free Camera Speed Multiplier (from Modifier)", 8).setRange(0.001, 1000.0); + declareSeparator(); + + declareDouble ("p-navi-orbit-sensitivity", "Orbit Camera Sensitivity", 1/650.).setPrecision(5).setRange(0.0, 1.0); + declareBool ("p-navi-orbit-invert", "Invert Orbit Camera Mouse Input", false); declareDouble ("navi-orbit-rot-speed", "Orbital Camera Rotational Speed", 3.14 / 4).setRange(0.001, 6.28); declareDouble ("navi-orbit-speed-mult", "Orbital Camera Speed Multiplier (from Modifier)", 4).setRange(0.001, 1000.0); declareBool ("navi-orbit-const-roll", "Keep camera roll constant for orbital camera", true); declareSeparator(); + declareBool ("context-select", "Context Sensitive Selection", false); declareDouble ("drag-factor", "Mouse sensitivity during drag operations", 1.0). setRange (0.001, 100.0); From e4a1b6b5b891d3f98a7ebbadc332638d8795499e Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Sat, 16 Dec 2017 14:36:27 -0600 Subject: [PATCH 503/505] Explicitly setting CMAKE_CXX_STANDARD to C++11 --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1593dda2b..1fc9f5016 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -338,6 +338,7 @@ if (NOT WIN32 AND NOT APPLE) endif() # CXX Compiler settings +set(CMAKE_CXX_STANDARD 11) if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wundef -Wno-unused-parameter -std=c++11 -pedantic -Wno-long-long") add_definitions( -DBOOST_NO_CXX11_SCOPED_ENUMS=ON ) From 1a58171e86b90d1498808facfc955d35288730eb Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Dec 2017 18:09:25 +0400 Subject: [PATCH 504/505] Do not allow to sell items from containers with zero capacity (bug #4268) --- apps/openmw/mwworld/worldimp.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2d38f1518..340876759 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2446,9 +2446,8 @@ namespace MWWorld if (ptr.getRefData().isDeleted()) return true; - // we should not sell ingrediends from owned organic containers - MWWorld::LiveCellRef* ref = ptr.get(); - if (ref && (ref->mBase->mFlags & ESM::Container::Organic)) + // vanilla Morrowind does not allow to sell items from containers with zero capacity + if (ptr.getClass().getCapacity(ptr) <= 0.f) return true; if (Misc::StringUtils::ciEqual(ptr.getCellRef().getOwner(), mOwner.getCellRef().getRefId())) From b8c25e6bff7ae42c24073523473c0f7f47034a70 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 21 Dec 2017 14:49:09 +0000 Subject: [PATCH 505/505] Use the correct priority of animation sources in getStartTime (Fixes #4263) --- apps/openmw/mwrender/animation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a1aa24871..16ce9b436 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -625,7 +625,7 @@ namespace MWRender float Animation::getStartTime(const std::string &groupname) const { - for(AnimSourceList::const_iterator iter(mAnimSources.begin()); iter != mAnimSources.end(); ++iter) + for(AnimSourceList::const_reverse_iterator iter(mAnimSources.rbegin()); iter != mAnimSources.rend(); ++iter) { const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys(); @@ -638,7 +638,7 @@ namespace MWRender float Animation::getTextKeyTime(const std::string &textKey) const { - for(AnimSourceList::const_iterator iter(mAnimSources.begin()); iter != mAnimSources.end(); ++iter) + for(AnimSourceList::const_reverse_iterator iter(mAnimSources.rbegin()); iter != mAnimSources.rend(); ++iter) { const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys();